refactor: circuit relay to async (#477)

* refactor: add dialing over relay support

* chore: fix lint

* fix: dont clear listeners on close

* fix: if dial errors already have codes, just rethrow them

* fix: clear the registrar when libp2p stops

* fix: improve connection maintenance with circuit

* chore: correct feedback

* test: use chai as promised

* test(fix): reset multiaddrs on dial test
This commit is contained in:
Jacob Heun
2019-11-29 16:41:08 +01:00
parent 18a062ed12
commit f77ce39484
30 changed files with 937 additions and 1169 deletions

View File

@ -1,10 +1,15 @@
'use strict'
const pipe = require('it-pipe')
const { Connection } = require('libp2p-interfaces/src/connection')
const multiaddr = require('multiaddr')
const Muxer = require('libp2p-mplex')
const Multistream = require('multistream-select')
const pair = require('it-pair')
const errCode = require('err-code')
const { codes } = require('../../src/errors')
const mockMultiaddrConnPair = require('./mockMultiaddrConn')
const peerUtils = require('./creators/peer')
module.exports = async (properties = {}) => {
@ -48,3 +53,103 @@ module.exports = async (properties = {}) => {
...properties
})
}
/**
* Creates a full connection pair, without the transport or encryption
*
* @param {object} options
* @param {Multiaddr[]} options.addrs Should contain two addresses for the local and remote peer respectively
* @param {PeerId[]} options.remotePeer Should contain two peer ids, for the local and remote peer respectively
* @param {Map<string, function>} options.protocols The protocols the connections should support
* @returns {{inbound:Connection, outbound:Connection}}
*/
module.exports.pair = function connectionPair ({ addrs, peers, protocols }) {
const [localPeer, remotePeer] = peers
const {
inbound: inboundMaConn,
outbound: outboundMaConn
} = mockMultiaddrConnPair({ addrs, remotePeer })
const inbound = createConnection({
direction: 'inbound',
maConn: inboundMaConn,
protocols,
// Inbound connection peers are reversed
localPeer: remotePeer,
remotePeer: localPeer
})
const outbound = createConnection({
direction: 'outbound',
maConn: outboundMaConn,
protocols,
localPeer,
remotePeer
})
return { inbound, outbound }
}
function createConnection ({
direction,
maConn,
localPeer,
remotePeer,
protocols
}) {
// Create the muxer
const muxer = new Muxer({
// Run anytime a remote stream is created
onStream: async muxedStream => {
const mss = new Multistream.Listener(muxedStream)
try {
const { stream, protocol } = await mss.handle(Array.from(protocols.keys()))
connection.addStream(stream, protocol)
// Need to be able to notify a peer of this this._onStream({ connection, stream, protocol })
const handler = protocols.get(protocol)
handler({ connection, stream, protocol })
} catch (err) {
// Do nothing
}
},
// Run anytime a stream closes
onStreamEnd: muxedStream => {
connection.removeStream(muxedStream.id)
}
})
const newStream = async protocols => {
const muxedStream = muxer.newStream()
const mss = new Multistream.Dialer(muxedStream)
try {
const { stream, protocol } = await mss.select(protocols)
return { stream: { ...muxedStream, ...stream }, protocol }
} catch (err) {
throw errCode(err, codes.ERR_UNSUPPORTED_PROTOCOL)
}
}
// Pipe all data through the muxer
pipe(maConn, muxer, maConn)
maConn.timeline.upgraded = Date.now()
// Create the connection
const connection = new Connection({
localAddr: maConn.localAddr,
remoteAddr: maConn.remoteAddr,
localPeer: localPeer,
remotePeer: remotePeer,
stat: {
direction,
timeline: maConn.timeline,
multiplexer: Muxer.multicodec,
encryption: 'N/A'
},
newStream,
getStreams: () => muxer.streams,
close: err => maConn.close(err)
})
return connection
}