当前位置: 首页 > news >正文

【p2p、分布式,区块链笔记 Torrent】: WebTorrent GitTorrent bittorrent-dht

bittorrent-dht模块

  • BitTorrent DHT 通过 DHT 网络广播值,允许其他用户通过 DHT 来发现和获取这些数据。

1. 导入依赖

var DHT = require('bittorrent-dht')

2. 创建实例

var dht = new DHT({bootstrap: config.dht.bootstrap
})
dht.listen(config.dht.listen)
  • new DHT({...}):创建一个新的 DHT 实例,bootstrap 参数用于指定引导节点的地址,允许客户端加入 DHT 网络。

  • dht.listen(...):在指定的端口上开始监听来自其他 DHT 节点的请求。

  • 处理 DHT 准备就绪事件

dht.on('ready', function () {// 处理
})
  • 示例代码
var DHT = require("bittorrent-dht");
var dht = new DHT();var dht = new DHT();
var value = new Buffer(200).fill("abc");dht.on("ready", function () {dht.put({ v: value }, function (errors, hash) {console.error("errors=", errors);console.log("hash=", hash);});
});setTimeout(function () {var arr = dht.toArray(); // 获取DHT节点数组console.log("DHT节点数组:", arr); // 打印数组到控制台dht.destroy();
}, 100000);
  • 输出:
➜  workspace git:(master) ✗ node index.js
(node:17667) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
errors= [Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '95.72.172.196:6881'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '5.49.12.204:40333'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '95.29.240.208:6881'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '109.175.109.86:8893'},Error: 202 Server Errorat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '146.19.24.245:23544'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '81.101.23.157:56418'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '159.146.86.15:42164'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '195.8.44.196:20515'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '5.79.173.86:26358'},Error: 202 Server Errorat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '13.58.27.33:6881'},Error: 202 Server Errorat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '18.223.137.220:6881'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '103.15.254.90:18384'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '189.147.128.165:6898'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '49.187.241.178:6881'},Error: 203 missing 'token' keyat DHT._onResponseOrError (/project/workspace/node_modules/bittorrent-dht/client.js:1077:11)at DHT._onData (/project/workspace/node_modules/bittorrent-dht/client.js:1037:10)at Socket.emit (node:events:518:28)at UDP.onMessage [as onmessage] (node:dgram:942:8) {address: '195.211.192.65:43468'},Error: query timed outat Timeout.onTimeout [as _onTimeout] (/project/workspace/node_modules/bittorrent-dht/client.js:1445:8)at listOnTimeout (node:internal/timers:573:17)at process.processTimers (node:internal/timers:514:7) {address: '146.59.3.81:10240'},Error: query timed outat Timeout.onTimeout [as _onTimeout] (/project/workspace/node_modules/bittorrent-dht/client.js:1445:8)at listOnTimeout (node:internal/timers:573:17)at process.processTimers (node:internal/timers:514:7) {address: '195.8.44.196:41850'},Error: query timed outat Timeout.onTimeout [as _onTimeout] (/project/workspace/node_modules/bittorrent-dht/client.js:1445:8)at listOnTimeout (node:internal/timers:573:17)at process.processTimers (node:internal/timers:514:7) {address: '90.154.72.124:16183'},Error: query timed outat Timeout.onTimeout [as _onTimeout] (/project/workspace/node_modules/bittorrent-dht/client.js:1445:8)at listOnTimeout (node:internal/timers:573:17)at process.processTimers (node:internal/timers:514:7) {address: '193.233.120.141:16199'}
]
hash= <Buffer ba 16 0d 84 85 59 c6 05 52 b7 83 f2 3c d3 55 5b 2a 32 c7 b8>
DHT节点数组: [{id: '6b5611b3bfb7b8c8372c069a1e22e540609bda5a',addr: '87.98.162.88:6881'},{id: 'a811480f80e15cc2da5de2efb637b55db52124a1',addr: '178.32.217.211:6881'},{id: 'af15df9751f12d69492050218fbad8ec1245bce3',addr: '37.48.111.3:28010'},{id: '89f562f9f211a457acfe33b20f629ccac543ab72',addr: '51.38.34.56:51413'},{id: 'a995297613a597c36b910494795510f888a39263',addr: '89.149.202.214:21147'},{id: '9b334e8f333ef9fa3f2a52934ec1fd771535e68e',addr: '178.162.174.223:28009'},{id: 'a555d8b451608de54ccad3db9a7349ec5096e407',addr: '178.162.173.132:28015'},{id: 'a5d1090886585bfbec069777aed63730feb71483',addr: '188.34.190.92:6881'},{id: '85f1caa50b72c07a86a9501968002b7d59501a95',addr: '46.242.12.117:13066'},{id: '997e40df66b6fb64577807c6c30802851843520b',addr: '178.162.174.237:28001'},{id: 'ae5a71d29d9b373b84ff5d397db31135caea6af8',addr: '146.71.50.196:4000'},{id: 'a3a090845890ffa9883b2f65e4cdd319c536b0af',addr: '47.54.23.223:51413'},{id: '9aa0c85e94e179e4692e3d86e707d5899062bed8',addr: '178.162.173.166:28015'},{id: '9f53fe555940af320f9c7540445589cc84369884',addr: '23.158.56.119:10095'},{id: '84fe47cc3c76ba793bc0f7f1ae6996431161ba60',addr: '88.201.206.119:3334'},{id: 'a3573c0b6206eaa41f2ce9d29dc9de5fef2865d1',addr: '81.207.238.6:1024'},{id: '9191c3ea0cf55e663d18fc552df2a580395f7a80',addr: '82.65.220.127:6885'},{id: 'b2498f2a643a78207bcb3dce4307f8e0a615297e',addr: '24.20.153.108:6969'},{id: 'b5a304f2843ba084416908fe7e7002fe9c5478ad',addr: '14.48.222.76:7801'},{id: 'a449d2b1d34c39c9ee4d917b24ce22af0db22248',addr: '5.129.239.125:49001'},{id: '9900258a640be2f0cd0c35a961a386c1cc9cf589',addr: '103.140.3.17:15195'},{id: 'e3d5f4b4aed69802dbb34b24f6fd358063dd1cf4',addr: '14.104.200.224:10920'},{id: 'e0f0da00d1bee565e0a21088787bdcbb4a2633e7',addr: '125.77.176.152:37740'},{id: 'e0dd29c1e17a46839ab2e54c32675e5463f9e03b',addr: '113.0.38.69:32981'},{id: 'e36ff0fa563342fd2fc905576a784e4277b9ee59',addr: '124.115.94.28:64425'},{id: 'e13b76f9a31ebe5a6d29b765b293143d461ca426',addr: '122.192.133.176:6887'},{id: 'e29a50d52c1c9029a9d3a7f9fe152e5803ae3344',addr: '36.4.10.196:38999'},{id: 'e5c14f6d2ee91906c9265afaab45482594f7467e',addr: '221.157.193.11:6881'},{id: 'e46507c044a8265a16360dc481a3c631dc79aff1',addr: '61.147.218.204:56016'},{id: 'e66a2f0d5056c00ba4425bab7ca0cfab4df7ddcf',addr: '120.40.56.40:22840'},{id: 'e632ccac3c4bc229581ea4d2039626cb12881e1c',addr: '218.91.170.101:6891'},{id: 'e6b14eb0462c8ac5e7553ec6b6003a65075c363e',addr: '39.112.211.158:40954'},{id: 'e71f1918956034be0a634b9cdbbec5665d2ac654',addr: '183.134.38.41:6890'},{id: 'e73c15b0beffd4373c145e00f07d4a450408dd52',addr: '61.173.61.203:59951'},{id: 'e711e8dda372363d608afa0a050d3fbdec8425db',addr: '185.149.91.43:51079'},{id: 'e71361d74d4799186ac0d62bccecbfe66c63b2cd',addr: '169.150.223.225:6881'},{id: 'e706b08a6b939e8d5e37ea2e4f9418c97cc1d66d',addr: '94.75.194.118:28006'},{id: 'e703e8c3a3c766f1ed6a365998f05ba84d81dd83',addr: '77.82.189.152:49001'},{id: 'e72eb05590c079a0acb407fdbb5204bc9b95d53b',addr: '49.245.2.242:11706'},{id: 'e725c22b82a5adebf493bd66ac859562b4f2b3ee',addr: '14.103.76.31:60020'},{id: 'e71f2ba6bec45aff6d35b3356e1ed3df4d5f15bb',addr: '121.236.15.238:9888'},{id: 'e751aa9bd98fbfc9b3aaa026443ebd8c429f5fcc',addr: '195.154.171.138:5250'},{id: 'e74e28a755e0b680d4197753c31e9ad081d8b8b4',addr: '184.64.199.181:48670'},{id: 'e74ca9d20211352647212795b0c4e761c067d874',addr: '220.200.42.0:62559'},{id: 'e74bbc1b073c79c49051b88c502986c8c21dd36f',addr: '81.40.181.46:8621'},{id: 'e7507c39a1cb087aa7ccc8f3adc3d04203d37f31',addr: '185.203.56.10:60696'},{id: 'e743d8ec35a30db1bb12137f67eae6e39b013508',addr: '183.195.21.211:13284'},{id: 'e74f8c5f47304ac841de681ec4b4cfbc134cbd7f',addr: '112.24.228.151:27868'},{id: 'e7503d0d29de824e4caae6017a4e6419d1a43082',addr: '81.202.75.215:6889'},{id: 'e753d24bdf60c8128dd48d15431093c20c34693d',addr: '209.193.67.78:51413'},{id: 'e755e97111a41814b466e4b7a5526a06f2cc534c',addr: '186.57.159.109:6881'},{id: 'e761c3d8d84b09395c0a2affd38e24c0c9418b4c',addr: '42.193.175.166:18826'},{id: 'e760ac2c0424839b85bf02179b32866ab297689b',addr: '88.0.223.106:51413'},{id: 'e767d67550eb627914a8d20b78728c9d59d95fc5',addr: '195.230.109.6:43242'},{id: 'e760a6ddaf17ee5725d15c21d9ed8186085ff04c',addr: '59.5.76.86:41202'},{id: 'e76579760dc1ad7e3d992d2bef992d6ea156bd89',addr: '131.153.18.45:22574'},{id: 'e762cffedfef8b697f64e88452b548e4ca052d0f',addr: '217.225.89.57:6881'},{id: 'e763d907a08cf6fcb07eecc265d595632377624c',addr: '107.181.234.142:51413'},{id: 'e766eb1feb72f2cb87aa747086e3faef8764f06e',addr: '219.251.137.25:40972'},{id: 'e760b549f1f1bbe9ebb3a6db3c870c3e99245e52',addr: '59.6.5.153:64536'},{id: 'e760afea3b0f54c53a75070241592c5dc6fd0c59',addr: '27.125.248.23:15630'},{id: 'e767644b57a9dbe2029ead2d395633301bfff07e',addr: '59.3.119.55:40804'},{id: 'e763054ba30fa0e3e767721c6a911ce9e7ac50fe',addr: '60.163.61.30:17077'},{id: 'e76595f27f020daa5d106a3d4e25bd24b1564b6a',addr: '179.131.236.32:50321'},{id: 'e7672ee9801a6f85413c6314f6305f7b94f93e37',addr: '121.128.111.23:40811'},{id: 'e760245fb585019447ba47e497a94d662e6349c8',addr: '59.188.57.119:6889'},{id: 'e7620cc83f2240a3b3d69ef294eece88c729f902',addr: '72.21.17.91:61318'},{id: 'e761f830ff2f48422470dabafe53ce7d08fb3cd2',addr: '85.140.162.247:55414'},{id: 'e7672049fe578e109d980c8eb64057cdb3454c02',addr: '207.65.155.118:51413'},{id: 'e76793864960d52d457ef2ebe2fcb40d02f57ca9',addr: '157.157.193.103:5030'},{id: 'e769bdb7be648414ae3cafb158fb4c18fa94826a',addr: '72.21.17.3:12743'},{id: 'e76a5736ae4740254fc6c57c04afe7bcd093c5fc',addr: '222.113.206.3:32996'},{id: 'e769bd26374a11ebcd96ac0021ea2bbe5aec00f2',addr: '72.21.17.3:57563'},{id: 'e76b41a618e160c3a5c837d5ecc70648305e58a4',addr: '2.98.139.134:19856'},{id: 'e768b641d52f2dfe3bf304d3ee8a8ce4dded3bf8',addr: '119.197.185.173:60761'},{id: 'e76bb57181f76165df4289688ea4e6730f3cf7ec',addr: '188.21.206.210:29115'},{id: 'e76b7ad6ae529049f1f1bbe9ebb3a6db3c870ce1',addr: '84.9.37.4:35609'},{id: 'e76bc6b2e88753a773e28c5c73ce4dd13178d9c6',addr: '111.196.228.198:5774'},{id: 'e769bf4d3366684d43e979222cd64fdb976a0142',addr: '72.21.17.3:62436'},{id: 'e7683854beae9b503af99d95f65dc8626d274b94',addr: '178.162.174.237:28007'},{id: 'e7686b42c80418f1dbaac7420de4e7b865eed412',addr: '89.105.15.4:16345'},{id: 'e769beafcbe43b71166602d4f70a330402c7b07a',addr: '72.21.17.3:20057'},{id: 'e7680d81a626489edee91255d9a08264a78cb8f7',addr: '170.150.1.175:26340'},{id: 'e76c07b8216f99cb4eee48795bc504be5e85ad92',addr: '178.221.133.198:46873'},{id: 'e76c04cffe2e06e0aa57a0edec0062b8f42c5803',addr: '49.117.14.143:8392'},{id: 'e76c0d1dc74193c186b35361733df3bb591d16ef',addr: '46.197.49.135:26616'},{id: 'e76c00c84cc41bd997f5c942055eed780a74189e',addr: '185.251.151.248:51413'},{id: 'e76c047b5dc0aaad6529b9e9487159c2c74fed01',addr: '223.247.106.145:55291'},{id: 'e76c00169995fb98f8c90f59817b3c989b5dfb3d',addr: '82.132.246.194:54677'},{id: 'e76c074d30740c88fcdac1f93ba8faa46fa572a5',addr: '122.148.246.194:30754'},{id: 'e76c0f976890ad222b72782990615e613e03d7e7',addr: '212.35.183.80:3168'},{id: 'e76c06ba160fdc583ed1969d1db70fae30a78541',addr: '90.15.84.33:40622'},{id: 'e76c06ba160fdc583ed1969d1db70f8dc9547307',addr: '49.12.86.202:6883'},{id: 'e76c06ba160fdc583ed152fbdd8d2da45f042476',addr: '146.19.24.245:23544'},{id: 'e76c0993a20cef635b7fad5e4dc95a8bcae8e107',addr: '132.147.119.80:1041'},{id: 'e76c0df644d2255ca4a4c8c8ee3029ecb2fd2d1b',addr: '178.234.59.239:6881'},{id: 'e76c1edc0b17287dbee23dbdc40875faab321fff',addr: '93.156.208.226:48379'},{id: 'e76c1fd6f2a275af36e9955fbcce091188938046',addr: '200.121.141.155:31719'},{id: 'e76c108b98fc86ac2e0d75ed5ff5c03e163dd9eb',addr: '82.7.191.13:36957'},{id: 'e76c1bde86a78072e5aafa52b4d87b270f1d571e',addr: '70.175.203.76:6881'},... 100 more items
]

3. 发布announce

dht.announce(sha, config.dht.announce, function (err) {if (err !== null) {console.log('Announced ' + sha)}
})
  • dht.announce(sha, ...):将特定的 SHA 值(GitTorrent项目即 Git 提交的哈希)及其相应的网络地址发布到 DHT 网络。其他节点可以通过这个信息来查找特定的 Git 数据。通过这个函数,节点通知 DHT 网络,它正在下载一个特定的种子。这使得其他节点能够发现这个下载中的节点,从而进行数据交换。具体实现如下:
/*** Announce that the peer, controlling the querying node, is downloading a torrent on a port.* 声明当前节点正在下载一个种子,告诉DHT网络此信息。* * @param {string|Buffer} infoHash - 种子的 infoHash,唯一标识符。* @param {number} port - 当前节点下载种子的端口号。* @param {function=} cb - 可选的回调函数,宣布完成时调用。*/
DHT.prototype.announce = function (infoHash, port, cb) {var self = this// 如果回调函数没有提供,设置一个空函数if (!cb) cb = function () {}// 如果DHT实例已经销毁,调用回调函数并传递错误信息if (self.destroyed) return cb(new Error('dht is destroyed'))// 将infoHash转换为Buffer格式infoHash = idToBuffer(infoHash)// 将infoHash转换为十六进制字符串,便于处理和输出var infoHashHex = idToHexString(infoHash)// 输出调试信息,表示正在宣布下载self._debug('announce %s %s', infoHashHex, port)// 遍历本地节点地址,为每个地址添加peer信息到DHT表中self.localAddresses.forEach(function (address) {self._addPeer(address + ':' + port, infoHashHex)})// 查找是否已经有对应 infoHash 的路由表存在var table = self.tables[infoHashHex]if (table) {// 如果有对应的路由表,直接使用表中的最近节点进行处理onClosest(null, table.closest({ id: infoHash }, K))} else {// 否则,发起一个lookup查询,查找最近的节点self.lookup(infoHash, onClosest)}/*** 当查找到最近的节点时调用的回调函数* @param {Error|null} err - 错误信息,如果存在错误* @param {Array} closest - 查找到的最近节点列表*/function onClosest (err, closest) {if (err) return cb(err) // 如果有错误,调用回调并返回错误信息// 遍历每个最近的节点,向他们发送 "announce_peer" 消息closest.forEach(function (contact) {self._sendAnnouncePeer(contact.addr, infoHash, port, contact.token)})// 输出调试信息,表示宣布操作结束self._debug('announce end %s %s', infoHashHex, port)// 调用回调函数,表示宣布完成cb(null)}
}
  • 路由表的重用
    • 如果 dht.announce 在调用 dht.lookup 之后的 5 分钟内被调用,并且路由表仍然有效,则可以重用最近的路由表。这意味着函数会更快地完成,因为不需要再次查询其他节点。
    • 如果调用时没有缓存的路由表,dht.announce 会首先执行 dht.lookup 来发现相关节点。这将耗费更多时间,因为需要重新获取有效的 “tokens”。下面是一个官方提供的路由表示例:
const dht1 = new DHT()// some time passes ...// destroy the dht
const nodes = dht1.toJSON().nodes
dht1.destroy()// some time passes ...// initialize a new dht with the same routing table as the first
const dht2 = new DHT()nodes.forEach(function (node) {dht2.addNode(node)
})

4. 增dht.put(opts, callback)

import DHT from 'bittorrent-dht'
const dht = new DHT()
const value = Buffer.alloc(200).fill('abc')// 可放入一个小于 1000 字节的值dht.put({ v: value }, function (err, hash) {console.error('error=', err)console.log('hash=', hash)
})
  • 此扩展允许在 BitTorrent DHT 中存储和检索任意数据 [1]。它既支持存储不可变项目(其中密钥是数据本身的 SHA-1 哈希值),也支持存储可变项目(其中密钥是用于对数据进行签名的密钥对的公钥)。具体实现如下:
/*** Write arbitrary mutable and immutable data to the DHT.* Specified in BEP44: http://bittorrent.org/beps/bep_0044.html* @param {Object} opts* @param {function=} cb*/
DHT.prototype.put = function (opts, cb) {var self = thisvar isMutable = opts.k || opts.sigif (opts.v === undefined) {throw new Error('opts.v not given')}if (opts.v.length >= 1000) {throw new Error('v must be less than 1000 bytes in put()')}if (isMutable && opts.cas && typeof opts.cas !== 'number') {throw new Error('opts.cas must be an integer if provided')}if (isMutable && !opts.k) {throw new Error('opts.k ed25519 public key required for mutable put')}if (isMutable && opts.k.length !== 32) {throw new Error('opts.k ed25519 public key must be 32 bytes')}if (isMutable && !opts.sig) {throw new Error('opts.sig signature required for mutable put')}if (isMutable && opts.sig.length !== 64) {throw new Error('opts.sig signature must be 64 bytes')}if (isMutable && opts.salt && opts.salt.length > 64) {throw new Error('opts.salt is > 64 bytes long')}if (isMutable && opts.seq === undefined) {throw new Error('opts.seq not provided for a mutable update')}if (isMutable && typeof opts.seq !== 'number') {throw new Error('opts.seq not an integer')}return self._put(opts, cb)
}/*** put() without type checks for internal use* @param {Object} opts* @param {function=} cb*/
DHT.prototype._put = function (opts, cb) {var self = thisvar pending = 0var errors = []var isMutable = opts.k || opts.sigvar hash = isMutable? sha1(opts.salt ? Buffer.concat([ opts.salt, opts.k ]) : opts.k): sha1(opts.v)if (self.nodes.toArray().length === 0) {process.nextTick(function () {addLocal(null, [])})} else {self.lookup(hash, onLookup)}function onLookup (err, nodes) {if (err) return cb(err)nodes.forEach(function (node) {put(node)})addLocal()}function addLocal () {var localData = {id: self.nodeId,v: opts.v}var localAddr = '127.0.0.1:' + self._portif (isMutable) {if (opts.cas) localData.cas = opts.caslocalData.sig = opts.siglocalData.k = opts.klocalData.seq = opts.seqlocalData.token = opts.token || self._generateToken(localAddr)}self.nodes.add({id: hash,addr: localAddr,data: localData})if (pending === 0) {process.nextTick(function () { cb(errors, hash) })}}return hashfunction put (node) {if (node.data) return // skip data nodespending += 1var t = self._getTransactionId(node.addr, next(node))var data = {a: {id: opts.id || self.nodeId,v: opts.v},t: transactionIdToBuffer(t),y: 'q',q: 'put'}if (isMutable) {data.a.token = opts.token || self._generateToken(node.addr)data.a.seq = Math.round(opts.seq)data.a.sig = opts.sigdata.a.k = opts.kif (opts.salt) data.a.salt = opts.saltif (opts.cas) data.a.cas = Math.round(opts.cas)}self._send(node.addr, data)}function next (node) {return function (err) {if (err) {err.address = node.addrerrors.push(err)}if (--pending === 0) cb(errors, hash)}}
}

5. 查dht.get(hash, opts, callback)

    var val = new Buffer(key, 'hex')dht.get(val, function (err, res) {if (err) {return console.error(err)}var json = res.v.toString()var repos = JSON.parse(json)}

GitTorrent的gittorrentd命令实现

  • gittorrentd通过 BitTorrent DHT 和 GitTorrent 协议,将 Git 仓库数据通过 P2P 网络共享。
  • 通过遍历本地的 Git 仓库目录,列出所有引用,并将其 SHA 通过 DHT 网络广播。
  • 使用 net 模块创建 TCP 服务器,响应来自 P2P 节点的 Git 数据请求,并通过 WebTorrent 实现种子文件的共享。

创建 DHT 实例

#!/usr/bin/env node  // 文件开头的这行叫做“shebang”,它告诉操作系统使用node来运行这个脚本。因此,当你在命令行中运行./gittorrentd时,它实际上是在用Node.js环境执行该脚本。// 引入所需的模块
var DHT = require('bittorrent-dht'); // BitTorrent 的 DHT 模块,用于发现对等节点
var EC = require('elliptic').ec; // 椭圆曲线加密库,支持多种加密算法
var ed25519 = new EC('ed25519'); // 使用 Ed25519 椭圆曲线进行加密操作
var exec = require('child_process').exec; // 允许执行 shell 命令
var glob = require('glob'); // 用于文件路径匹配
var fs = require('fs'); // 文件系统模块
var hat = require('hat'); // 随机 ID 生成库
var net = require('net'); // 提供网络套接字操作
var Protocol = require('bittorrent-protocol'); // BitTorrent 协议模块
var spawn = require('child_process').spawn; // 生成子进程以运行外部命令
var ut_gittorrent = require('ut_gittorrent'); // 用于 BitTorrent 上的 Git 传输扩展
var ut_metadata = require('ut_metadata'); // BitTorrent 元数据传输扩展
var WebTorrent = require('webtorrent'); // WebTorrent 客户端库,用于 BitTorrent 下载和种子
var zeroFill = require('zero-fill'); // 补零函数,格式化数字
var config = require('./config'); // 加载用户自定义配置
var git = require('./git'); // 加载 Git 操作相关的自定义模块// 生成 BitTorrent 客户端的版本号字符串(用于 Peer ID),根据 package.json 的版本生成
var VERSION = require('./package.json').version.match(/([0-9]+)/g).slice(0, 2).map(zeroFill(2)).join('');// 错误处理函数,打印错误并退出
function die(error) {console.error(error);process.exit(1);
}// 创建 DHT 实例,使用配置文件中定义的引导节点
var dht = new DHT({bootstrap: config.dht.bootstrap
});
// DHT 监听来自 Peers 的请求
dht.listen(config.dht.listen);var announcedRefs = {}; // 存储已经公布的 Git 引用 (refs)
var userProfile = {repositories: {} // 存储用户的 Git 仓库信息
};// 生成或读取密钥文件
var key = create_or_read_keyfile();function create_or_read_keyfile() {// 如果密钥文件不存在,创建一个新的 Ed25519 密钥对if (!fs.existsSync(config.key)) {var keypair = new EC('ed25519').genKeyPair();fs.writeFileSync(config.key, JSON.stringify({pub: keypair.getPublic('hex'), // 公钥priv: keypair.getPrivate('hex') // 私钥}));}// 读取已存在的密钥文件var key = JSON.parse(fs.readFileSync(config.key).toString());return ed25519.keyPair({priv: key.priv, // 私钥privEnc: 'hex',pub: key.pub, // 公钥pubEnc: 'hex'});
}// 补零函数,确保缓冲区长度达到指定的字节数
function bpad(n, buf) {if (buf.length === n) return buf;if (buf.length < n) {var b = new Buffer(n);buf.copy(b, n - buf.length);for (var i = 0; i < n - buf.length; i++) b[i] = 0;return b;}
}

当 DHT 就绪时,执行以下操作


var head = ''; // 当前仓库的 HEAD 引用// 当 DHT 就绪时,执行以下操作
dht.on('ready', function () {// 查找文件目录// 使用 glob 搜索所有带有 git-daemon-export-ok 文件的目录(Git 可公开的仓库)//,比如/projectA/git-daemon-export-ok和/projectB/.git/git-daemon-export-okvar repos = glob.sync('*/{,.git/}git-daemon-export-ok', { strict: false });var count = repos.length;repos.forEach(function (repo) {console.log('in repo ' + repo);repo = repo.replace(/git-daemon-export-ok$/, ''); // 文件名中移除 git-daemon-export-ok console.log(repo);var reponame = repo.replace(/\/.git\/$/, ''); // 提取仓库名或路径部分userProfile.repositories[reponame] = {}; // 初始化用户的仓库信息// 使用自定义 Git 模块列出该仓库的所有引用 (refs)// 第二个参数是一个回调函数,当 git ls-remote 获取到每一个引用时,都会调用该回调函数,并传递该引用的 sha(40 位提交哈希)和 ref(引用名,通常是分支或标签的全名)var ls = git.ls(repo, function (sha, ref) {// 只处理 HEAD 和 heads(分支)引用,忽略其他引用if (ref !== 'HEAD' && !ref.match(/^refs\/heads\//)) {return;}if (ref === 'refs/heads/master') {head = sha; // 如果是 master 分支,将其 SHA 设为 HEAD}userProfile.repositories[reponame][ref] = sha; // 记录仓库引用if (!announcedRefs[sha]) {console.log('Announcing ' + sha + ' for ' + ref + ' on repo ' + repo);announcedRefs[sha] = repo; // 标记已公布的引用dht.announce(sha, config.dht.announce, function (err) {if (err !== null) {console.log('Announced ' + sha);}});}});// 当列出引用结束时,减少计数器,最终发布用户的可变密钥ls.stdout.on('end', function () {count--;if (count <= 0) {publish_mutable_key(); // 当所有仓库处理完毕,发布密钥}});ls.on('exit', function (err) {if (err) {die(err); // 如果 git.ls 失败,终止程序}});});// 定义publish_mutable_key函数发布用户的可变密钥到 DHTfunction publish_mutable_key() {var json = JSON.stringify(userProfile); // 将用户仓库信息序列化为 JSONif (json.length > 950) {console.error("Can't publish mutable key: doesn't fit in 950 bytes.");return false; // 如果数据过大,无法发布}var value = new Buffer(json.length);value.write(json);var sig = key.sign(value); // 使用用户密钥对数据进行签名var opts = {k: bpad(32, Buffer(key.getPublic().x.toArray())), // 公钥seq: 0,v: value, // 用户数据sig: Buffer.concat([bpad(32, Buffer(sig.r.toArray())), // 签名的一部分bpad(32, Buffer(sig.s.toArray()))  // 签名的另一部分])};console.log(json);// 将可变密钥发布到 DHTdht.put(opts, function (errors, hash) {console.error('errors=', errors);console.log('hash=', hash.toString('hex')); // 打印发布的哈希值});}// 创建一个 TCP 服务器,并处理 P2P 连接net.createServer(function (socket) {var wire = new Protocol(); // 创建新的 BitTorrent 协议实例(bittorrent-protocol)wire.use(ut_gittorrent()); // 使用 GitTorrent 扩展wire.use(ut_metadata()); // 使用元数据传输扩展// 将 socket 和协议 wire 连接起来socket.pipe(wire).pipe(socket);// 当收到握手时,处理对等节点wire.on('handshake', function (infoHash, peerId) {console.log('Received handshake for ' + infoHash.toString('hex'));var myPeerId = new Buffer('-WW' + VERSION + '-' + hat(48), 'utf8');wire.handshake(new Buffer(infoHash), new Buffer(myPeerId)); // 发送握手响应});// 当对等节点请求 Git 包时,生成相应的数据wire.ut_gittorrent.on('generatePack', function (sha) {console.error('calling git pack-objects for ' + sha);if (!announcedRefs[sha]) {console.error('Asked for an unknown sha: ' + sha);return;}var directory = announcedRefs[sha];var have = null;if (sha !== head) {have = head;}// 使用 Git 打包对象var pack = git.upload_pack(directory, sha, have);pack.stderr.pipe(process.stderr);// 当打包完成时,写入到文件pack.on('ready', function () {var filename = sha + '.pack';var stream = fs.createWriteStream(filename);pack.stdout.pipe(stream);stream.on('close', function () {console.error('Finished writing ' + filename);// 使用 WebTorrent 将文件进行种子共享var webtorrent = new WebTorrent({dht: {bootstrap: config.dht.bootstrap},tracker: false});// 种子创建完成后发送给对等节点webtorrent.seed(filename, function onTorrent (torrent) {console.error(torrent.infoHash);wire.ut_gittorrent.sendTorrent(torrent.infoHash);});});});// 打包进程结束时,检查退出码pack.on('exit', function (code) {if (code !== 0) {console.error('git-upload-pack process exited with code ' + code);}});});}).listen(config.dht.announce); // 监听配置中定义的端口
});

相关文章:

【p2p、分布式,区块链笔记 Torrent】: WebTorrent GitTorrent bittorrent-dht

bittorrent-dht模块 BitTorrent DHT 通过 DHT 网络广播值&#xff0c;允许其他用户通过 DHT 来发现和获取这些数据。 1. 导入依赖 var DHT require(bittorrent-dht)2. 创建实例 var dht new DHT({bootstrap: config.dht.bootstrap }) dht.listen(config.dht.listen)new D…...

【Next.js 项目实战系列】05-删除 Issue

原文链接 CSDN 的排版/样式可能有问题&#xff0c;去我的博客查看原文系列吧&#xff0c;觉得有用的话&#xff0c;给我的库点个star&#xff0c;关注一下吧 上一篇【Next.js 项目实战系列】04-修改 Issue 删除 Issue 添加删除 Button​ 本节代码链接 这里我们主要关注布局…...

Springboot api http并发测试请求

pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> 线程发起请求 package com.example.demo;import org.springframework.http.HttpEntity; import org…...

Qt的websocket客户端和服务器测试(非安全版本)

测试内容&#xff1a; 客户端&#xff1a; 1 连接服务器 2 发送数据 3 处理错误信号 4 监听断开信号 5 接收服务器的数据 服务器&#xff1a; 1 监听等待客户端连接 2 向指定的客户端发送数据 4 监听断开信号 5 接收客户端的数据 测试界面 工程文件.pro添加的内容&#xff1a;…...

Prometheus运维监控平台之监控指标注册到consul脚本开发、自定义监控项采集配置调试(三)

系列文章目录 运维监控平台搭建 运维监控平台监控标签 golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置V1版本 文章目录 系列文章目录目的一、监控指标注册到consul的golang脚本开发1、修改settings.yaml文件2、修改config/ocnsul,go文件3、修改core/consul…...

C语言——数组

1.数组的概念 数组是一组相同类型元素的集合&#xff1b; 数组中可以存放1个或多个元素&#xff0c;但数组元素个数不能为0。 同时数组可以分为一维数组和多维数组&#xff0c;多维数组一般常见 是二维数组。 2.一维数组的创建和初始化 一维数组的创建的基本语法&#xff1a; …...

MySQL-09.DDL-表结构操作-查询修改删除

一.查询 二.修改 三.删除 -- DDL&#xff1a;查看表结构 -- 查看&#xff1a;当前数据库下的表show tables ;-- 查看&#xff1a;查看指定的表结构 desc tb_emp;-- 查看&#xff1a;数据库的建表语句 show create table tb_emp;-- DDL:修改表结构 -- 修改&#xff1a;为表tb…...

WileyNJDv5_Template模板无法编译生成pdf文件

文章目录 问题解决办法结果 问题 使用WileyNJDv5_Template模板时&#xff0c;修改tex文件里的内容&#xff0c;按F6编译后&#xff0c;并没有报错&#xff0c;但是编辑后的pdf文件没有生成&#xff0c;因为看文件夹里的pdf文件日期还是以前的日期&#xff0c;所以是旧版的pdf文…...

亿配芯城(ICGOODFIND)教你外贸(海外)推广电子元器件芯片的专用词语

在电子元器件行业&#xff0c;海外推广是企业拓展市场、提升竞争力的重要手段。而在海外推广过程中&#xff0c;恰当运用专用词语能够准确传达产品信息、吸引客户关注&#xff0c;提升推广效果。本文将详细介绍亿配芯城&#xff08;ICGOODFIND&#xff09;电子元器件海外推广中…...

windows和linux的一些使用问题一一记录

文章目录 windows 11 激活wsl文件共享命令互通wslg网络 Hyper-V双系统遇到再记录……… windows 11 激活 然后执行 slmgr /skms kms.03k.org slmgr /atowsl 卡死打开任务管理关闭下就行了 wsl --list -v # 安装的 wsl --list --online #可以安装的wsl -d kali-linux # 启…...

排序算法上——插入,希尔,选择,堆排序

前言&#xff1a; 常见排序方法如下&#xff1a; 本篇将介绍4种排序方法&#xff0c;分别为插入排序&#xff0c;希尔排序&#xff0c;选择排序&#xff0c;堆排序&#xff0c;并分别举例与讲解。 一. 插入排序 1.1 含义与动图分析 插入排序的思想是在有序区间的下一个位置…...

Mycat 详细介绍及入门实战,解决数据库性能问题

一、基本原理 1、数据分片 &#xff08;1&#xff09;、水平分片 Mycat 将一个大表的数据按照一定的规则拆分成多个小表&#xff0c;分布在不同的数据库节点上。例如&#xff0c;可以根据某个字段的值进行哈希取模&#xff0c;将数据均匀的分布到不同的节点上。 这样做的好处…...

FFmpeg源码:avformat_new_stream函数分析

一、avformat_new_stream函数的声明 avformat_new_stream函数定义在FFmpeg源码&#xff08;本文演示用的FFmpeg源码版本为7.0.1&#xff09;的头文件libavformat/avformat.h中&#xff1a; /*** Add a new stream to a media file.** When demuxing, it is called by the dem…...

【java】深入解析Lambda表达式

Lambda表达式是Java 8引入的一项重要特性&#xff0c;它提供了一种简洁的方式来实现函数式编程。Lambda表达式的使用广泛而且灵活&#xff0c;可以简化代码并提高可读性。本篇文章将深入解析Lambda表达式&#xff0c;包括使用场景、基础学习、代码案例、实现方法和注意事项等方…...

Chromium html<img>对应c++接口定义

<img src"tulip.jpg" alt"上海鲜花港 - 郁金香" /> 1、html_tag_names.json5中接口定义&#xff1a; &#xff08;third_party\blink\renderer\core\html\html_tag_names.json5&#xff09; {name: "img",constructorNeedsCreateElementF…...

卸载Python

1、查看安装框架位置并删除 Sudo rm -rf /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8 2、查看应用并删除 在 /Applications/Python 3.x 看是否存在&#xff0c;如果存在并删除。 3、删除软连接 ls -l /usr/bin/py* 或 ls -…...

算法剖析:二分查找

文章目录 前言二分查找模板朴素模板左右查找模板 一、二分查找二、 在排序数组中查找元素的第一个和最后一个位置三、搜索插入位置四、x 的平方根五、山脉数组的峰顶索引六、寻找峰值七、寻找旋转排序数组中的最小值八、 点名总结 前言 二分查找是一种高效的查找算法&#xff…...

Invoke 和 InvokeRequired以及他们两个的区别

在.NET中&#xff0c;Invoke和InvokeRequired是Windows Forms编程中用于确保线程安全的关键方法和属性。它们通常用在多线程环境中&#xff0c;以确保UI控件的更新操作在创建控件的线程上执行&#xff0c;避免因跨线程操作导致的异常。 InvokeRequired 属性 InvokeRequired属…...

SpringBoot概览及核心原理

Spring Boot 是由Pivotal 团队设计的全新框架&#xff0c;其目的是用来简化 Spring 应用开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使得开发人员不再需要定义一系列样板化的配置文件&#xff0c;而专注于核心业务开发&#xff0c;项目涉及的一些基础设施则交…...

根据basic auth请求https获取token

根据basic auth请求https获取token 对接第三方接口&#xff0c;给了接口文档&#xff0c;但是没有示例代码&#xff0c;postman一直可请求成功&#xff0c;java就是不行。百思不得其解&#xff0c;最后请求公司大神&#xff0c;得到一套秘籍。 第一步 第二步 Authorization&am…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...