mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-05-02 05:52:14 +00:00
fix: add timeout for circuit relay (#1294)
Make sure we don't potentially wait forever during incoming circuit relay handshakes. Adds a timeout option to the hop config to control how long we will wait.
This commit is contained in:
parent
0bb1b802c8
commit
ba56c64662
@ -12,6 +12,7 @@ import { peerIdFromBytes } from '@libp2p/peer-id'
|
|||||||
import type { Duplex } from 'it-stream-types'
|
import type { Duplex } from 'it-stream-types'
|
||||||
import type { Circuit } from '../transport.js'
|
import type { Circuit } from '../transport.js'
|
||||||
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
||||||
|
import type { AbortOptions } from '@libp2p/interfaces'
|
||||||
|
|
||||||
const log = logger('libp2p:circuit:hop')
|
const log = logger('libp2p:circuit:hop')
|
||||||
|
|
||||||
@ -118,7 +119,7 @@ export async function handleHop (hopRequest: HopRequest) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HopConfig {
|
export interface HopConfig extends AbortOptions {
|
||||||
connection: Connection
|
connection: Connection
|
||||||
request: CircuitPB
|
request: CircuitPB
|
||||||
}
|
}
|
||||||
@ -130,11 +131,14 @@ export interface HopConfig {
|
|||||||
export async function hop (options: HopConfig): Promise<Duplex<Uint8Array>> {
|
export async function hop (options: HopConfig): Promise<Duplex<Uint8Array>> {
|
||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
request
|
request,
|
||||||
|
signal
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
// Create a new stream to the relay
|
// Create a new stream to the relay
|
||||||
const stream = await connection.newStream(RELAY_CODEC)
|
const stream = await connection.newStream(RELAY_CODEC, {
|
||||||
|
signal
|
||||||
|
})
|
||||||
// Send the HOP request
|
// Send the HOP request
|
||||||
const streamHandler = new StreamHandler({ stream })
|
const streamHandler = new StreamHandler({ stream })
|
||||||
streamHandler.write(request)
|
streamHandler.write(request)
|
||||||
@ -156,7 +160,7 @@ export async function hop (options: HopConfig): Promise<Duplex<Uint8Array>> {
|
|||||||
throw errCode(new Error(`HOP request failed with code "${response.code ?? 'unknown'}"`), Errors.ERR_HOP_REQUEST_FAILED)
|
throw errCode(new Error(`HOP request failed with code "${response.code ?? 'unknown'}"`), Errors.ERR_HOP_REQUEST_FAILED)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CanHopOptions {
|
export interface CanHopOptions extends AbortOptions {
|
||||||
connection: Connection
|
connection: Connection
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,11 +169,14 @@ export interface CanHopOptions {
|
|||||||
*/
|
*/
|
||||||
export async function canHop (options: CanHopOptions) {
|
export async function canHop (options: CanHopOptions) {
|
||||||
const {
|
const {
|
||||||
connection
|
connection,
|
||||||
|
signal
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
// Create a new stream to the relay
|
// Create a new stream to the relay
|
||||||
const stream = await connection.newStream(RELAY_CODEC)
|
const stream = await connection.newStream(RELAY_CODEC, {
|
||||||
|
signal
|
||||||
|
})
|
||||||
|
|
||||||
// Send the HOP request
|
// Send the HOP request
|
||||||
const streamHandler = new StreamHandler({ stream })
|
const streamHandler = new StreamHandler({ stream })
|
||||||
|
@ -5,6 +5,7 @@ import { StreamHandler } from './stream-handler.js'
|
|||||||
import { validateAddrs } from './utils.js'
|
import { validateAddrs } from './utils.js'
|
||||||
import type { Connection } from '@libp2p/interface-connection'
|
import type { Connection } from '@libp2p/interface-connection'
|
||||||
import type { Duplex } from 'it-stream-types'
|
import type { Duplex } from 'it-stream-types'
|
||||||
|
import type { AbortOptions } from '@libp2p/interfaces'
|
||||||
|
|
||||||
const log = logger('libp2p:circuit:stop')
|
const log = logger('libp2p:circuit:stop')
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ export function handleStop (options: HandleStopOptions): Duplex<Uint8Array> | un
|
|||||||
return streamHandler.rest()
|
return streamHandler.rest()
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StopOptions {
|
export interface StopOptions extends AbortOptions {
|
||||||
connection: Connection
|
connection: Connection
|
||||||
request: CircuitPB
|
request: CircuitPB
|
||||||
}
|
}
|
||||||
@ -53,10 +54,13 @@ export interface StopOptions {
|
|||||||
export async function stop (options: StopOptions) {
|
export async function stop (options: StopOptions) {
|
||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
request
|
request,
|
||||||
|
signal
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
const stream = await connection.newStream([RELAY_CODEC])
|
const stream = await connection.newStream(RELAY_CODEC, {
|
||||||
|
signal
|
||||||
|
})
|
||||||
log('starting stop request to %p', connection.remotePeer)
|
log('starting stop request to %p', connection.remotePeer)
|
||||||
const streamHandler = new StreamHandler({ stream })
|
const streamHandler = new StreamHandler({ stream })
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
import type { AddressSorter } from '@libp2p/interface-peer-store'
|
import type { AddressSorter } from '@libp2p/interface-peer-store'
|
||||||
import type { Startable } from '@libp2p/interfaces/startable'
|
import type { Startable } from '@libp2p/interfaces/startable'
|
||||||
import type { Components } from '@libp2p/components'
|
import type { Components } from '@libp2p/components'
|
||||||
|
import type { RelayConfig } from '../index.js'
|
||||||
|
|
||||||
const log = logger('libp2p:relay')
|
const log = logger('libp2p:relay')
|
||||||
|
|
||||||
@ -22,11 +23,6 @@ export interface RelayAdvertiseConfig {
|
|||||||
ttl?: number
|
ttl?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HopConfig {
|
|
||||||
enabled?: boolean
|
|
||||||
active?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AutoRelayConfig {
|
export interface AutoRelayConfig {
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
|
|
||||||
@ -36,13 +32,8 @@ export interface AutoRelayConfig {
|
|||||||
maxListeners: number
|
maxListeners: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RelayInit {
|
export interface RelayInit extends RelayConfig {
|
||||||
addressSorter?: AddressSorter
|
addressSorter?: AddressSorter
|
||||||
maxListeners?: number
|
|
||||||
onError?: (error: Error, msg?: string) => void
|
|
||||||
hop: HopConfig
|
|
||||||
advertise: RelayAdvertiseConfig
|
|
||||||
autoRelay: AutoRelayConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Relay implements Startable {
|
export class Relay implements Startable {
|
||||||
|
@ -17,12 +17,20 @@ import type { AbortOptions } from '@libp2p/interfaces'
|
|||||||
import type { IncomingStreamData } from '@libp2p/interface-registrar'
|
import type { IncomingStreamData } from '@libp2p/interface-registrar'
|
||||||
import type { Listener, Transport, CreateListenerOptions, ConnectionHandler } from '@libp2p/interface-transport'
|
import type { Listener, Transport, CreateListenerOptions, ConnectionHandler } from '@libp2p/interface-transport'
|
||||||
import type { Connection } from '@libp2p/interface-connection'
|
import type { Connection } from '@libp2p/interface-connection'
|
||||||
|
import type { RelayConfig } from '../index.js'
|
||||||
|
import { abortableDuplex } from 'abortable-iterator'
|
||||||
|
import { TimeoutController } from 'timeout-abort-controller'
|
||||||
|
|
||||||
const log = logger('libp2p:circuit')
|
const log = logger('libp2p:circuit')
|
||||||
|
|
||||||
export class Circuit implements Transport, Initializable {
|
export class Circuit implements Transport, Initializable {
|
||||||
private handler?: ConnectionHandler
|
private handler?: ConnectionHandler
|
||||||
private components: Components = new Components()
|
private components: Components = new Components()
|
||||||
|
private readonly _init: RelayConfig
|
||||||
|
|
||||||
|
constructor (init: RelayConfig) {
|
||||||
|
this._init = init
|
||||||
|
}
|
||||||
|
|
||||||
init (components: Components): void {
|
init (components: Components): void {
|
||||||
this.components = components
|
this.components = components
|
||||||
@ -54,49 +62,20 @@ export class Circuit implements Transport, Initializable {
|
|||||||
|
|
||||||
async _onProtocol (data: IncomingStreamData) {
|
async _onProtocol (data: IncomingStreamData) {
|
||||||
const { connection, stream } = data
|
const { connection, stream } = data
|
||||||
const streamHandler = new StreamHandler({ stream })
|
const controller = new TimeoutController(this._init.hop.timeout)
|
||||||
const request = await streamHandler.read()
|
|
||||||
|
|
||||||
if (request == null) {
|
try {
|
||||||
log('request was invalid, could not read from stream')
|
const source = abortableDuplex(stream, controller.signal)
|
||||||
streamHandler.write({
|
const streamHandler = new StreamHandler({
|
||||||
type: CircuitPB.Type.STATUS,
|
stream: {
|
||||||
code: CircuitPB.Status.MALFORMED_MESSAGE
|
...stream,
|
||||||
|
...source
|
||||||
|
}
|
||||||
})
|
})
|
||||||
streamHandler.close()
|
const request = await streamHandler.read()
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let virtualConnection
|
if (request == null) {
|
||||||
|
log('request was invalid, could not read from stream')
|
||||||
switch (request.type) {
|
|
||||||
case CircuitPB.Type.CAN_HOP: {
|
|
||||||
log('received CAN_HOP request from %p', connection.remotePeer)
|
|
||||||
await handleCanHop({ circuit: this, connection, streamHandler })
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case CircuitPB.Type.HOP: {
|
|
||||||
log('received HOP request from %p', connection.remotePeer)
|
|
||||||
virtualConnection = await handleHop({
|
|
||||||
connection,
|
|
||||||
request,
|
|
||||||
streamHandler,
|
|
||||||
circuit: this,
|
|
||||||
connectionManager: this.components.getConnectionManager()
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case CircuitPB.Type.STOP: {
|
|
||||||
log('received STOP request from %p', connection.remotePeer)
|
|
||||||
virtualConnection = await handleStop({
|
|
||||||
connection,
|
|
||||||
request,
|
|
||||||
streamHandler
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
log('Request of type %s not supported', request.type)
|
|
||||||
streamHandler.write({
|
streamHandler.write({
|
||||||
type: CircuitPB.Type.STATUS,
|
type: CircuitPB.Type.STATUS,
|
||||||
code: CircuitPB.Status.MALFORMED_MESSAGE
|
code: CircuitPB.Status.MALFORMED_MESSAGE
|
||||||
@ -104,27 +83,68 @@ export class Circuit implements Transport, Initializable {
|
|||||||
streamHandler.close()
|
streamHandler.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (virtualConnection != null) {
|
let virtualConnection
|
||||||
// @ts-expect-error dst peer will not be undefined
|
|
||||||
const remoteAddr = new Multiaddr(request.dstPeer.addrs[0])
|
|
||||||
// @ts-expect-error dst peer will not be undefined
|
|
||||||
const localAddr = new Multiaddr(request.srcPeer.addrs[0])
|
|
||||||
const maConn = streamToMaConnection({
|
|
||||||
stream: virtualConnection,
|
|
||||||
remoteAddr,
|
|
||||||
localAddr
|
|
||||||
})
|
|
||||||
const type = request.type === CircuitPB.Type.HOP ? 'relay' : 'inbound'
|
|
||||||
log('new %s connection %s', type, maConn.remoteAddr)
|
|
||||||
|
|
||||||
const conn = await this.components.getUpgrader().upgradeInbound(maConn)
|
switch (request.type) {
|
||||||
log('%s connection %s upgraded', type, maConn.remoteAddr)
|
case CircuitPB.Type.CAN_HOP: {
|
||||||
|
log('received CAN_HOP request from %p', connection.remotePeer)
|
||||||
if (this.handler != null) {
|
await handleCanHop({ circuit: this, connection, streamHandler })
|
||||||
this.handler(conn)
|
break
|
||||||
|
}
|
||||||
|
case CircuitPB.Type.HOP: {
|
||||||
|
log('received HOP request from %p', connection.remotePeer)
|
||||||
|
virtualConnection = await handleHop({
|
||||||
|
connection,
|
||||||
|
request,
|
||||||
|
streamHandler,
|
||||||
|
circuit: this,
|
||||||
|
connectionManager: this.components.getConnectionManager()
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case CircuitPB.Type.STOP: {
|
||||||
|
log('received STOP request from %p', connection.remotePeer)
|
||||||
|
virtualConnection = await handleStop({
|
||||||
|
connection,
|
||||||
|
request,
|
||||||
|
streamHandler
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
log('Request of type %s not supported', request.type)
|
||||||
|
streamHandler.write({
|
||||||
|
type: CircuitPB.Type.STATUS,
|
||||||
|
code: CircuitPB.Status.MALFORMED_MESSAGE
|
||||||
|
})
|
||||||
|
streamHandler.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virtualConnection != null) {
|
||||||
|
// @ts-expect-error dst peer will not be undefined
|
||||||
|
const remoteAddr = new Multiaddr(request.dstPeer.addrs[0])
|
||||||
|
// @ts-expect-error dst peer will not be undefined
|
||||||
|
const localAddr = new Multiaddr(request.srcPeer.addrs[0])
|
||||||
|
const maConn = streamToMaConnection({
|
||||||
|
stream: virtualConnection,
|
||||||
|
remoteAddr,
|
||||||
|
localAddr
|
||||||
|
})
|
||||||
|
const type = request.type === CircuitPB.Type.HOP ? 'relay' : 'inbound'
|
||||||
|
log('new %s connection %s', type, maConn.remoteAddr)
|
||||||
|
|
||||||
|
const conn = await this.components.getUpgrader().upgradeInbound(maConn)
|
||||||
|
log('%s connection %s upgraded', type, maConn.remoteAddr)
|
||||||
|
|
||||||
|
if (this.handler != null) {
|
||||||
|
this.handler(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
controller.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +180,7 @@ export class Circuit implements Transport, Initializable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const virtualConnection = await hop({
|
const virtualConnection = await hop({
|
||||||
|
...options,
|
||||||
connection: relayConnection,
|
connection: relayConnection,
|
||||||
request: {
|
request: {
|
||||||
type: CircuitPB.Type.HOP,
|
type: CircuitPB.Type.HOP,
|
||||||
|
@ -69,7 +69,8 @@ const DefaultConfig: Partial<Libp2pInit> = {
|
|||||||
},
|
},
|
||||||
hop: {
|
hop: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
active: false
|
active: false,
|
||||||
|
timeout: 30000
|
||||||
},
|
},
|
||||||
autoRelay: {
|
autoRelay: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
@ -93,6 +93,7 @@ export class FetchService implements Startable {
|
|||||||
const connection = await this.components.getConnectionManager().openConnection(peer, options)
|
const connection = await this.components.getConnectionManager().openConnection(peer, options)
|
||||||
let timeoutController
|
let timeoutController
|
||||||
let signal = options.signal
|
let signal = options.signal
|
||||||
|
let stream: Stream | undefined
|
||||||
|
|
||||||
// create a timeout if no abort signal passed
|
// create a timeout if no abort signal passed
|
||||||
if (signal == null) {
|
if (signal == null) {
|
||||||
@ -100,14 +101,14 @@ export class FetchService implements Startable {
|
|||||||
signal = timeoutController.signal
|
signal = timeoutController.signal
|
||||||
}
|
}
|
||||||
|
|
||||||
const stream = await connection.newStream([this.protocol], {
|
|
||||||
signal
|
|
||||||
})
|
|
||||||
|
|
||||||
// make stream abortable
|
|
||||||
const source = abortableDuplex(stream, signal)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
stream = await connection.newStream([this.protocol], {
|
||||||
|
signal
|
||||||
|
})
|
||||||
|
|
||||||
|
// make stream abortable
|
||||||
|
const source = abortableDuplex(stream, signal)
|
||||||
|
|
||||||
const result = await pipe(
|
const result = await pipe(
|
||||||
[FetchRequest.encode({ identifier: key })],
|
[FetchRequest.encode({ identifier: key })],
|
||||||
lp.encode(),
|
lp.encode(),
|
||||||
@ -146,7 +147,9 @@ export class FetchService implements Startable {
|
|||||||
timeoutController.clear()
|
timeoutController.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.close()
|
if (stream != null) {
|
||||||
|
stream.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +228,7 @@ export class IdentifyService implements Startable {
|
|||||||
async _identify (connection: Connection, options: AbortOptions = {}): Promise<Identify> {
|
async _identify (connection: Connection, options: AbortOptions = {}): Promise<Identify> {
|
||||||
let timeoutController
|
let timeoutController
|
||||||
let signal = options.signal
|
let signal = options.signal
|
||||||
|
let stream: Stream | undefined
|
||||||
|
|
||||||
// create a timeout if no abort signal passed
|
// create a timeout if no abort signal passed
|
||||||
if (signal == null) {
|
if (signal == null) {
|
||||||
@ -235,14 +236,14 @@ export class IdentifyService implements Startable {
|
|||||||
signal = timeoutController.signal
|
signal = timeoutController.signal
|
||||||
}
|
}
|
||||||
|
|
||||||
const stream = await connection.newStream([this.identifyProtocolStr], {
|
|
||||||
signal
|
|
||||||
})
|
|
||||||
|
|
||||||
// make stream abortable
|
|
||||||
const source = abortableDuplex(stream, signal)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
stream = await connection.newStream([this.identifyProtocolStr], {
|
||||||
|
signal
|
||||||
|
})
|
||||||
|
|
||||||
|
// make stream abortable
|
||||||
|
const source = abortableDuplex(stream, signal)
|
||||||
|
|
||||||
const data = await pipe(
|
const data = await pipe(
|
||||||
[],
|
[],
|
||||||
source,
|
source,
|
||||||
@ -266,7 +267,9 @@ export class IdentifyService implements Startable {
|
|||||||
timeoutController.clear()
|
timeoutController.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.close()
|
if (stream != null) {
|
||||||
|
stream.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ export interface MetricsConfig {
|
|||||||
export interface HopConfig {
|
export interface HopConfig {
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
active?: boolean
|
active?: boolean
|
||||||
|
timeout: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RelayConfig {
|
export interface RelayConfig {
|
||||||
|
@ -218,7 +218,7 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|||||||
})))
|
})))
|
||||||
|
|
||||||
if (init.relay.enabled) {
|
if (init.relay.enabled) {
|
||||||
this.components.getTransportManager().add(this.configureComponent(new Circuit()))
|
this.components.getTransportManager().add(this.configureComponent(new Circuit(init.relay)))
|
||||||
|
|
||||||
this.configureComponent(new Relay(this.components, {
|
this.configureComponent(new Relay(this.components, {
|
||||||
addressSorter: init.connectionManager.addressSorter,
|
addressSorter: init.connectionManager.addressSorter,
|
||||||
|
@ -13,6 +13,7 @@ import type { Components } from '@libp2p/components'
|
|||||||
import type { AbortOptions } from '@libp2p/interfaces'
|
import type { AbortOptions } from '@libp2p/interfaces'
|
||||||
import { abortableDuplex } from 'abortable-iterator'
|
import { abortableDuplex } from 'abortable-iterator'
|
||||||
import { TimeoutController } from 'timeout-abort-controller'
|
import { TimeoutController } from 'timeout-abort-controller'
|
||||||
|
import type { Stream } from '@libp2p/interface-connection'
|
||||||
|
|
||||||
const log = logger('libp2p:ping')
|
const log = logger('libp2p:ping')
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ export class PingService implements Startable {
|
|||||||
const connection = await this.components.getConnectionManager().openConnection(peer, options)
|
const connection = await this.components.getConnectionManager().openConnection(peer, options)
|
||||||
let timeoutController
|
let timeoutController
|
||||||
let signal = options.signal
|
let signal = options.signal
|
||||||
|
let stream: Stream | undefined
|
||||||
|
|
||||||
// create a timeout if no abort signal passed
|
// create a timeout if no abort signal passed
|
||||||
if (signal == null) {
|
if (signal == null) {
|
||||||
@ -90,14 +92,14 @@ export class PingService implements Startable {
|
|||||||
signal = timeoutController.signal
|
signal = timeoutController.signal
|
||||||
}
|
}
|
||||||
|
|
||||||
const stream = await connection.newStream([this.protocol], {
|
|
||||||
signal
|
|
||||||
})
|
|
||||||
|
|
||||||
// make stream abortable
|
|
||||||
const source = abortableDuplex(stream, signal)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
stream = await connection.newStream([this.protocol], {
|
||||||
|
signal
|
||||||
|
})
|
||||||
|
|
||||||
|
// make stream abortable
|
||||||
|
const source = abortableDuplex(stream, signal)
|
||||||
|
|
||||||
const result = await pipe(
|
const result = await pipe(
|
||||||
[data],
|
[data],
|
||||||
source,
|
source,
|
||||||
@ -115,7 +117,9 @@ export class PingService implements Startable {
|
|||||||
timeoutController.clear()
|
timeoutController.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.close()
|
if (stream != null) {
|
||||||
|
stream.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import { RELAY_CODEC } from '../../src/circuit/multicodec.js'
|
|||||||
import { StreamHandler } from '../../src/circuit/circuit/stream-handler.js'
|
import { StreamHandler } from '../../src/circuit/circuit/stream-handler.js'
|
||||||
import { CircuitRelay } from '../../src/circuit/pb/index.js'
|
import { CircuitRelay } from '../../src/circuit/pb/index.js'
|
||||||
import { createNodeOptions, createRelayOptions } from './utils.js'
|
import { createNodeOptions, createRelayOptions } from './utils.js'
|
||||||
|
import delay from 'delay'
|
||||||
|
|
||||||
describe('Dialing (via relay, TCP)', () => {
|
describe('Dialing (via relay, TCP)', () => {
|
||||||
let srcLibp2p: Libp2pNode
|
let srcLibp2p: Libp2pNode
|
||||||
@ -170,4 +171,37 @@ describe('Dialing (via relay, TCP)', () => {
|
|||||||
expect(dstToRelayConn).to.have.lengthOf(1)
|
expect(dstToRelayConn).to.have.lengthOf(1)
|
||||||
expect(dstToRelayConn).to.have.nested.property('[0].stat.status', 'OPEN')
|
expect(dstToRelayConn).to.have.nested.property('[0].stat.status', 'OPEN')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should time out when establishing a relay connection', async () => {
|
||||||
|
await relayLibp2p.stop()
|
||||||
|
relayLibp2p = await createNode({
|
||||||
|
config: createRelayOptions({
|
||||||
|
relay: {
|
||||||
|
autoRelay: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
hop: {
|
||||||
|
// very short timeout
|
||||||
|
timeout: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const relayAddr = relayLibp2p.components.getTransportManager().getAddrs()[0]
|
||||||
|
const dialAddr = relayAddr.encapsulate(`/p2p/${relayLibp2p.peerId.toString()}`)
|
||||||
|
|
||||||
|
const connection = await srcLibp2p.dial(dialAddr)
|
||||||
|
const stream = await connection.newStream('/libp2p/circuit/relay/0.1.0')
|
||||||
|
|
||||||
|
await stream.sink(async function * () {
|
||||||
|
// delay for longer than the timeout
|
||||||
|
await delay(1000)
|
||||||
|
yield Uint8Array.from([0])
|
||||||
|
}())
|
||||||
|
|
||||||
|
// because we timed out, the remote should have reset the stream
|
||||||
|
await expect(all(stream.source)).to.eventually.be.rejected
|
||||||
|
.with.property('code', 'ERR_MPLEX_STREAM_RESET')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user