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

@ -9,5 +9,13 @@ module.exports = {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
},
config: {
relay: {
enabled: true,
hop: {
enabled: false
}
}
}
}

View File

@ -9,5 +9,13 @@ module.exports = {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
},
config: {
relay: {
enabled: true,
hop: {
enabled: false
}
}
}
}

View File

@ -5,7 +5,7 @@ const PeerInfo = require('peer-info')
const Peers = require('../../fixtures/peers')
module.exports.createPeerInfo = async (length) => {
async function createPeerInfo (length) {
const peers = await Promise.all(
Array.from({ length })
.map((_, i) => PeerId.create())
@ -14,11 +14,19 @@ module.exports.createPeerInfo = async (length) => {
return peers.map((peer) => new PeerInfo(peer))
}
module.exports.createPeerInfoFromFixture = async (length) => {
const peers = await Promise.all(
function createPeerIdsFromFixture (length) {
return Promise.all(
Array.from({ length })
.map((_, i) => PeerId.createFromJSON(Peers[i]))
)
}
async function createPeerInfoFromFixture (length) {
const peers = await createPeerIdsFromFixture(length)
return peers.map((peer) => new PeerInfo(peer))
}
module.exports.createPeerInfo = createPeerInfo
module.exports.createPeerIdsFromFixture = createPeerIdsFromFixture
module.exports.createPeerInfoFromFixture = createPeerInfoFromFixture

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
}

View File

@ -13,10 +13,11 @@ const AbortController = require('abort-controller')
*/
module.exports = function mockMultiaddrConnPair ({ addrs, remotePeer }) {
const controller = new AbortController()
const [localAddr, remoteAddr] = addrs
const [inbound, outbound] = duplexPair()
outbound.localAddr = addrs[0]
outbound.remoteAddr = addrs[1].encapsulate(`/p2p/${remotePeer.toB58String()}`)
outbound.localAddr = localAddr
outbound.remoteAddr = remoteAddr.encapsulate(`/p2p/${remotePeer.toB58String()}`)
outbound.timeline = {
open: Date.now()
}
@ -25,8 +26,8 @@ module.exports = function mockMultiaddrConnPair ({ addrs, remotePeer }) {
controller.abort()
}
inbound.localAddr = addrs[1]
inbound.remoteAddr = addrs[0]
inbound.localAddr = remoteAddr
inbound.remoteAddr = localAddr
inbound.timeline = {
open: Date.now()
}