connect (socket) { if (!socket || !socket.readable || !socket.writable) { throw new Error('Must specify socket duplex stream') } this.socket = socket socket.once('close', () => this.disconnect(new Error('Socket closed'))) socket.on('error', this._error.bind(this)) var protocolOpts = { magic: this.params.magic, messages: this.params.messages } var decoder = transforms.decode() var protoDecoder = proto.createDecodeStream(protocolOpts) protoDecoder.on('error', this._error.bind(this)) this._decoder = debugStream(debug.rx) socket.pipe(protoDecoder).pipe(decoder).pipe(this._decoder) this._encoder = transforms.encode() var protoEncoder = proto.createEncodeStream(protocolOpts) protoEncoder.on('error', this._error.bind(this)) var encodeDebug = debugStream(debug.tx) this._encoder.pipe(encodeDebug).pipe(protoEncoder).pipe(socket) // timeout if handshake doesn't finish fast enough if (this.handshakeTimeout) { this._handshakeTimeout = setTimeout(() => { this._handshakeTimeout = null this._error(new Error('Peer handshake timed out')) }, this.handshakeTimeout) this.once('ready', () => { clearTimeout(this._handshakeTimeout) this._handshakeTimeout = null }) } // set up ping interval and initial pings this.once('ready', () => { this._pingInterval = setInterval(this.ping.bind(this), this.pingInterval) for (var i = 0; i < INITIAL_PING_N; i++) { setTimeout(this.ping.bind(this), INITIAL_PING_INTERVAL * i) } }) this._registerListeners() this._sendVersion() }
this._connectPeer((err, bridgePeer) => { if (err) { this.emit('connectError', err) return setImmediate(() => this._onConnection(null, client)) } debug(`connected to TCP peer for bridging: ${bridgePeer.remoteAddress}`) var onError = (err) => { if (!err) return client.destroy() bridgePeer.destroy() debug('error', err.message) this.emit('peerError', err, client, bridgePeer) } client.once('error', onError) bridgePeer.once('error', onError) client.once('close', () => bridgePeer.destroy()) bridgePeer.once('close', () => client.destroy()) client.pipe(bridgePeer) var transform = through((message, enc, cb) => { if (message.command !== 'version') return cb(null, message) var version = message.payload if (!version.userAgent.endsWith('/')) version.userAgent += '/' version.userAgent += `webcoin-bridge:${pkg.version} (proxy; ` + `${bridgePeer.remoteAddress}:${bridgePeer.remotePort})/` cb(null, message) bridgePeer.unpipe() bridgePeer.pipe(client) }) var protocolOpts = { magic: this._params.magic, messages: this._params.messages } pump( bridgePeer, proto.createDecodeStream(protocolOpts), transform, proto.createEncodeStream(protocolOpts), client, onError ) this.emit('bridge', client, bridgePeer) })