diff --git a/package.json b/package.json new file mode 100644 index 0000000..44df250 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "@lumeweb/peer-discovery-source-bittorrent", + "version": "0.1.0", + "devDependencies": { + "@types/b4a": "^1.6.0", + "@types/node": "^18.11.17", + "prettier": "^2.8.1", + "typescript": "^4.9.4" + }, + "dependencies": { + "@lumeweb/peer-discovery": "https://git.lumeweb.com/LumeWeb/peer-discovery.git", + "b4a": "^1.6.1", + "bittorrent-dht": "^11.0.1", + "bittorrent-dht-sodium": "^1.2.0", + "sha.js": "^2.4.11" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f337e18 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,45 @@ +import DHT from "bittorrent-dht"; +import { Peer, PeerDiscovery } from "@lumeweb/peer-discovery"; +import eddsa from "bittorrent-dht-sodium"; +import sha from "sha.js"; +import * as Buffer from "buffer"; +import b4a from "b4a"; + +export default class BitTorrentSource { + private _discovery: PeerDiscovery; + private _dht: DHT; + private _readyResolve: Function; + private _ready: Promise = new Promise((resolve) => { + this._readyResolve = resolve; + }); + + constructor(discovery: PeerDiscovery, bootstrap?: string[]) { + this._discovery = discovery; + this._dht = new DHT({ bootstrap, verify: eddsa.verify }); + this._dht.on("ready", this._readyResolve); + } + + public async discover(pubkey: Buffer): Promise { + await this._ready; + + const hash = sha("sha1").update(pubkey).digest(); + + return new Promise((resolve, reject) => { + this._dht.get(hash, function (err, res) { + if (err) { + console.log(err); + reject(false); + return; + } + + const json = JSON.parse(b4a.from(res.v).toString()); + + resolve({ host: json?.host, port: json?.port }); + }); + }); + } + + public register(name: string): boolean { + return this._discovery.registerSource(name, this.discover.bind(this)); + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8d1c301 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "esnext", + "sourceMap": true, + "esModuleInterop": true, + "outDir": "dist", + "declaration": true + }, + "include": ["src"], + "exclude": [ + "node_modules" + ] +}