mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-13 07:41:32 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
b5c9e48b68 | |||
9942cbd50c | |||
037c965a67 | |||
748b552876 | |||
961b48bb8d | |||
000826db21 | |||
45c33675a7 | |||
a28c878f4a | |||
67067c97d5 | |||
f45cd1c4b5 | |||
0a02207116 | |||
0b854a949f |
@ -45,7 +45,7 @@ const after = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
bundlesize: { maxSize: '225kB' },
|
bundlesize: { maxSize: '260kB' },
|
||||||
hooks: {
|
hooks: {
|
||||||
pre: before,
|
pre: before,
|
||||||
post: after
|
post: after
|
||||||
|
35
.github/workflows/main.yml
vendored
35
.github/workflows/main.yml
vendored
@ -72,3 +72,38 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- run: yarn
|
- run: yarn
|
||||||
- run: cd examples && yarn && npm run test -- chat
|
- run: cd examples && yarn && npm run test -- chat
|
||||||
|
test-connection-encryption-example:
|
||||||
|
needs: check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: yarn
|
||||||
|
- run: cd examples && yarn && npm run test -- connection-encryption
|
||||||
|
test-echo-example:
|
||||||
|
needs: check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: yarn
|
||||||
|
- run: cd examples && yarn && npm run test -- echo
|
||||||
|
test-libp2p-in-the-browser-example:
|
||||||
|
needs: check
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: yarn
|
||||||
|
- run: cd examples && yarn && npm run test -- libp2p-in-the-browser
|
||||||
|
test-discovery-mechanisms-example:
|
||||||
|
needs: check
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: yarn
|
||||||
|
- run: cd examples && yarn && npm run test -- discovery-mechanisms
|
||||||
|
test-pnet-example:
|
||||||
|
needs: check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: yarn
|
||||||
|
- run: cd examples && yarn && npm run test -- pnet
|
||||||
|
13
CHANGELOG.md
13
CHANGELOG.md
@ -1,3 +1,16 @@
|
|||||||
|
## [0.30.3](https://github.com/libp2p/js-libp2p/compare/v0.30.2...v0.30.3) (2021-01-27)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.30.2](https://github.com/libp2p/js-libp2p/compare/v0.30.1...v0.30.2) (2021-01-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* store multiaddrs during content and peer routing queries ([#865](https://github.com/libp2p/js-libp2p/issues/865)) ([45c3367](https://github.com/libp2p/js-libp2p/commit/45c33675a7412c66d0fd4e113ef8506077b6f492))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.30.1](https://github.com/libp2p/js-libp2p/compare/v0.30.0...v0.30.1) (2021-01-18)
|
## [0.30.1](https://github.com/libp2p/js-libp2p/compare/v0.30.0...v0.30.1) (2021-01-18)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Libp2p = require('../../')
|
const Libp2p = require('../..')
|
||||||
const TCP = require('libp2p-tcp')
|
const TCP = require('libp2p-tcp')
|
||||||
const Mplex = require('libp2p-mplex')
|
const Mplex = require('libp2p-mplex')
|
||||||
const { NOISE } = require('libp2p-noise')
|
const { NOISE } = require('libp2p-noise')
|
@ -1,4 +1,4 @@
|
|||||||
# Encrypted Communications
|
# Connection Encryption
|
||||||
|
|
||||||
libp2p can leverage the encrypted communications from the transports it uses (i.e WebRTC). To ensure that every connection is encrypted, independently of how it was set up, libp2p also supports a set of modules that encrypt every communication established.
|
libp2p can leverage the encrypted communications from the transports it uses (i.e WebRTC). To ensure that every connection is encrypted, independently of how it was set up, libp2p also supports a set of modules that encrypt every communication established.
|
||||||
|
|
30
examples/connection-encryption/test.js
Normal file
30
examples/connection-encryption/test.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const execa = require('execa')
|
||||||
|
const pDefer = require('p-defer')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
|
||||||
|
async function test () {
|
||||||
|
const messageReceived = pDefer()
|
||||||
|
process.stdout.write('1.js\n')
|
||||||
|
|
||||||
|
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||||
|
cwd: path.resolve(__dirname),
|
||||||
|
all: true
|
||||||
|
})
|
||||||
|
|
||||||
|
proc.all.on('data', async (data) => {
|
||||||
|
process.stdout.write(data)
|
||||||
|
|
||||||
|
const s = uint8ArrayToString(data)
|
||||||
|
if (s.includes('This information is sent out encrypted to the other peer')) {
|
||||||
|
messageReceived.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await messageReceived.promise
|
||||||
|
proc.kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = test
|
@ -7,15 +7,7 @@ const Mplex = require('libp2p-mplex')
|
|||||||
const { NOISE } = require('libp2p-noise')
|
const { NOISE } = require('libp2p-noise')
|
||||||
const Bootstrap = require('libp2p-bootstrap')
|
const Bootstrap = require('libp2p-bootstrap')
|
||||||
|
|
||||||
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json
|
const bootstrapers = require('./bootstrapers')
|
||||||
const bootstrapers = [
|
|
||||||
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
||||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
|
||||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
|
||||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
|
||||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
|
||||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
|
||||||
]
|
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
|
13
examples/discovery-mechanisms/bootstrapers.js
vendored
Normal file
13
examples/discovery-mechanisms/bootstrapers.js
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json
|
||||||
|
const bootstrapers = [
|
||||||
|
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
||||||
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||||
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||||
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||||
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||||
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = bootstrapers
|
42
examples/discovery-mechanisms/test-1.js
Normal file
42
examples/discovery-mechanisms/test-1.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const execa = require('execa')
|
||||||
|
const pWaitFor = require('p-wait-for')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
const bootstrapers = require('./bootstrapers')
|
||||||
|
|
||||||
|
const discoveredCopy = 'Discovered:'
|
||||||
|
const connectedCopy = 'Connection established to:'
|
||||||
|
|
||||||
|
async function test () {
|
||||||
|
const discoveredNodes = []
|
||||||
|
const connectedNodes = []
|
||||||
|
|
||||||
|
process.stdout.write('1.js\n')
|
||||||
|
|
||||||
|
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||||
|
cwd: path.resolve(__dirname),
|
||||||
|
all: true
|
||||||
|
})
|
||||||
|
|
||||||
|
proc.all.on('data', async (data) => {
|
||||||
|
process.stdout.write(data)
|
||||||
|
const line = uint8ArrayToString(data)
|
||||||
|
|
||||||
|
// Discovered or Connected
|
||||||
|
if (line.includes(discoveredCopy)) {
|
||||||
|
const id = line.trim().split(discoveredCopy)[1]
|
||||||
|
discoveredNodes.push(id)
|
||||||
|
} else if (line.includes(connectedCopy)) {
|
||||||
|
const id = line.trim().split(connectedCopy)[1]
|
||||||
|
connectedNodes.push(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await pWaitFor(() => discoveredNodes.length === bootstrapers.length && connectedNodes.length === bootstrapers.length)
|
||||||
|
|
||||||
|
proc.kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = test
|
35
examples/discovery-mechanisms/test-2.js
Normal file
35
examples/discovery-mechanisms/test-2.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const execa = require('execa')
|
||||||
|
const pWaitFor = require('p-wait-for')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
|
||||||
|
const discoveredCopy = 'Discovered:'
|
||||||
|
|
||||||
|
async function test() {
|
||||||
|
const discoveredNodes = []
|
||||||
|
|
||||||
|
process.stdout.write('2.js\n')
|
||||||
|
|
||||||
|
const proc = execa('node', [path.join(__dirname, '2.js')], {
|
||||||
|
cwd: path.resolve(__dirname),
|
||||||
|
all: true
|
||||||
|
})
|
||||||
|
|
||||||
|
proc.all.on('data', async (data) => {
|
||||||
|
process.stdout.write(data)
|
||||||
|
const line = uint8ArrayToString(data)
|
||||||
|
|
||||||
|
if (line.includes(discoveredCopy)) {
|
||||||
|
const id = line.trim().split(discoveredCopy)[1]
|
||||||
|
discoveredNodes.push(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await pWaitFor(() => discoveredNodes.length === 2)
|
||||||
|
|
||||||
|
proc.kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = test
|
11
examples/discovery-mechanisms/test.js
Normal file
11
examples/discovery-mechanisms/test.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const test1 = require('./test-1')
|
||||||
|
const test2 = require('./test-2')
|
||||||
|
|
||||||
|
async function test () {
|
||||||
|
await test1()
|
||||||
|
await test2()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = test
|
@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const createLibp2p = require('./libp2p-bundle')
|
const createLibp2p = require('./libp2p')
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const createLibp2p = require('./libp2p-bundle')
|
const createLibp2p = require('./libp2p')
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
|
61
examples/echo/test.js
Normal file
61
examples/echo/test.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const execa = require('execa')
|
||||||
|
const pDefer = require('p-defer')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
|
||||||
|
function startProcess(name) {
|
||||||
|
return execa('node', [path.join(__dirname, name)], {
|
||||||
|
cwd: path.resolve(__dirname),
|
||||||
|
all: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function test () {
|
||||||
|
const listenerReady = pDefer()
|
||||||
|
const messageReceived = pDefer()
|
||||||
|
|
||||||
|
// Step 1 process
|
||||||
|
process.stdout.write('node listener.js\n')
|
||||||
|
const listenerProc = startProcess('src/listener.js')
|
||||||
|
listenerProc.all.on('data', async (data) => {
|
||||||
|
process.stdout.write(data)
|
||||||
|
const s = uint8ArrayToString(data)
|
||||||
|
|
||||||
|
if (s.includes('Listener ready, listening on:')) {
|
||||||
|
listenerReady.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await listenerReady.promise
|
||||||
|
process.stdout.write('==================================================================\n')
|
||||||
|
|
||||||
|
// Step 2 process
|
||||||
|
process.stdout.write('node dialer.js\n')
|
||||||
|
const dialerProc = startProcess('src/dialer.js')
|
||||||
|
dialerProc.all.on('data', async (data) => {
|
||||||
|
process.stdout.write(data)
|
||||||
|
const s = uint8ArrayToString(data)
|
||||||
|
|
||||||
|
if (s.includes('received echo:')) {
|
||||||
|
messageReceived.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await messageReceived.promise
|
||||||
|
process.stdout.write('echo message received\n')
|
||||||
|
|
||||||
|
listenerProc.kill()
|
||||||
|
dialerProc.kill()
|
||||||
|
await Promise.all([
|
||||||
|
listenerProc,
|
||||||
|
dialerProc
|
||||||
|
]).catch((err) => {
|
||||||
|
if (err.signal !== 'SIGTERM') {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = test
|
@ -8,6 +8,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"build": "parcel build index.html",
|
||||||
"start": "parcel index.html"
|
"start": "parcel index.html"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
52
examples/libp2p-in-the-browser/test.js
Normal file
52
examples/libp2p-in-the-browser/test.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const execa = require('execa')
|
||||||
|
const { chromium } = require('playwright');
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
let url = ''
|
||||||
|
const proc = execa('parcel', ['./index.html'], {
|
||||||
|
preferLocal: true,
|
||||||
|
localDir: __dirname,
|
||||||
|
cwd: __dirname,
|
||||||
|
all: true
|
||||||
|
})
|
||||||
|
|
||||||
|
proc.all.on('data', async (chunk) => {
|
||||||
|
/**@type {string} */
|
||||||
|
const out = chunk.toString()
|
||||||
|
|
||||||
|
if (out.includes('Server running at')) {
|
||||||
|
url = out.replace('Server running at ', '')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out.includes('✨ Built in ')) {
|
||||||
|
try {
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.goto(url);
|
||||||
|
await page.waitForFunction(selector => document.querySelector(selector).innerText === 'libp2p started!', '#status')
|
||||||
|
await page.waitForFunction(
|
||||||
|
selector => {
|
||||||
|
const text = document.querySelector(selector).innerText
|
||||||
|
return text.includes('libp2p id is') &&
|
||||||
|
text.includes('Found peer') &&
|
||||||
|
text.includes('Connected to')
|
||||||
|
},
|
||||||
|
'#output',
|
||||||
|
{ timeout: 5000 }
|
||||||
|
)
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
} finally {
|
||||||
|
proc.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = run
|
@ -12,5 +12,8 @@
|
|||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"p-defer": "^3.0.0",
|
"p-defer": "^3.0.0",
|
||||||
"which": "^2.0.1"
|
"which": "^2.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"playwright": "^1.7.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
examples/pnet/test.js
Normal file
30
examples/pnet/test.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const execa = require('execa')
|
||||||
|
const pDefer = require('p-defer')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
|
||||||
|
async function test () {
|
||||||
|
const messageReceived = pDefer()
|
||||||
|
process.stdout.write('index.js\n')
|
||||||
|
|
||||||
|
const proc = execa('node', [path.join(__dirname, 'index.js')], {
|
||||||
|
cwd: path.resolve(__dirname),
|
||||||
|
all: true
|
||||||
|
})
|
||||||
|
|
||||||
|
proc.all.on('data', async (data) => {
|
||||||
|
process.stdout.write(data)
|
||||||
|
|
||||||
|
const s = uint8ArrayToString(data)
|
||||||
|
if (s.includes('This message is sent on a private network')) {
|
||||||
|
messageReceived.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await messageReceived.promise
|
||||||
|
proc.kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = test
|
@ -22,7 +22,6 @@ async function testExample (dir) {
|
|||||||
await installDeps(dir)
|
await installDeps(dir)
|
||||||
await build(dir)
|
await build(dir)
|
||||||
await runTest(dir)
|
await runTest(dir)
|
||||||
// TODO: add browser test setup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function installDeps (dir) {
|
async function installDeps (dir) {
|
||||||
@ -89,7 +88,7 @@ async function runTest (dir) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const runTest = require(testFile)
|
const test = require(testFile)
|
||||||
|
|
||||||
await runTest()
|
await test()
|
||||||
}
|
}
|
70
package.json
70
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "libp2p",
|
"name": "libp2p",
|
||||||
"version": "0.30.1",
|
"version": "0.30.3",
|
||||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
@ -52,35 +52,41 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
"aggregate-error": "^3.0.1",
|
"aggregate-error": "^3.1.0",
|
||||||
"any-signal": "^1.1.0",
|
"any-signal": "^2.1.1",
|
||||||
"bignumber.js": "^9.0.0",
|
"bignumber.js": "^9.0.1",
|
||||||
"cids": "^1.0.0",
|
"cids": "^1.1.5",
|
||||||
"class-is": "^1.1.0",
|
"class-is": "^1.1.0",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.3.1",
|
||||||
"err-code": "^2.0.0",
|
"err-code": "^2.0.0",
|
||||||
"events": "^3.1.0",
|
"events": "^3.2.0",
|
||||||
"hashlru": "^2.3.0",
|
"hashlru": "^2.3.0",
|
||||||
"interface-datastore": "^2.0.0",
|
"interface-datastore": "^3.0.3",
|
||||||
"ipfs-utils": "^5.0.1",
|
"ipfs-utils": "^6.0.0",
|
||||||
"it-all": "^1.0.1",
|
"it-all": "^1.0.4",
|
||||||
"it-buffer": "^0.1.2",
|
"it-buffer": "^0.1.2",
|
||||||
"it-handshake": "^1.0.1",
|
"it-drain": "^1.0.3",
|
||||||
"it-length-prefixed": "^3.0.1",
|
"it-filter": "^1.0.1",
|
||||||
|
"it-first": "^1.0.4",
|
||||||
|
"it-handshake": "^1.0.2",
|
||||||
|
"it-length-prefixed": "^3.1.0",
|
||||||
|
"it-map": "^1.0.4",
|
||||||
|
"it-merge": "1.0.0",
|
||||||
"it-pipe": "^1.1.0",
|
"it-pipe": "^1.1.0",
|
||||||
"it-protocol-buffers": "^0.2.0",
|
"it-protocol-buffers": "^0.2.0",
|
||||||
"libp2p-crypto": "^0.18.0",
|
"it-take": "1.0.0",
|
||||||
|
"libp2p-crypto": "^0.19.0",
|
||||||
"libp2p-interfaces": "^0.8.1",
|
"libp2p-interfaces": "^0.8.1",
|
||||||
"libp2p-utils": "^0.2.2",
|
"libp2p-utils": "^0.2.2",
|
||||||
"mafmt": "^8.0.0",
|
"mafmt": "^8.0.0",
|
||||||
"merge-options": "^2.0.0",
|
"merge-options": "^3.0.4",
|
||||||
"moving-average": "^1.0.0",
|
"moving-average": "^1.0.0",
|
||||||
"multiaddr": "^8.1.0",
|
"multiaddr": "^8.1.0",
|
||||||
"multicodec": "^2.0.0",
|
"multicodec": "^2.1.0",
|
||||||
"multihashing-async": "^2.0.1",
|
"multihashing-async": "^2.0.1",
|
||||||
"multistream-select": "^1.0.0",
|
"multistream-select": "^1.0.0",
|
||||||
"mutable-proxy": "^1.0.0",
|
"mutable-proxy": "^1.0.0",
|
||||||
"node-forge": "^0.9.1",
|
"node-forge": "^0.10.0",
|
||||||
"p-any": "^3.0.0",
|
"p-any": "^3.0.0",
|
||||||
"p-fifo": "^1.0.0",
|
"p-fifo": "^1.0.0",
|
||||||
"p-settle": "^4.0.1",
|
"p-settle": "^4.0.1",
|
||||||
@ -91,7 +97,7 @@
|
|||||||
"set-delayed-interval": "^1.0.0",
|
"set-delayed-interval": "^1.0.0",
|
||||||
"streaming-iterables": "^5.0.2",
|
"streaming-iterables": "^5.0.2",
|
||||||
"timeout-abort-controller": "^1.1.1",
|
"timeout-abort-controller": "^1.1.1",
|
||||||
"varint": "^5.0.0",
|
"varint": "^6.0.0",
|
||||||
"xsalsa20": "^1.0.2"
|
"xsalsa20": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -100,20 +106,20 @@
|
|||||||
"aegir": "^29.2.0",
|
"aegir": "^29.2.0",
|
||||||
"chai-bytes": "^0.1.2",
|
"chai-bytes": "^0.1.2",
|
||||||
"chai-string": "^1.5.0",
|
"chai-string": "^1.5.0",
|
||||||
"delay": "^4.3.0",
|
"delay": "^4.4.0",
|
||||||
"interop-libp2p": "^0.3.0",
|
"interop-libp2p": "^0.3.0",
|
||||||
"into-stream": "^6.0.0",
|
"into-stream": "^6.0.0",
|
||||||
"ipfs-http-client": "^47.0.1",
|
"ipfs-http-client": "^48.2.2",
|
||||||
"it-concat": "^1.0.0",
|
"it-concat": "^1.0.0",
|
||||||
"it-pair": "^1.0.0",
|
"it-pair": "^1.0.0",
|
||||||
"it-pushable": "^1.4.0",
|
"it-pushable": "^1.4.0",
|
||||||
"libp2p": ".",
|
"libp2p": ".",
|
||||||
"libp2p-bootstrap": "^0.12.0",
|
"libp2p-bootstrap": "^0.12.0",
|
||||||
"libp2p-delegated-content-routing": "^0.8.0",
|
"libp2p-delegated-content-routing": "^0.9.0",
|
||||||
"libp2p-delegated-peer-routing": "^0.8.0",
|
"libp2p-delegated-peer-routing": "^0.8.0",
|
||||||
"libp2p-floodsub": "^0.24.0",
|
"libp2p-floodsub": "^0.24.0",
|
||||||
"libp2p-gossipsub": "^0.7.0",
|
"libp2p-gossipsub": "^0.8.0",
|
||||||
"libp2p-kad-dht": "^0.20.0",
|
"libp2p-kad-dht": "^0.20.5",
|
||||||
"libp2p-mdns": "^0.15.0",
|
"libp2p-mdns": "^0.15.0",
|
||||||
"libp2p-mplex": "^0.10.1",
|
"libp2p-mplex": "^0.10.1",
|
||||||
"libp2p-noise": "^2.0.0",
|
"libp2p-noise": "^2.0.0",
|
||||||
@ -125,11 +131,11 @@
|
|||||||
"nock": "^13.0.3",
|
"nock": "^13.0.3",
|
||||||
"p-defer": "^3.0.0",
|
"p-defer": "^3.0.0",
|
||||||
"p-times": "^3.0.0",
|
"p-times": "^3.0.0",
|
||||||
"p-wait-for": "^3.1.0",
|
"p-wait-for": "^3.2.0",
|
||||||
"promisify-es6": "^1.0.3",
|
"promisify-es6": "^1.0.3",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"sinon": "^9.0.2",
|
"sinon": "^9.2.4",
|
||||||
"uint8arrays": "^1.1.0"
|
"uint8arrays": "^2.0.5"
|
||||||
},
|
},
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"David Dias <daviddias.p@gmail.com>",
|
"David Dias <daviddias.p@gmail.com>",
|
||||||
@ -150,11 +156,11 @@
|
|||||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||||
"Ryan Bell <ryan@piing.net>",
|
"Ryan Bell <ryan@piing.net>",
|
||||||
|
"Samlior <samlior@foxmail.com>",
|
||||||
"Thomas Eizinger <thomas@eizinger.io>",
|
"Thomas Eizinger <thomas@eizinger.io>",
|
||||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||||
"Didrik Nordström <didrik@betamos.se>",
|
"Didrik Nordström <didrik@betamos.se>",
|
||||||
"Fei Liu <liu.feiwood@gmail.com>",
|
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||||
"Ethan Lam <elmemphis2000@gmail.com>",
|
|
||||||
"Joel Gustafson <joelg@mit.edu>",
|
"Joel Gustafson <joelg@mit.edu>",
|
||||||
"Julien Bouquillon <contact@revolunet.com>",
|
"Julien Bouquillon <contact@revolunet.com>",
|
||||||
"Kevin Kwok <antimatter15@gmail.com>",
|
"Kevin Kwok <antimatter15@gmail.com>",
|
||||||
@ -162,7 +168,7 @@
|
|||||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||||
"Diogo Silva <fsdiogo@gmail.com>",
|
"Diogo Silva <fsdiogo@gmail.com>",
|
||||||
"Samlior <samlior@foxmail.com>",
|
"isan_rivkin <isanrivkin@gmail.com>",
|
||||||
"Smite Chow <xiaopengyou@live.com>",
|
"Smite Chow <xiaopengyou@live.com>",
|
||||||
"Soeren <nikorpoulsen@gmail.com>",
|
"Soeren <nikorpoulsen@gmail.com>",
|
||||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||||
@ -173,13 +179,13 @@
|
|||||||
"robertkiel <robert.kiel@validitylabs.org>",
|
"robertkiel <robert.kiel@validitylabs.org>",
|
||||||
"Cindy Wu <ciindy.wu@gmail.com>",
|
"Cindy Wu <ciindy.wu@gmail.com>",
|
||||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||||
"ebinks <elizabethjbinks@gmail.com>",
|
|
||||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||||
"Francis Gulotta <wizard@roborooter.com>",
|
"Francis Gulotta <wizard@roborooter.com>",
|
||||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
"ebinks <elizabethjbinks@gmail.com>",
|
||||||
"Henrique Dias <hacdias@gmail.com>",
|
"Henrique Dias <hacdias@gmail.com>",
|
||||||
"isan_rivkin <isanrivkin@gmail.com>",
|
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||||
"Irakli Gozalishvili <rfobic@gmail.com>"
|
"Fei Liu <liu.feiwood@gmail.com>",
|
||||||
|
"Ethan Lam <elmemphis2000@gmail.com>"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ const TextEncoder = require('ipfs-utils/src/text-encoder')
|
|||||||
* @returns {Promise<CID>}
|
* @returns {Promise<CID>}
|
||||||
*/
|
*/
|
||||||
module.exports.namespaceToCid = async (namespace) => {
|
module.exports.namespaceToCid = async (namespace) => {
|
||||||
const bytes = new TextEncoder('utf8').encode(namespace)
|
const bytes = new TextEncoder().encode(namespace)
|
||||||
const hash = await multihashing(bytes, 'sha2-256')
|
const hash = await multihashing(bytes, 'sha2-256')
|
||||||
|
|
||||||
return new CID(hash)
|
return new CID(hash)
|
||||||
|
@ -160,7 +160,7 @@ class ConnectionManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await tasks
|
await Promise.all(tasks)
|
||||||
this.connections.clear()
|
this.connections.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
* This code is based on `latency-monitor` (https://github.com/mlucool/latency-monitor) by `mlucool` (https://github.com/mlucool), available under Apache License 2.0 (https://github.com/mlucool/latency-monitor/blob/master/LICENSE)
|
* This code is based on `latency-monitor` (https://github.com/mlucool/latency-monitor) by `mlucool` (https://github.com/mlucool), available under Apache License 2.0 (https://github.com/mlucool/latency-monitor/blob/master/LICENSE)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* global window */
|
|
||||||
const globalThis = require('ipfs-utils/src/globalthis')
|
|
||||||
/** @typedef {import('../types').EventEmitterFactory} Events */
|
/** @typedef {import('../types').EventEmitterFactory} Events */
|
||||||
/** @type Events */
|
/** @type Events */
|
||||||
const EventEmitter = require('events')
|
const EventEmitter = require('events')
|
||||||
@ -74,9 +72,9 @@ class LatencyMonitor extends EventEmitter {
|
|||||||
that.asyncTestFn = asyncTestFn // If there is no asyncFn, we measure latency
|
that.asyncTestFn = asyncTestFn // If there is no asyncFn, we measure latency
|
||||||
|
|
||||||
// If process: use high resolution timer
|
// If process: use high resolution timer
|
||||||
if (globalThis.process && globalThis.process.hrtime) {
|
if (globalThis.process && globalThis.process.hrtime) { // eslint-disable-line no-undef
|
||||||
debug('Using process.hrtime for timing')
|
debug('Using process.hrtime for timing')
|
||||||
that.now = globalThis.process.hrtime
|
that.now = globalThis.process.hrtime // eslint-disable-line no-undef
|
||||||
that.getDeltaMS = (startTime) => {
|
that.getDeltaMS = (startTime) => {
|
||||||
const hrtime = that.now(startTime)
|
const hrtime = that.now(startTime)
|
||||||
return (hrtime[0] * 1000) + (hrtime[1] / 1000000)
|
return (hrtime[0] * 1000) + (hrtime[1] / 1000000)
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const errCode = require('err-code')
|
const errCode = require('err-code')
|
||||||
const { messages, codes } = require('./errors')
|
const { messages, codes } = require('../errors')
|
||||||
|
const {
|
||||||
|
storeAddresses,
|
||||||
|
uniquePeers,
|
||||||
|
requirePeers,
|
||||||
|
maybeLimitSource
|
||||||
|
} = require('./utils')
|
||||||
|
|
||||||
const all = require('it-all')
|
const merge = require('it-merge')
|
||||||
const pAny = require('p-any')
|
const { pipe } = require('it-pipe')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('peer-id')} PeerId
|
* @typedef {import('peer-id')} PeerId
|
||||||
@ -21,22 +27,21 @@ const pAny = require('p-any')
|
|||||||
class ContentRouting {
|
class ContentRouting {
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
* @param {import('./')} libp2p
|
* @param {import('..')} libp2p
|
||||||
*/
|
*/
|
||||||
constructor (libp2p) {
|
constructor (libp2p) {
|
||||||
this.libp2p = libp2p
|
this.libp2p = libp2p
|
||||||
this.routers = libp2p._modules.contentRouting || []
|
this.routers = libp2p._modules.contentRouting || []
|
||||||
this.dht = libp2p._dht
|
this.dht = libp2p._dht
|
||||||
|
|
||||||
// If we have the dht, make it first
|
// If we have the dht, add it to the available content routers
|
||||||
if (this.dht) {
|
if (this.dht) {
|
||||||
this.routers.unshift(this.dht)
|
this.routers.push(this.dht)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over all content routers in series to find providers of the given key.
|
* Iterates over all content routers in parallel to find providers of the given key.
|
||||||
* Once a content router succeeds, iteration will stop.
|
|
||||||
*
|
*
|
||||||
* @param {CID} key - The CID key of the content to find
|
* @param {CID} key - The CID key of the content to find
|
||||||
* @param {object} [options]
|
* @param {object} [options]
|
||||||
@ -44,25 +49,20 @@ class ContentRouting {
|
|||||||
* @param {number} [options.maxNumProviders] - maximum number of providers to find
|
* @param {number} [options.maxNumProviders] - maximum number of providers to find
|
||||||
* @returns {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>}
|
* @returns {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>}
|
||||||
*/
|
*/
|
||||||
async * findProviders (key, options) {
|
async * findProviders (key, options = {}) {
|
||||||
if (!this.routers.length) {
|
if (!this.routers.length) {
|
||||||
throw errCode(new Error('No content this.routers available'), 'NO_ROUTERS_AVAILABLE')
|
throw errCode(new Error('No content this.routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await pAny(
|
yield * pipe(
|
||||||
this.routers.map(async (router) => {
|
merge(
|
||||||
const provs = await all(router.findProviders(key, options))
|
...this.routers.map(router => router.findProviders(key, options))
|
||||||
|
),
|
||||||
if (!provs || !provs.length) {
|
(source) => storeAddresses(source, this.libp2p.peerStore),
|
||||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
(source) => uniquePeers(source),
|
||||||
}
|
(source) => maybeLimitSource(source, options.maxNumProviders),
|
||||||
return provs
|
(source) => requirePeers(source)
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for (const peer of result) {
|
|
||||||
yield peer
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
89
src/content-routing/utils.js
Normal file
89
src/content-routing/utils.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errCode = require('err-code')
|
||||||
|
const filter = require('it-filter')
|
||||||
|
const map = require('it-map')
|
||||||
|
const take = require('it-take')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('peer-id')} PeerId
|
||||||
|
* @typedef {import('multiaddr')} Multiaddr
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the multiaddrs from every peer in the passed peer store
|
||||||
|
*
|
||||||
|
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||||
|
* @param {import('../peer-store')} peerStore
|
||||||
|
*/
|
||||||
|
function storeAddresses (source, peerStore) {
|
||||||
|
return map(source, (peer) => {
|
||||||
|
// ensure we have the addresses for a given peer
|
||||||
|
peerStore.addressBook.add(peer.id, peer.multiaddrs)
|
||||||
|
|
||||||
|
return peer
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter peers by unique peer id
|
||||||
|
*
|
||||||
|
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||||
|
*/
|
||||||
|
function uniquePeers (source) {
|
||||||
|
/** @type Set<string> */
|
||||||
|
const seen = new Set()
|
||||||
|
|
||||||
|
return filter(source, (peer) => {
|
||||||
|
// dedupe by peer id
|
||||||
|
if (seen.has(peer.id.toString())) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.add(peer.id.toString())
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require at least `min` peers to be yielded from `source`
|
||||||
|
*
|
||||||
|
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||||
|
* @param {number} min
|
||||||
|
*/
|
||||||
|
async function * requirePeers (source, min = 1) {
|
||||||
|
let seen = 0
|
||||||
|
|
||||||
|
for await (const peer of source) {
|
||||||
|
seen++
|
||||||
|
|
||||||
|
yield peer
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seen < min) {
|
||||||
|
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `max` is passed, only take that number of peers from the source
|
||||||
|
* otherwise take all the peers
|
||||||
|
*
|
||||||
|
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||||
|
* @param {number} [max]
|
||||||
|
*/
|
||||||
|
function maybeLimitSource (source, max) {
|
||||||
|
if (max) {
|
||||||
|
return take(source, max)
|
||||||
|
}
|
||||||
|
|
||||||
|
return source
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
storeAddresses,
|
||||||
|
uniquePeers,
|
||||||
|
requirePeers,
|
||||||
|
maybeLimitSource
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const errCode = require('err-code')
|
const errCode = require('err-code')
|
||||||
const AbortController = require('abort-controller').default
|
const AbortController = require('abort-controller').default
|
||||||
const anySignal = require('any-signal')
|
const { anySignal } = require('any-signal')
|
||||||
const FIFO = require('p-fifo')
|
const FIFO = require('p-fifo')
|
||||||
const pAny = require('p-any')
|
const pAny = require('p-any')
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class DialRequest {
|
|||||||
let conn
|
let conn
|
||||||
try {
|
try {
|
||||||
const signal = dialAbortControllers[i].signal
|
const signal = dialAbortControllers[i].signal
|
||||||
conn = await this.dialAction(addr, { ...options, signal: anySignal([signal, options.signal]) })
|
conn = await this.dialAction(addr, { ...options, signal: options.signal ? anySignal([signal, options.signal]) : signal })
|
||||||
// Remove the successful AbortController so it is not aborted
|
// Remove the successful AbortController so it is not aborted
|
||||||
dialAbortControllers.splice(i, 1)
|
dialAbortControllers.splice(i, 1)
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -7,7 +7,7 @@ const log = Object.assign(debug('libp2p:dialer'), {
|
|||||||
const errCode = require('err-code')
|
const errCode = require('err-code')
|
||||||
const multiaddr = require('multiaddr')
|
const multiaddr = require('multiaddr')
|
||||||
const TimeoutController = require('timeout-abort-controller')
|
const TimeoutController = require('timeout-abort-controller')
|
||||||
const anySignal = require('any-signal')
|
const { anySignal } = require('any-signal')
|
||||||
|
|
||||||
const DialRequest = require('./dial-request')
|
const DialRequest = require('./dial-request')
|
||||||
const { publicAddressesFirst } = require('libp2p-utils/src/address-sort')
|
const { publicAddressesFirst } = require('libp2p-utils/src/address-sort')
|
||||||
|
@ -7,7 +7,6 @@ const log = Object.assign(debug('libp2p'), {
|
|||||||
/** @typedef {import('./types').EventEmitterFactory} Events */
|
/** @typedef {import('./types').EventEmitterFactory} Events */
|
||||||
/** @type Events */
|
/** @type Events */
|
||||||
const EventEmitter = require('events')
|
const EventEmitter = require('events')
|
||||||
const globalThis = require('ipfs-utils/src/globalthis')
|
|
||||||
|
|
||||||
const errCode = require('err-code')
|
const errCode = require('err-code')
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
@ -243,7 +242,7 @@ class Libp2p extends EventEmitter {
|
|||||||
// Attach private network protector
|
// Attach private network protector
|
||||||
if (this._modules.connProtector) {
|
if (this._modules.connProtector) {
|
||||||
this.upgrader.protector = this._modules.connProtector
|
this.upgrader.protector = this._modules.connProtector
|
||||||
} else if (globalThis.process !== undefined && globalThis.process.env && globalThis.process.env.LIBP2P_FORCE_PNET) {
|
} else if (globalThis.process !== undefined && globalThis.process.env && globalThis.process.env.LIBP2P_FORCE_PNET) { // eslint-disable-line no-undef
|
||||||
throw new Error('Private network is enforced, but no protector was provided')
|
throw new Error('Private network is enforced, but no protector was provided')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,9 @@
|
|||||||
const sanitize = require('sanitize-filename')
|
const sanitize = require('sanitize-filename')
|
||||||
const mergeOptions = require('merge-options')
|
const mergeOptions = require('merge-options')
|
||||||
const crypto = require('libp2p-crypto')
|
const crypto = require('libp2p-crypto')
|
||||||
const Datastore = require('interface-datastore')
|
const { Key } = require('interface-datastore')
|
||||||
const CMS = require('./cms')
|
const CMS = require('./cms')
|
||||||
const errcode = require('err-code')
|
const errcode = require('err-code')
|
||||||
const { Number } = require('ipfs-utils/src/globalthis')
|
|
||||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
const uint8ArrayFromString = require('uint8arrays/from-string')
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
@ -15,7 +14,7 @@ require('node-forge/lib/sha512')
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('peer-id')} PeerId
|
* @typedef {import('peer-id')} PeerId
|
||||||
* @typedef {import('interface-datastore/src/key')} Key
|
* @typedef {import('interface-datastore/src/types').Datastore} Datastore
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const keyPrefix = '/pkcs8/'
|
const keyPrefix = '/pkcs8/'
|
||||||
@ -72,7 +71,7 @@ async function throwDelayed (err) {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function DsName (name) {
|
function DsName (name) {
|
||||||
return new Datastore.Key(keyPrefix + name)
|
return new Key(keyPrefix + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,7 +82,7 @@ function DsName (name) {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function DsInfoName (name) {
|
function DsInfoName (name) {
|
||||||
return new Datastore.Key(infoPrefix + name)
|
return new Key(infoPrefix + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,16 +5,24 @@ const log = Object.assign(debug('libp2p:peer-routing'), {
|
|||||||
error: debug('libp2p:peer-routing:err')
|
error: debug('libp2p:peer-routing:err')
|
||||||
})
|
})
|
||||||
const errCode = require('err-code')
|
const errCode = require('err-code')
|
||||||
|
const {
|
||||||
|
storeAddresses,
|
||||||
|
uniquePeers,
|
||||||
|
requirePeers
|
||||||
|
} = require('./content-routing/utils')
|
||||||
|
|
||||||
const all = require('it-all')
|
const merge = require('it-merge')
|
||||||
const pAny = require('p-any')
|
const { pipe } = require('it-pipe')
|
||||||
|
const first = require('it-first')
|
||||||
|
const drain = require('it-drain')
|
||||||
|
const filter = require('it-filter')
|
||||||
const {
|
const {
|
||||||
setDelayedInterval,
|
setDelayedInterval,
|
||||||
clearDelayedInterval
|
clearDelayedInterval
|
||||||
} = require('set-delayed-interval')
|
} = require('set-delayed-interval')
|
||||||
|
const PeerId = require('peer-id')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('peer-id')} PeerId
|
|
||||||
* @typedef {import('multiaddr')} Multiaddr
|
* @typedef {import('multiaddr')} Multiaddr
|
||||||
*/
|
*/
|
||||||
class PeerRouting {
|
class PeerRouting {
|
||||||
@ -27,9 +35,9 @@ class PeerRouting {
|
|||||||
this._peerStore = libp2p.peerStore
|
this._peerStore = libp2p.peerStore
|
||||||
this._routers = libp2p._modules.peerRouting || []
|
this._routers = libp2p._modules.peerRouting || []
|
||||||
|
|
||||||
// If we have the dht, make it first
|
// If we have the dht, add it to the available peer routers
|
||||||
if (libp2p._dht) {
|
if (libp2p._dht) {
|
||||||
this._routers.unshift(libp2p._dht)
|
this._routers.push(libp2p._dht)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._refreshManagerOptions = libp2p._options.peerRouting.refreshManager
|
this._refreshManagerOptions = libp2p._options.peerRouting.refreshManager
|
||||||
@ -55,9 +63,8 @@ class PeerRouting {
|
|||||||
*/
|
*/
|
||||||
async _findClosestPeersTask () {
|
async _findClosestPeersTask () {
|
||||||
try {
|
try {
|
||||||
for await (const { id, multiaddrs } of this.getClosestPeers(this._peerId.id)) {
|
// nb getClosestPeers adds the addresses to the address book
|
||||||
this._peerStore.addressBook.add(id, multiaddrs)
|
await drain(this.getClosestPeers(this._peerId.id))
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error(err)
|
log.error(err)
|
||||||
}
|
}
|
||||||
@ -71,7 +78,7 @@ class PeerRouting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over all peer routers in series to find the given peer.
|
* Iterates over all peer routers in parallel to find the given peer.
|
||||||
*
|
*
|
||||||
* @param {PeerId} id - The id of the peer to find
|
* @param {PeerId} id - The id of the peer to find
|
||||||
* @param {object} [options]
|
* @param {object} [options]
|
||||||
@ -83,16 +90,20 @@ class PeerRouting {
|
|||||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||||
}
|
}
|
||||||
|
|
||||||
return pAny(this._routers.map(async (router) => {
|
const output = await pipe(
|
||||||
const result = await router.findPeer(id, options)
|
merge(
|
||||||
|
...this._routers.map(router => [router.findPeer(id, options)])
|
||||||
|
),
|
||||||
|
(source) => filter(source, Boolean),
|
||||||
|
(source) => storeAddresses(source, this._peerStore),
|
||||||
|
(source) => first(source)
|
||||||
|
)
|
||||||
|
|
||||||
// If we don't have a result, we need to provide an error to keep trying
|
if (output) {
|
||||||
if (!result || Object.keys(result).length === 0) {
|
return output
|
||||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,20 +119,14 @@ class PeerRouting {
|
|||||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await pAny(
|
yield * pipe(
|
||||||
this._routers.map(async (router) => {
|
merge(
|
||||||
const peers = await all(router.getClosestPeers(key, options))
|
...this._routers.map(router => router.getClosestPeers(key, options))
|
||||||
|
),
|
||||||
if (!peers || !peers.length) {
|
(source) => storeAddresses(source, this._peerStore),
|
||||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
(source) => uniquePeers(source),
|
||||||
}
|
(source) => requirePeers(source)
|
||||||
return peers
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for (const peer of result) {
|
|
||||||
yield peer
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +63,10 @@ module.exports.decodeV1PSK = (pskBuffer) => {
|
|||||||
const metadata = uint8ArrayToString(pskBuffer).split(/(?:\r\n|\r|\n)/g)
|
const metadata = uint8ArrayToString(pskBuffer).split(/(?:\r\n|\r|\n)/g)
|
||||||
const pskTag = metadata.shift()
|
const pskTag = metadata.shift()
|
||||||
const codec = metadata.shift()
|
const codec = metadata.shift()
|
||||||
const psk = uint8ArrayFromString(metadata.shift(), 'base16')
|
const pskString = metadata.shift()
|
||||||
|
const psk = pskString && uint8ArrayFromString(pskString, 'base16')
|
||||||
|
|
||||||
if (psk.byteLength !== KEY_LENGTH) {
|
if (!psk || psk.byteLength !== KEY_LENGTH) {
|
||||||
throw new Error(Errors.INVALID_PSK)
|
throw new Error(Errors.INVALID_PSK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
const { expect } = require('aegir/utils/chai')
|
const { expect } = require('aegir/utils/chai')
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
|
const { CLOSED } = require('libp2p-interfaces/src/connection/status')
|
||||||
|
|
||||||
const delay = require('delay')
|
const delay = require('delay')
|
||||||
const pWaitFor = require('p-wait-for')
|
const pWaitFor = require('p-wait-for')
|
||||||
@ -268,5 +269,40 @@ describe('libp2p.connections', () => {
|
|||||||
|
|
||||||
await libp2p.stop()
|
await libp2p.stop()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should be closed status once immediately stopping', async () => {
|
||||||
|
const [libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/15003/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const [remoteLibp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[1],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/15004/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||||
|
await libp2p.dial(remoteLibp2p.peerId)
|
||||||
|
|
||||||
|
const totalConns = Array.from(libp2p.connections.values())
|
||||||
|
expect(totalConns.length).to.eql(1)
|
||||||
|
const conns = totalConns[0]
|
||||||
|
expect(conns.length).to.eql(1)
|
||||||
|
const conn = conns[0]
|
||||||
|
|
||||||
|
await libp2p.stop()
|
||||||
|
expect(conn.stat.status).to.eql(CLOSED)
|
||||||
|
|
||||||
|
await remoteLibp2p.stop()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -12,6 +12,8 @@ const CID = require('cids')
|
|||||||
const ipfsHttpClient = require('ipfs-http-client')
|
const ipfsHttpClient = require('ipfs-http-client')
|
||||||
const DelegatedContentRouter = require('libp2p-delegated-content-routing')
|
const DelegatedContentRouter = require('libp2p-delegated-content-routing')
|
||||||
const multiaddr = require('multiaddr')
|
const multiaddr = require('multiaddr')
|
||||||
|
const drain = require('it-drain')
|
||||||
|
const all = require('it-all')
|
||||||
|
|
||||||
const peerUtils = require('../utils/creators/peer')
|
const peerUtils = require('../utils/creators/peer')
|
||||||
const { baseOptions, routingOptions } = require('./utils')
|
const { baseOptions, routingOptions } = require('./utils')
|
||||||
@ -78,10 +80,14 @@ describe('content-routing', () => {
|
|||||||
|
|
||||||
it('should use the nodes dht to find providers', async () => {
|
it('should use the nodes dht to find providers', async () => {
|
||||||
const deferred = pDefer()
|
const deferred = pDefer()
|
||||||
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
|
||||||
sinon.stub(nodes[0]._dht, 'findProviders').callsFake(function * () {
|
sinon.stub(nodes[0]._dht, 'findProviders').callsFake(function * () {
|
||||||
deferred.resolve()
|
deferred.resolve()
|
||||||
yield
|
yield {
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await nodes[0].contentRouting.findProviders().next()
|
await nodes[0].contentRouting.findProviders().next()
|
||||||
@ -138,10 +144,14 @@ describe('content-routing', () => {
|
|||||||
|
|
||||||
it('should use the delegate router to find providers', async () => {
|
it('should use the delegate router to find providers', async () => {
|
||||||
const deferred = pDefer()
|
const deferred = pDefer()
|
||||||
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
|
||||||
sinon.stub(delegate, 'findProviders').callsFake(function * () {
|
sinon.stub(delegate, 'findProviders').callsFake(function * () {
|
||||||
deferred.resolve()
|
deferred.resolve()
|
||||||
yield
|
yield {
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await node.contentRouting.findProviders().next()
|
await node.contentRouting.findProviders().next()
|
||||||
@ -151,25 +161,36 @@ describe('content-routing', () => {
|
|||||||
|
|
||||||
it('should be able to register as a provider', async () => {
|
it('should be able to register as a provider', async () => {
|
||||||
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||||
const mockApi = nock('http://0.0.0.0:60197')
|
const provider = 'QmZNgCqZCvTsi3B4Vt7gsSqpkqDpE7M2Y9TDmEhbDb4ceF'
|
||||||
// mock the refs call
|
|
||||||
.post('/api/v0/refs')
|
const mockBlockApi = nock('http://0.0.0.0:60197')
|
||||||
|
// mock the block/stat call
|
||||||
|
.post('/api/v0/block/stat')
|
||||||
.query(true)
|
.query(true)
|
||||||
.reply(200, null, [
|
.reply(200, '{"Key":"QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB","Size":"2169"}', [
|
||||||
|
'Content-Type', 'application/json',
|
||||||
|
'X-Chunked-Output', '1'
|
||||||
|
])
|
||||||
|
const mockDhtApi = nock('http://0.0.0.0:60197')
|
||||||
|
// mock the dht/provide call
|
||||||
|
.post('/api/v0/dht/provide')
|
||||||
|
.query(true)
|
||||||
|
.reply(200, `{"Extra":"","ID":"QmWKqWXCtRXEeCQTo3FoZ7g4AfnGiauYYiczvNxFCHicbB","Responses":[{"Addrs":["/ip4/0.0.0.0/tcp/0"],"ID":"${provider}"}],"Type":4}\n`, [
|
||||||
'Content-Type', 'application/json',
|
'Content-Type', 'application/json',
|
||||||
'X-Chunked-Output', '1'
|
'X-Chunked-Output', '1'
|
||||||
])
|
])
|
||||||
|
|
||||||
await node.contentRouting.provide(cid)
|
await node.contentRouting.provide(cid)
|
||||||
|
|
||||||
expect(mockApi.isDone()).to.equal(true)
|
expect(mockBlockApi.isDone()).to.equal(true)
|
||||||
|
expect(mockDhtApi.isDone()).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle errors when registering as a provider', async () => {
|
it('should handle errors when registering as a provider', async () => {
|
||||||
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||||
const mockApi = nock('http://0.0.0.0:60197')
|
const mockApi = nock('http://0.0.0.0:60197')
|
||||||
// mock the refs call
|
// mock the block/stat call
|
||||||
.post('/api/v0/refs')
|
.post('/api/v0/block/stat')
|
||||||
.query(true)
|
.query(true)
|
||||||
.reply(502, 'Bad Gateway', ['Content-Type', 'application/json'])
|
.reply(502, 'Bad Gateway', ['Content-Type', 'application/json'])
|
||||||
|
|
||||||
@ -251,6 +272,110 @@ describe('content-routing', () => {
|
|||||||
|
|
||||||
afterEach(() => node.stop())
|
afterEach(() => node.stop())
|
||||||
|
|
||||||
|
it('should store the multiaddrs of a peer', async () => {
|
||||||
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const result = {
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/123.123.123.123/tcp/49320')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'findProviders').callsFake(function * () {})
|
||||||
|
sinon.stub(delegate, 'findProviders').callsFake(function * () {
|
||||||
|
yield result
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(node.peerStore.addressBook.get(providerPeerId)).to.not.be.ok()
|
||||||
|
|
||||||
|
await drain(node.contentRouting.findProviders('a cid'))
|
||||||
|
|
||||||
|
expect(node.peerStore.addressBook.get(providerPeerId)).to.deep.include({
|
||||||
|
isCertified: false,
|
||||||
|
multiaddr: result.multiaddrs[0]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not wait for routing findProviders to finish before returning results', async () => {
|
||||||
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const result = {
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/123.123.123.123/tcp/49320')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'findProviders').callsFake(async function * () { // eslint-disable-line require-yield
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
sinon.stub(delegate, 'findProviders').callsFake(async function * () {
|
||||||
|
yield result
|
||||||
|
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
for await (const provider of node.contentRouting.findProviders('a cid')) {
|
||||||
|
expect(provider.id).to.deep.equal(providerPeerId)
|
||||||
|
defer.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should dedupe results', async () => {
|
||||||
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const result = {
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/123.123.123.123/tcp/49320')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'findProviders').callsFake(async function * () {
|
||||||
|
yield result
|
||||||
|
})
|
||||||
|
sinon.stub(delegate, 'findProviders').callsFake(async function * () {
|
||||||
|
yield result
|
||||||
|
})
|
||||||
|
|
||||||
|
const results = await all(node.contentRouting.findProviders('a cid'))
|
||||||
|
|
||||||
|
expect(results).to.be.an('array').with.lengthOf(1).that.deep.equals([result])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should combine multiaddrs when different addresses are returned by different content routers', async () => {
|
||||||
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const result1 = {
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/123.123.123.123/tcp/49320')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const result2 = {
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/213.213.213.213/tcp/2344')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'findProviders').callsFake(async function * () {
|
||||||
|
yield result1
|
||||||
|
})
|
||||||
|
sinon.stub(delegate, 'findProviders').callsFake(async function * () {
|
||||||
|
yield result2
|
||||||
|
})
|
||||||
|
|
||||||
|
await drain(node.contentRouting.findProviders('a cid'))
|
||||||
|
|
||||||
|
expect(node.peerStore.addressBook.get(providerPeerId)).to.deep.include({
|
||||||
|
isCertified: false,
|
||||||
|
multiaddr: result1.multiaddrs[0]
|
||||||
|
}).and.to.deep.include({
|
||||||
|
isCertified: false,
|
||||||
|
multiaddr: result2.multiaddrs[0]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should use both the dht and delegate router to provide', async () => {
|
it('should use both the dht and delegate router to provide', async () => {
|
||||||
const dhtDeferred = pDefer()
|
const dhtDeferred = pDefer()
|
||||||
const delegatedDeferred = pDefer()
|
const delegatedDeferred = pDefer()
|
||||||
@ -271,15 +396,18 @@ describe('content-routing', () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should only use the dht if it finds providers', async () => {
|
it('should use the dht if the delegate fails to find providers', async () => {
|
||||||
const results = [true]
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = [{
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}]
|
||||||
|
|
||||||
sinon.stub(node._dht, 'findProviders').callsFake(function * () {
|
sinon.stub(node._dht, 'findProviders').callsFake(function * () {
|
||||||
yield results[0]
|
yield results[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
sinon.stub(delegate, 'findProviders').callsFake(function * () { // eslint-disable-line require-yield
|
sinon.stub(delegate, 'findProviders').callsFake(function * () { // eslint-disable-line require-yield
|
||||||
throw new Error('the delegate should not have been called')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const providers = []
|
const providers = []
|
||||||
@ -292,7 +420,11 @@ describe('content-routing', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should use the delegate if the dht fails to find providers', async () => {
|
it('should use the delegate if the dht fails to find providers', async () => {
|
||||||
const results = [true]
|
const [providerPeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = [{
|
||||||
|
id: providerPeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}]
|
||||||
|
|
||||||
sinon.stub(node._dht, 'findProviders').callsFake(function * () {})
|
sinon.stub(node._dht, 'findProviders').callsFake(function * () {})
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ const delay = require('delay')
|
|||||||
const pDefer = require('p-defer')
|
const pDefer = require('p-defer')
|
||||||
const pWaitFor = require('p-wait-for')
|
const pWaitFor = require('p-wait-for')
|
||||||
const mergeOptions = require('merge-options')
|
const mergeOptions = require('merge-options')
|
||||||
|
const drain = require('it-drain')
|
||||||
|
const all = require('it-all')
|
||||||
|
|
||||||
const ipfsHttpClient = require('ipfs-http-client')
|
const ipfsHttpClient = require('ipfs-http-client')
|
||||||
const DelegatedPeerRouter = require('libp2p-delegated-peer-routing')
|
const DelegatedPeerRouter = require('libp2p-delegated-peer-routing')
|
||||||
@ -82,10 +84,14 @@ describe('peer-routing', () => {
|
|||||||
|
|
||||||
it('should use the nodes dht to get the closest peers', async () => {
|
it('should use the nodes dht to get the closest peers', async () => {
|
||||||
const deferred = pDefer()
|
const deferred = pDefer()
|
||||||
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
|
||||||
sinon.stub(nodes[0]._dht, 'getClosestPeers').callsFake(function * () {
|
sinon.stub(nodes[0]._dht, 'getClosestPeers').callsFake(function * () {
|
||||||
deferred.resolve()
|
deferred.resolve()
|
||||||
yield
|
yield {
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await nodes[0].peerRouting.getClosestPeers().next()
|
await nodes[0].peerRouting.getClosestPeers().next()
|
||||||
@ -128,10 +134,14 @@ describe('peer-routing', () => {
|
|||||||
|
|
||||||
it('should use the delegate router to find peers', async () => {
|
it('should use the delegate router to find peers', async () => {
|
||||||
const deferred = pDefer()
|
const deferred = pDefer()
|
||||||
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
|
||||||
sinon.stub(delegate, 'findPeer').callsFake(() => {
|
sinon.stub(delegate, 'findPeer').callsFake(() => {
|
||||||
deferred.resolve()
|
deferred.resolve()
|
||||||
return 'fake peer-id'
|
return {
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await node.peerRouting.findPeer()
|
await node.peerRouting.findPeer()
|
||||||
@ -140,10 +150,14 @@ describe('peer-routing', () => {
|
|||||||
|
|
||||||
it('should use the delegate router to get the closest peers', async () => {
|
it('should use the delegate router to get the closest peers', async () => {
|
||||||
const deferred = pDefer()
|
const deferred = pDefer()
|
||||||
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
|
||||||
sinon.stub(delegate, 'getClosestPeers').callsFake(function * () {
|
sinon.stub(delegate, 'getClosestPeers').callsFake(function * () {
|
||||||
deferred.resolve()
|
deferred.resolve()
|
||||||
yield
|
yield {
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await node.peerRouting.getClosestPeers().next()
|
await node.peerRouting.getClosestPeers().next()
|
||||||
@ -152,7 +166,7 @@ describe('peer-routing', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to find a peer', async () => {
|
it('should be able to find a peer', async () => {
|
||||||
const peerKey = 'QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL'
|
const peerKey = PeerId.createFromB58String('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
|
||||||
const mockApi = nock('http://0.0.0.0:60197')
|
const mockApi = nock('http://0.0.0.0:60197')
|
||||||
.post('/api/v0/dht/findpeer')
|
.post('/api/v0/dht/findpeer')
|
||||||
.query(true)
|
.query(true)
|
||||||
@ -277,55 +291,93 @@ describe('peer-routing', () => {
|
|||||||
|
|
||||||
afterEach(() => node.stop())
|
afterEach(() => node.stop())
|
||||||
|
|
||||||
it('should only use the dht if it finds the peer', async () => {
|
|
||||||
const dhtDeferred = pDefer()
|
|
||||||
|
|
||||||
sinon.stub(node._dht, 'findPeer').callsFake(() => {
|
|
||||||
dhtDeferred.resolve()
|
|
||||||
return { id: node.peerId }
|
|
||||||
})
|
|
||||||
sinon.stub(delegate, 'findPeer').callsFake(() => {
|
|
||||||
throw new Error('the delegate should not have been called')
|
|
||||||
})
|
|
||||||
|
|
||||||
await node.peerRouting.findPeer('a peer id')
|
|
||||||
await dhtDeferred.promise
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should use the delegate if the dht fails to find the peer', async () => {
|
it('should use the delegate if the dht fails to find the peer', async () => {
|
||||||
const results = [true]
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = {
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}
|
||||||
|
|
||||||
sinon.stub(node._dht, 'findPeer').callsFake(() => {})
|
sinon.stub(node._dht, 'findPeer').callsFake(() => {})
|
||||||
sinon.stub(delegate, 'findPeer').callsFake(() => {
|
sinon.stub(delegate, 'findPeer').callsFake(() => {
|
||||||
return results
|
return results
|
||||||
})
|
})
|
||||||
|
|
||||||
const peer = await node.peerRouting.findPeer('a peer id')
|
const peer = await node.peerRouting.findPeer(remotePeerId)
|
||||||
expect(peer).to.eql(results)
|
expect(peer).to.eql(results)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should only use the dht if it gets the closest peers', async () => {
|
it('should not wait for the dht to return if the delegate does first', async () => {
|
||||||
const results = [true]
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = {
|
||||||
sinon.stub(node._dht, 'getClosestPeers').callsFake(function * () {
|
id: remotePeerId,
|
||||||
yield results[0]
|
multiaddrs: []
|
||||||
})
|
|
||||||
|
|
||||||
sinon.stub(delegate, 'getClosestPeers').callsFake(function * () { // eslint-disable-line require-yield
|
|
||||||
throw new Error('the delegate should not have been called')
|
|
||||||
})
|
|
||||||
|
|
||||||
const closest = []
|
|
||||||
for await (const peer of node.peerRouting.getClosestPeers('a cid')) {
|
|
||||||
closest.push(peer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(closest).to.have.length.above(0)
|
const defer = pDefer()
|
||||||
expect(closest).to.eql(results)
|
|
||||||
|
sinon.stub(node._dht, 'findPeer').callsFake(async () => {
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
sinon.stub(delegate, 'findPeer').callsFake(() => {
|
||||||
|
return results
|
||||||
|
})
|
||||||
|
|
||||||
|
const peer = await node.peerRouting.findPeer(remotePeerId)
|
||||||
|
expect(peer).to.eql(results)
|
||||||
|
|
||||||
|
defer.resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not wait for the delegate to return if the dht does first', async () => {
|
||||||
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = {
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'findPeer').callsFake(() => {
|
||||||
|
return results
|
||||||
|
})
|
||||||
|
sinon.stub(delegate, 'findPeer').callsFake(async () => {
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
const peer = await node.peerRouting.findPeer(remotePeerId)
|
||||||
|
expect(peer).to.eql(results)
|
||||||
|
|
||||||
|
defer.resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should store the addresses of the found peer', async () => {
|
||||||
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = {
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/123.123.123.123/tcp/38982')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const spy = sinon.spy(node.peerStore.addressBook, 'add')
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'findPeer').callsFake(() => {
|
||||||
|
return results
|
||||||
|
})
|
||||||
|
sinon.stub(delegate, 'findPeer').callsFake(() => {})
|
||||||
|
|
||||||
|
await node.peerRouting.findPeer(remotePeerId)
|
||||||
|
|
||||||
|
expect(spy.calledWith(results.id, results.multiaddrs)).to.be.true()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should use the delegate if the dht fails to get the closest peer', async () => {
|
it('should use the delegate if the dht fails to get the closest peer', async () => {
|
||||||
const results = [true]
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = [{
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: []
|
||||||
|
}]
|
||||||
|
|
||||||
sinon.stub(node._dht, 'getClosestPeers').callsFake(function * () { })
|
sinon.stub(node._dht, 'getClosestPeers').callsFake(function * () { })
|
||||||
|
|
||||||
@ -333,14 +385,55 @@ describe('peer-routing', () => {
|
|||||||
yield results[0]
|
yield results[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
const closest = []
|
const closest = await all(node.peerRouting.getClosestPeers('a cid'))
|
||||||
for await (const peer of node.peerRouting.getClosestPeers('a cid')) {
|
|
||||||
closest.push(peer)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(closest).to.have.length.above(0)
|
expect(closest).to.have.length.above(0)
|
||||||
expect(closest).to.eql(results)
|
expect(closest).to.eql(results)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should store the addresses of the closest peer', async () => {
|
||||||
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const result = {
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/123.123.123.123/tcp/38982')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const spy = sinon.spy(node.peerStore.addressBook, 'add')
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'getClosestPeers').callsFake(function * () { })
|
||||||
|
|
||||||
|
sinon.stub(delegate, 'getClosestPeers').callsFake(function * () {
|
||||||
|
yield result
|
||||||
|
})
|
||||||
|
|
||||||
|
await drain(node.peerRouting.getClosestPeers('a cid'))
|
||||||
|
|
||||||
|
expect(spy.calledWith(result.id, result.multiaddrs)).to.be.true()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should dedupe closest peers', async () => {
|
||||||
|
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||||
|
const results = [{
|
||||||
|
id: remotePeerId,
|
||||||
|
multiaddrs: [
|
||||||
|
multiaddr('/ip4/123.123.123.123/tcp/38982')
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
|
||||||
|
sinon.stub(node._dht, 'getClosestPeers').callsFake(function * () {
|
||||||
|
yield * results
|
||||||
|
})
|
||||||
|
|
||||||
|
sinon.stub(delegate, 'getClosestPeers').callsFake(function * () {
|
||||||
|
yield * results
|
||||||
|
})
|
||||||
|
|
||||||
|
const peers = await all(node.peerRouting.getClosestPeers('a cid'))
|
||||||
|
|
||||||
|
expect(peers).to.be.an('array').with.a.lengthOf(1).that.deep.equals(results)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('peer routing refresh manager service', () => {
|
describe('peer routing refresh manager service', () => {
|
||||||
|
Reference in New Issue
Block a user