Kumi
d176a8f89b
Introduced a command-line interface that allows users to upload and download files using WebTorrent. Files can be shared using a generated mnemonic phrase for easy retrieval. The CLI supports one-time uploads and continuous seeding options. Added configuration files to manage dependencies and environmental variables, including `.gitignore` for ignoring the `node_modules`. This feature enables a decentralized file sharing mechanism and leverages mnemonic phrases for simpler sharing.
111 lines
3.2 KiB
JavaScript
Executable file
111 lines
3.2 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
import { Command } from 'commander';
|
|
import WebTorrent from 'webtorrent';
|
|
import bip39 from 'bip39';
|
|
import dotenv from 'dotenv';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
|
|
dotenv.config();
|
|
|
|
const app = new Command();
|
|
const client = new WebTorrent();
|
|
const trackerUrl = process.env.TRACKER_URL || "wss://tracker.transfer.coffee";
|
|
|
|
// Upload file and generate mnemonic
|
|
app
|
|
.command('upload <filePath>')
|
|
.description('Upload a file and get a mnemonic to share')
|
|
.option('-o, --one-time', 'Exit once the file has been downloaded once')
|
|
.action((filePath, options) => {
|
|
if (!fs.existsSync(filePath)) {
|
|
console.error('File does not exist.');
|
|
process.exit(1);
|
|
}
|
|
const opts = {
|
|
announce: [trackerUrl],
|
|
};
|
|
|
|
console.log(`Connecting to tracker: ${trackerUrl}`);
|
|
|
|
client.seed(filePath, opts, (torrent) => {
|
|
console.log(`File is seeding. InfoHash: ${torrent.infoHash}`);
|
|
try {
|
|
const mnemonic = bip39.entropyToMnemonic(torrent.infoHash);
|
|
console.log(`Mnemonic for sharing: ${mnemonic}`);
|
|
|
|
if (options.oneTime) {
|
|
torrent.on('upload', () => {
|
|
const completedPeer = torrent.wires.some(wire => wire.uploaded === torrent.length);
|
|
if (completedPeer) {
|
|
console.log('A peer has completed the download. Exiting...');
|
|
process.exit(0);
|
|
}
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(`Error generating mnemonic: ${error.message}`);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Download file using mnemonic
|
|
app
|
|
.command('download [words...]')
|
|
.description('Download a file using a mnemonic')
|
|
.option('-s, --seed', 'Continue seeding after download is complete')
|
|
.action((words, options) => {
|
|
try {
|
|
const mnemonic = words.join(' ');
|
|
if (!bip39.validateMnemonic(mnemonic)) {
|
|
throw new Error('Invalid mnemonic');
|
|
}
|
|
const infoHash = bip39.mnemonicToEntropy(mnemonic);
|
|
|
|
console.log(`Connecting to tracker: ${trackerUrl}`);
|
|
console.log('Searching for seeds...');
|
|
|
|
const opts = {
|
|
announce: [trackerUrl],
|
|
};
|
|
|
|
client.add(infoHash, opts, (torrent) => {
|
|
const file = torrent.files[0];
|
|
const output = path.join(process.cwd(), file.name);
|
|
const stream = fs.createWriteStream(output);
|
|
|
|
console.log(`Downloading file: ${file.name}`);
|
|
console.log('Size:', file.length, 'bytes');
|
|
console.log('');
|
|
|
|
file.createReadStream().pipe(stream);
|
|
stream.on('finish', () => {
|
|
console.log("\nDownload complete:", output);
|
|
if (!options.seed) {
|
|
process.exit(0);
|
|
} else {
|
|
console.log('Continuing to seed...');
|
|
}
|
|
});
|
|
|
|
torrent.on('download', () => {
|
|
const progress = (torrent.downloaded / torrent.length * 100).toFixed(2);
|
|
process.stdout.write(`\rProgress: ${progress}%`);
|
|
});
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error(`Error downloading file: ${error.message}`);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
|
|
app
|
|
.command('help')
|
|
.description('Display help information')
|
|
.action(() => {
|
|
app.help();
|
|
});
|
|
|
|
app.parse(process.argv);
|