mirror of
https://github.com/vacp2p/nim-libp2p.git
synced 2026-01-09 15:57:56 -05:00
139 lines
4.5 KiB
Nim
139 lines
4.5 KiB
Nim
import std/[os, options, strformat, sequtils]
|
|
import redis
|
|
import chronos, chronicles
|
|
import
|
|
../../libp2p/[
|
|
builders,
|
|
switch,
|
|
multicodec,
|
|
observedaddrmanager,
|
|
services/hpservice,
|
|
services/autorelayservice,
|
|
protocols/connectivity/autonat/client as aclient,
|
|
protocols/connectivity/relay/client as rclient,
|
|
protocols/connectivity/relay/relay,
|
|
protocols/connectivity/autonat/service,
|
|
protocols/ping,
|
|
]
|
|
import ../../tests/[stubs/autonatclientstub, errorhelpers]
|
|
|
|
logScope:
|
|
topics = "hp interop node"
|
|
|
|
proc createSwitch(r: Relay = nil, hpService: Service = nil): Switch =
|
|
let rng = newRng()
|
|
var builder = SwitchBuilder
|
|
.new()
|
|
.withRng(rng)
|
|
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
|
|
.withObservedAddrManager(ObservedAddrManager.new(maxSize = 1, minCount = 1))
|
|
.withTcpTransport({ServerFlags.TcpNoDelay})
|
|
.withYamux()
|
|
.withAutonat()
|
|
.withNoise()
|
|
|
|
if hpService != nil:
|
|
builder = builder.withServices(@[hpService])
|
|
|
|
if r != nil:
|
|
builder = builder.withCircuitRelay(r)
|
|
|
|
let s = builder.build()
|
|
s.mount(Ping.new(rng = rng))
|
|
return s
|
|
|
|
proc main() {.async.} =
|
|
let relayClient = RelayClient.new()
|
|
let autoRelayService = AutoRelayService.new(1, relayClient, nil, newRng())
|
|
let autonatClientStub = AutonatClientStub.new(expectedDials = 1)
|
|
autonatClientStub.answer = NotReachable
|
|
let autonatService = AutonatService.new(autonatClientStub, newRng(), maxQueueSize = 1)
|
|
let hpservice = HPService.new(autonatService, autoRelayService)
|
|
|
|
let
|
|
isListener = getEnv("MODE") == "listen"
|
|
switch = createSwitch(relayClient, hpservice)
|
|
auxSwitch = createSwitch()
|
|
redisClient = open("redis", 6379.Port)
|
|
|
|
debug "Connected to redis"
|
|
|
|
await switch.start()
|
|
await auxSwitch.start()
|
|
|
|
let relayAddr =
|
|
try:
|
|
redisClient.bLPop(@["RELAY_TCP_ADDRESS"], 0)
|
|
except Exception as e:
|
|
raise newException(CatchableError, e.msg)
|
|
|
|
debug "All relay addresses", relayAddr
|
|
|
|
# This is necessary to make the autonat service work. It will ask this peer for our reachability which the autonat
|
|
# client stub will answer NotReachable.
|
|
await switch.connect(auxSwitch.peerInfo.peerId, auxSwitch.peerInfo.addrs)
|
|
|
|
# Wait for autonat to be NotReachable
|
|
while autonatService.networkReachability != NetworkReachability.NotReachable:
|
|
await sleepAsync(100.milliseconds)
|
|
|
|
# This will trigger the autonat relay service to make a reservation.
|
|
let relayMA = MultiAddress.init(relayAddr[1]).tryGet()
|
|
|
|
try:
|
|
debug "Dialing relay...", relayMA
|
|
let relayId = await switch.connect(relayMA).wait(30.seconds)
|
|
debug "Connected to relay", relayId
|
|
except AsyncTimeoutError as e:
|
|
raise newException(CatchableError, "Connection to relay timed out: " & e.msg, e)
|
|
|
|
# Wait for our relay address to be published
|
|
while not switch.peerInfo.addrs.anyIt(it.contains(multiCodec("p2p-circuit")).tryGet()):
|
|
await sleepAsync(100.milliseconds)
|
|
|
|
if isListener:
|
|
let listenerPeerId = switch.peerInfo.peerId
|
|
discard redisClient.rPush("LISTEN_CLIENT_PEER_ID", $listenerPeerId)
|
|
debug "Pushed listener client peer id to redis", listenerPeerId
|
|
|
|
# Nothing to do anymore, wait to be killed
|
|
await sleepAsync(2.minutes)
|
|
else:
|
|
let listenerId =
|
|
try:
|
|
PeerId.init(redisClient.bLPop(@["LISTEN_CLIENT_PEER_ID"], 0)[1]).tryGet()
|
|
except Exception as e:
|
|
raise newException(CatchableError, "Exception init peer: " & e.msg, e)
|
|
|
|
debug "Got listener peer id", listenerId
|
|
let listenerRelayAddr = MultiAddress.init($relayMA & "/p2p-circuit").tryGet()
|
|
|
|
debug "Dialing listener relay address", listenerRelayAddr
|
|
await switch.connect(listenerId, @[listenerRelayAddr])
|
|
|
|
# wait for hole-punching to complete in the background
|
|
await sleepAsync(5000.milliseconds)
|
|
|
|
let conn = switch.connManager.selectMuxer(listenerId).connection
|
|
let channel = await switch.dial(listenerId, @[listenerRelayAddr], PingCodec)
|
|
let delay = await Ping.new().ping(channel)
|
|
await allFuturesThrowing(
|
|
channel.close(), conn.close(), switch.stop(), auxSwitch.stop()
|
|
)
|
|
echo &"""{{"rtt_to_holepunched_peer_millis":{delay.millis}}}"""
|
|
|
|
try:
|
|
proc mainAsync(): Future[string] {.async.} =
|
|
# mainAsync wraps main and returns some value, as otherwise
|
|
# 'waitFor(fut)' has no type (or is ambiguous)
|
|
await main()
|
|
return "done"
|
|
|
|
discard waitFor(mainAsync().wait(4.minutes))
|
|
except AsyncTimeoutError as e:
|
|
error "Program execution timed out", description = e.msg
|
|
quit(-1)
|
|
except CatchableError as e:
|
|
error "Unexpected error", description = e.msg
|
|
quit(-1)
|