-
Notifications
You must be signed in to change notification settings - Fork 15
Feat/circuit relay #6
Changes from 33 commits
81b1e99
7013f88
65295bf
4052ffa
e444539
21eaeac
6cc1628
4b8907b
d40a5bf
9243b65
7a62388
c61c5fd
90b7320
e4e1790
46f172f
98a7d04
e9e8f73
655be31
9f91929
4dd9b5f
b124d28
d504b65
e938f61
d02d608
0af7ac5
645bf5f
08d168c
14059ed
4f7451f
35253ac
1a947d3
3bb68f9
7157e5d
6ff891e
e5f617a
59e6a85
e2a007f
c29f3a9
9e9c38c
d5dd246
4b3ee06
efcb48e
51a7118
06a4b9f
1c261a7
650876d
26daf07
2a686e4
b0e669a
9a2efbc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,9 +17,9 @@ | |
}, | ||
"scripts": { | ||
"lint": "aegir lint", | ||
"test": "aegir test -t node -t browser --no-cors", | ||
"test:node": "aegir test -t node -f test/node.js", | ||
"test:browser": "aegir test -t browser --no-cors -f test/browser.js" | ||
"test": "cross-env IPFS_REUSEPORT=false aegir test -t node -t browser --no-cors", | ||
"test:node": "cross-env IPFS_REUSEPORT=false aegir test -t node -f test/node.js", | ||
"test:browser": "cross-env IPFS_REUSEPORT=false aegir test -t browser --no-cors -f test/browser.js" | ||
}, | ||
"pre-commit": [ | ||
"lint" | ||
|
@@ -45,6 +45,7 @@ | |
"buffer-loader": "0.0.1", | ||
"chai": "^4.1.2", | ||
"cids": "^0.5.2", | ||
"cross-env": "^5.1.3", | ||
"detect-node": "^2.0.3", | ||
"dir-compare": "^1.4.0", | ||
"dirty-chai": "^2.0.1", | ||
|
@@ -53,10 +54,12 @@ | |
"form-data": "^2.3.1", | ||
"go-ipfs-dep": "^0.4.13", | ||
"hat": "0.0.3", | ||
"ipfs": "~0.27.7", | ||
"ipfs": "^0.28.0", | ||
"ipfs-api": "^18.1.1", | ||
"ipfsd-ctl": "~0.29.1", | ||
"left-pad": "^1.2.0", | ||
"libp2p-websocket-star": "^0.7.2", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you need to import the transport? |
||
"libp2p-websocket-star-rendezvous": "^0.2.2", | ||
"lodash": "^4.17.4", | ||
"mocha": "^4.0.1", | ||
"ncp": "^2.0.0", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,290 @@ | ||
/* eslint max-nested-callbacks: ["error", 8] */ | ||
/* eslint-env mocha */ | ||
'use strict' | ||
|
||
const chai = require('chai') | ||
const dirtyChai = require('dirty-chai') | ||
const expect = chai.expect | ||
chai.use(dirtyChai) | ||
|
||
const parallel = require('async/parallel') | ||
const series = require('async/series') | ||
|
||
const isNode = require('detect-node') | ||
|
||
const utils = require('./utils/circuit') | ||
|
||
const proc = utils.setUpProcNode | ||
const js = utils.setUpJsNode | ||
const go = utils.setUpGoNode | ||
|
||
const ws = utils.wsAddr | ||
const star = utils.wsStarAddr | ||
const circuit = utils.circuitAddr | ||
|
||
const send = utils.send | ||
|
||
const base = '/ip4/127.0.0.1/tcp/0' | ||
|
||
const connect = (nodeA, nodeB, relay, timeout, callback) => { | ||
if (typeof timeout === 'function') { | ||
callback = timeout | ||
timeout = 1000 | ||
} | ||
|
||
series([ | ||
(cb) => nodeA.ipfsd.api.swarm.connect(ws(relay.addrs), cb), | ||
(cb) => setTimeout(cb, timeout), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why Timeout? Swarm should just return after the connect is done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've tried without the timeouts but it fails in a lot of cases. I believe it is related to WS somehow - but just a hunch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thought about it some more and remembered the main reason this is there. Upon establishing a muxed connection, circuit will try to send the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That doesn't make sense. If there is any action caused and needed by swarm.connect, it won't finish (aka call the callback) until it's finished. Adding a timeout after the fact means that that swarm.connect is returning before the connection was finished, which is not the expected behavior. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the action doesn't happen as part of the swarm connect. It uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BTW - adding that to the flow would not be an issue at all, we already have a method that does the discovery ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not that. I'm saying that PeerInfo -- https://github.com/libp2p/js-peer-info/blob/master/src/index.js -- should contain the information about the Protocol we know are supported and also if the node can be a relay, so that you can scan through your Peers set and see if the nodes you are connected are indeed relay nodes. This would remove any race condition. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The
AFAIU, this would imply having a flag in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Better track this in a separate issue and add a TODO on the timeout that points to it :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, agree! We desperately need a sane service discovery mechanism... |
||
(cb) => nodeB.ipfsd.api.swarm.connect(ws(relay.addrs), cb), | ||
(cb) => setTimeout(cb, timeout), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
(cb) => nodeA.ipfsd.api.swarm.connect(circuit(nodeB.addrs), cb) | ||
], callback) | ||
} | ||
|
||
const timeout = 80 * 1000 | ||
const baseTest = { | ||
connect, | ||
send, | ||
timeout | ||
} | ||
|
||
let tests = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why let and not const? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. gets merged with the browser tests. I'll separated into two different files as you suggested bellow. |
||
'go-go-go': { | ||
create: (callback) => series([ | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb) | ||
], callback) | ||
}, | ||
'js-go-go': { | ||
create: (callback) => series([ | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb) | ||
], callback) | ||
}, | ||
'go-go-js': { | ||
create: (callback) => series([ | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback) | ||
}, | ||
'js-go-js': { | ||
create: (callback) => series([ | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback) | ||
}, | ||
'go-js-go': { | ||
create: (callback) => series([ | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb) | ||
], callback) | ||
}, | ||
'js-js-go': { | ||
create: (callback) => series([ | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb) | ||
], callback) | ||
}, | ||
'go-js-js': { | ||
create: (callback) => series([ | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback) | ||
}, | ||
'js-js-js': { | ||
create: (callback) => series([ | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback) | ||
} | ||
} | ||
|
||
const connWithTimeout = (timeout) => { | ||
return (nodeA, nodeB, relay, callback) => { | ||
connect(nodeA, nodeB, relay, timeout, callback) | ||
} | ||
} | ||
const browser = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have the browser ones in a separate file? This file is huge. |
||
'browser-go-js': { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keeping track of these mutations for a human is not super easy. Maybe we could generate the combinations given a list of implementations to test? For example, passing Might be a bit out-of-scope for this PR though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I like pre-generating as well. It gets a little tricky because of how nodes connect - |
||
create: | ||
(callback) => series([ | ||
(cb) => proc([], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do browser connects need a special timeout? |
||
}, | ||
'browser-go-go': { | ||
create: (callback) => series([ | ||
(cb) => proc([], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
}, | ||
'browser-js-js': { | ||
create: (callback) => series([ | ||
(cb) => proc([], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
}, | ||
'browser-js-go': { | ||
create: (callback) => series([ | ||
(cb) => proc([], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
}, | ||
'js-go-browser': { | ||
create: (callback) => series([ | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => proc([], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
}, | ||
'go-go-browser': { | ||
create: (callback) => series([ | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => proc([], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
}, | ||
'js-js-browser': { | ||
create: (callback) => series([ | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => proc([], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
}, | ||
'go-js-browser': { | ||
create: (callback) => series([ | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => proc([], cb) | ||
], callback), | ||
connect: connWithTimeout(1500) | ||
}, | ||
'go-browser-browser': { | ||
create: (callback) => series([ | ||
(cb) => go([`${base}/ws`], cb), | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb), | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb) | ||
], callback), | ||
connect: (nodeA, nodeB, relay, callback) => { | ||
series([ | ||
(cb) => relay.ipfsd.api.swarm.connect(ws(nodeA.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
(cb) => relay.ipfsd.api.swarm.connect(star(nodeB.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, there shouldn't be a need for timeouts here. |
||
(cb) => nodeA.ipfsd.api.swarm.connect(circuit(nodeB.addrs), cb) | ||
], callback) | ||
}, | ||
timeout: 100 * 1000, | ||
skip: () => true | ||
}, | ||
'js-browser-browser': { | ||
create: (callback) => series([ | ||
(cb) => js([`${base}/ws`], cb), | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb), | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb) | ||
], callback), | ||
connect: (nodeA, nodeB, relay, callback) => { | ||
series([ | ||
(cb) => relay.ipfsd.api.swarm.connect(ws(nodeA.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
(cb) => relay.ipfsd.api.swarm.connect(star(nodeB.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
(cb) => nodeA.ipfsd.api.swarm.connect(circuit(nodeB.addrs), cb) | ||
], callback) | ||
}, | ||
timeout: 100 * 1000 | ||
}, | ||
'browser-browser-go': { | ||
create: (callback) => series([ | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb), | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb), | ||
(cb) => go([`${base}/ws`], cb) | ||
], callback), | ||
connect: (nodeA, nodeB, relay, callback) => { | ||
series([ | ||
(cb) => relay.ipfsd.api.swarm.connect(star(nodeA.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
(cb) => relay.ipfsd.api.swarm.connect(ws(nodeB.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
(cb) => nodeA.ipfsd.api.swarm.connect(circuit(nodeB.addrs), cb) | ||
], callback) | ||
}, | ||
timeout: 100 * 1000, | ||
skip: () => true | ||
}, | ||
'browser-browser-js': { | ||
create: (callback) => series([ | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb), | ||
(cb) => proc([`/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star`], cb), | ||
(cb) => js([`${base}/ws`], cb) | ||
], callback), | ||
connect: (nodeA, nodeB, relay, callback) => { | ||
series([ | ||
(cb) => relay.ipfsd.api.swarm.connect(star(nodeA.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
(cb) => relay.ipfsd.api.swarm.connect(ws(nodeB.addrs), cb), | ||
(cb) => setTimeout(cb, 2000), | ||
(cb) => nodeA.ipfsd.api.swarm.connect(circuit(nodeB.addrs), cb) | ||
], callback) | ||
} | ||
} | ||
} | ||
|
||
describe('circuit', () => { | ||
if (!isNode) { | ||
tests = Object.assign([], tests, browser) | ||
} | ||
|
||
Object.keys(tests).forEach((test) => { | ||
let nodes | ||
let nodeA | ||
let relay | ||
let nodeB | ||
|
||
tests[test] = Object.assign({}, baseTest, tests[test]) | ||
const dsc = tests[test].skip && tests[test].skip() ? describe.skip : describe | ||
dsc(test, function () { | ||
this.timeout(tests[test].timeout) | ||
|
||
before((done) => { | ||
tests[test].create((err, _nodes) => { | ||
expect(err).to.not.exist() | ||
nodes = _nodes.map((n) => n.ipfsd) | ||
nodeA = _nodes[0] | ||
relay = _nodes[1] | ||
nodeB = _nodes[2] | ||
done() | ||
}) | ||
}) | ||
|
||
after((done) => parallel(nodes.map((ipfsd) => (cb) => ipfsd.stop(cb)), done)) | ||
|
||
it('connect', (done) => { | ||
tests[test].connect(nodeA, nodeB, relay, done) | ||
}) | ||
|
||
it('send', (done) => { | ||
tests[test].send(nodeA.ipfsd.api, nodeB.ipfsd.api, done) | ||
}) | ||
}) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep using the
~
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
npm install annoyingly changes the
^
and~
:(There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, you just need to check on submitting the PR. Reviewing one's PRs can go a long way.