holesail-share
Version:
A P2P based node package to share files on the Holepunch protocol
293 lines (260 loc) • 8.12 kB
JavaScript
#!/usr/bin/env node
const DHT = require('holesail-server') //require module to start server on local port
const goodbye = require('graceful-goodbye')
const HyperDHT = require('hyperdht')
const argv = require('minimist')(process.argv.slice(2)) //required to parse cli arguments
const {
createHash
} = require('crypto'); //for connectors
//setting up the command hierarchy
if (argv.help) {
const help = require('./includes/help.js');
help.printHelp(help.helpMessage);
process.exit(-1)
}
const localServer = new DHT();
if (argv.live) {
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const PORT =parseInt(argv.live, 10) || 3341;
// Array to store uploaded files
let uploadedFiles = [];
// Set up multer storage
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
// Serve index.html
app.get('/', (req, res) => {
res.send(`
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Holesail File Sharing</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f8f9fa;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
max-width: 600px;
padding: 40px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
h1, h2 {
margin-top: 0;
color: #007bff;
text-align: center;
}
input[type="file"] {
display: block;
margin: 20px auto;
padding: 10px;
width: calc(100% - 20px);
border: 2px dashed #007bff;
border-radius: 8px;
background-color: #f8f9fa;
color: #007bff;
font-size: 16px;
cursor: pointer;
transition: border-color 0.3s ease-in-out;
}
input[type="file"]:hover {
border-color: #0056b3;
}
button {
display: block;
margin: 0 auto;
padding: 10px 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s ease-in-out;
}
button:hover {
background-color: #0056b3;
}
ul {
list-style-type: none;
padding: 0;
margin-top: 20px;
}
li {
margin-bottom: 10px;
padding: 10px;
background-color: #f0f0f0;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease-in-out;
}
li:hover {
transform: translateY(-2px);
}
a {
color: #007bff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>File Sharing App</h1>
<input type="file" id="fileInput" />
<button onclick="handleUpload()">Upload</button>
<hr>
<h2>Shared Files</h2>
<ul id="fileList"></ul>
</div>
<script>
// Function to handle file upload
function handleUpload() {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (!file) {
alert('Please select a file.');
return;
}
const formData = new FormData();
formData.append('file', file);
fetch('/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
const fileName = data.fileName;
const downloadLink = document.createElement('a');
downloadLink.href = 'data:application/octet-stream;base64,' + data.fileData;
downloadLink.setAttribute('download', fileName);
downloadLink.textContent = fileName;
const listItem = document.createElement('li');
listItem.appendChild(downloadLink);
document.getElementById('fileList').appendChild(listItem);
})
.catch(error => {
console.error('Error:', error);
});
}
// Function to display previously uploaded files
function displayFiles(files) {
const fileList = document.getElementById('fileList');
fileList.innerHTML = '';
files.forEach(file => {
const downloadLink = document.createElement('a');
downloadLink.href = 'data:application/octet-stream;base64,' + file.fileData;
downloadLink.setAttribute('download', file.fileName);
downloadLink.textContent = file.fileName;
const listItem = document.createElement('li');
listItem.appendChild(downloadLink);
fileList.appendChild(listItem);
});
}
// Fetch previously uploaded files on page load
fetch('/files')
.then(response => response.json())
.then(data => {
displayFiles(data);
})
.catch(error => {
console.error('Error:', error);
});
</script>
</body>
</html>
`);
});
// Handle file upload
app.post('/upload', upload.single('file'), (req, res) => {
if (!req.file) {
return res.status(400).send('No file uploaded.');
}
const fileData = req.file.buffer.toString('base64');
const fileName = req.file.originalname;
uploadedFiles.push({ fileName, fileData });
res.send({ fileName, fileData });
});
// Serve uploaded files
app.get('/files', (req, res) => {
res.json(uploadedFiles);
});
// Start the server
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
// --host
if (argv.host) {
host = argv.host
} else {
host = '127.0.0.1'
}
//to preserve seed
if (argv.connector) {
if (argv.connector.length === 64) {
connector = argv.connector
} else {
connector = createHash('sha256').update(argv.connector.toString()).digest('hex');
}
} else {
connector = null
}
localServer.serve({port:PORT, host:host}, () => {
console.log(`Server started, Now listening on ${host}:` + `${PORT}`);
console.log(`Your connector is: ${argv.connector}`);
console.log('Server public key:', localServer.getPublicKey());
}, connector);
} else if (argv.connect) {
//give priority to connector instead of connection seed
if (argv.connector) {
if (argv.connector.length === 64) {
connector = argv.connector
} else {
connector = createHash('sha256').update(argv.connector.toString()).digest('hex');
const seed = Buffer.from(connector, 'hex');
//the keypair here is not a reference to the function above
connector = HyperDHT.keyPair(seed).publicKey.toString('hex');
}
} else {
connector = argv.connect
}
if (!PORT) {
port = 8989
} else {
port = PORT
}
//--host
if (argv.host) {
host = argv.host
} else {
host = '127.0.0.1'
}
const holesailClient = require('holesail-client')
const pubClient = new holesailClient(connector)
pubClient.connect({port:port, host:host}, () => {
console.log(`Client setup, access on ${host}:${port}`);
console.log(`Your connector is: ${argv.connector}`);
console.log('Connected to public key:', connector);
}
)
} else {
console.log(helpMessage);
process.exit(-1)
}
goodbye(async () => {
await localServer.destroy()
})