feat(cli): add file sharing CLI using Transfer.coffee

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.
This commit is contained in:
Kumi 2024-10-20 21:13:01 +02:00
commit d176a8f89b
Signed by: kumi
GPG key ID: ECBCC9082395383F
4 changed files with 1465 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules

111
cli.mjs Executable file
View file

@ -0,0 +1,111 @@
#!/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);

21
package.json Normal file
View file

@ -0,0 +1,21 @@
{
"name": "transfer-coffee-cli",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"type": "module",
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"dependencies": {
"axios": "^1.7.7",
"bip39": "^3.1.0",
"commander": "^12.1.0",
"dotenv": "^16.4.5",
"webtorrent": "^2.5.1"
}
}

1332
yarn.lock Normal file

File diff suppressed because it is too large Load diff