From abc7a446436fa97c9ff25ed690f9cda46c5f38c8 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:19:41 -0400 Subject: [PATCH 01/11] feat: kad-dht --- nim-peer/src/nim_peer.nim | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index 34e16c3e..370e5f65 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -1,8 +1,10 @@ {.push raises: [Exception].} import tables, deques, strutils, os, streams +import std/sets import libp2p, chronos, cligen, chronicles +import libp2p/protocols/kademlia from libp2p/protocols/pubsub/rpc/message import Message from illwave as iw import nil, `[]`, `[]=`, `==`, width, height @@ -17,6 +19,7 @@ const PeerIdFile: string = "local.peerid" MaxKeyLen: int = 4096 ListenPort: int = 9093 + DiscoveryInterval = 10.seconds proc cleanup() {.noconv: (raises: []).} = try: @@ -76,6 +79,52 @@ proc loadOrCreateKey(rng: var HmacDrbgContext): PrivateKey = echo "Could not create new key" quit(1) +proc roomToKadKey(room: string): Key {.raises: [].} = + var roomBytes = newSeq[byte](room.len) + for i, ch in room: + roomBytes[i] = byte(ord(ch)) + MultiHash.digest("sha2-256", roomBytes).tryGet().toKey() + +proc seedKadRoutingTable(kad: KadDHT, switch: Switch) = + var peers: seq[(PeerId, seq[MultiAddress])] + for peerId, addrs in switch.peerStore[AddressBook].book.pairs: + if peerId == switch.peerInfo.peerId or addrs.len == 0: + continue + peers.add((peerId, addrs)) + + if peers.len > 0: + kad.updatePeers(peers) + +proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. + async: (raises: [CancelledError]) +.} = + let roomKey = roomToKadKey(room) + + while true: + seedKadRoutingTable(kad, switch) + + # announce ourselves as a provider for this room and query for other providers + await kad.addProvider(roomKey) + let providers = await kad.getProviders(roomKey) + + for provider in providers.items: + let peerId = PeerId.init(provider.id).valueOr: + continue + if peerId == switch.peerInfo.peerId or switch.isConnected(peerId): + continue + if provider.addrs.len == 0: + continue + + try: + await switch.connect(peerId, provider.addrs) + info "Connected to peer via Kad-DHT", peerId = $peerId + except CancelledError as exc: + raise exc + except DialFailedError as exc: + debug "Failed to connect to discovered peer", peerId = $peerId, description = exc.msg + + await sleepAsync(DiscoveryInterval) + proc start( addrs: Opt[MultiAddress], headless: bool, room: string, port: int ) {.async: (raises: [CancelledError]).} = @@ -131,8 +180,10 @@ proc start( except InitializationError as exc: echo "Could not initialize gossipsub: " & $exc.msg quit(1) + let kad = KadDHT.new(switch) try: + switch.mount(kad) switch.mount(gossip) switch.mount(fileExchange) await switch.start() @@ -153,6 +204,8 @@ proc start( except Exception as exc: error "Connection error", description = exc.msg + asyncSpawn discoverPeersWithKad(switch, kad, room) + # wait so that gossipsub can form mesh await sleepAsync(3.seconds) From 5a07add6e2d54caef994391f7aaecec2f5d54f3e Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:24:34 -0400 Subject: [PATCH 02/11] fix: roomToKadKey --- nim-peer/src/nim_peer.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index 370e5f65..745d65b6 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -79,11 +79,14 @@ proc loadOrCreateKey(rng: var HmacDrbgContext): PrivateKey = echo "Could not create new key" quit(1) -proc roomToKadKey(room: string): Key {.raises: [].} = +proc roomToKadKey(room: string): Opt[Key] {.raises: [].} = var roomBytes = newSeq[byte](room.len) for i, ch in room: roomBytes[i] = byte(ord(ch)) - MultiHash.digest("sha2-256", roomBytes).tryGet().toKey() + let digest = MultiHash.digest("sha2-256", roomBytes).valueOr: + error "Could not derive Kad-DHT key for room", room = room, description = error + return Opt.none(Key) + Opt.some(digest.toKey()) proc seedKadRoutingTable(kad: KadDHT, switch: Switch) = var peers: seq[(PeerId, seq[MultiAddress])] From a573647044cfa909b81835e9b55abdde0a09a797 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:25:32 -0400 Subject: [PATCH 03/11] fix: more fixes --- nim-peer/src/nim_peer.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index 745d65b6..c2a55f94 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -102,13 +102,15 @@ proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. async: (raises: [CancelledError]) .} = let roomKey = roomToKadKey(room) + if roomKey.isNone(): + return while true: seedKadRoutingTable(kad, switch) # announce ourselves as a provider for this room and query for other providers - await kad.addProvider(roomKey) - let providers = await kad.getProviders(roomKey) + await kad.addProvider(roomKey.get()) + let providers = await kad.getProviders(roomKey.get()) for provider in providers.items: let peerId = PeerId.init(provider.id).valueOr: From 7cd8b4bc9f3ed46eedb024cb1f60b35e789ee66a Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:26:00 -0400 Subject: [PATCH 04/11] fix: tag --- nim-peer/src/nim_peer.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index c2a55f94..cb419b4d 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -88,7 +88,7 @@ proc roomToKadKey(room: string): Opt[Key] {.raises: [].} = return Opt.none(Key) Opt.some(digest.toKey()) -proc seedKadRoutingTable(kad: KadDHT, switch: Switch) = +proc seedKadRoutingTable(kad: KadDHT, switch: Switch) {.raises: [].} = var peers: seq[(PeerId, seq[MultiAddress])] for peerId, addrs in switch.peerStore[AddressBook].book.pairs: if peerId == switch.peerInfo.peerId or addrs.len == 0: From 13509f4512586031567663c248de71dc491f7803 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:26:51 -0400 Subject: [PATCH 05/11] more fixes --- nim-peer/src/nim_peer.nim | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index cb419b4d..7e69b1ce 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -110,7 +110,19 @@ proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. # announce ourselves as a provider for this room and query for other providers await kad.addProvider(roomKey.get()) - let providers = await kad.getProviders(roomKey.get()) + var providers: HashSet[Provider] + try: + providers = await kad.getProviders(roomKey.get()) + except CancelledError as exc: + raise exc + except DialFailedError as exc: + debug "Kad provider lookup failed to dial", description = exc.msg + await sleepAsync(DiscoveryInterval) + continue + except LPStreamError as exc: + debug "Kad provider lookup stream error", description = exc.msg + await sleepAsync(DiscoveryInterval) + continue for provider in providers.items: let peerId = PeerId.init(provider.id).valueOr: From 8ede2ac7b8ade2ee0c6c0b46c53fef4805ecc3f1 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:28:45 -0400 Subject: [PATCH 06/11] more fixes --- nim-peer/src/nim_peer.nim | 69 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index 7e69b1ce..e9891b94 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -5,7 +5,7 @@ import std/sets import libp2p, chronos, cligen, chronicles import libp2p/protocols/kademlia -from libp2p/protocols/pubsub/rpc/message import Message +import libp2p/protocols/pubsub/rpc/message as pubsub_message from illwave as iw import nil, `[]`, `[]=`, `==`, width, height from terminal import nil @@ -99,48 +99,47 @@ proc seedKadRoutingTable(kad: KadDHT, switch: Switch) {.raises: [].} = kad.updatePeers(peers) proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. - async: (raises: [CancelledError]) + async: (raises: []) .} = let roomKey = roomToKadKey(room) if roomKey.isNone(): return - while true: - seedKadRoutingTable(kad, switch) - - # announce ourselves as a provider for this room and query for other providers - await kad.addProvider(roomKey.get()) - var providers: HashSet[Provider] - try: - providers = await kad.getProviders(roomKey.get()) - except CancelledError as exc: - raise exc - except DialFailedError as exc: - debug "Kad provider lookup failed to dial", description = exc.msg - await sleepAsync(DiscoveryInterval) - continue - except LPStreamError as exc: - debug "Kad provider lookup stream error", description = exc.msg - await sleepAsync(DiscoveryInterval) - continue + try: + while true: + seedKadRoutingTable(kad, switch) - for provider in providers.items: - let peerId = PeerId.init(provider.id).valueOr: - continue - if peerId == switch.peerInfo.peerId or switch.isConnected(peerId): + # announce ourselves as a provider for this room and query for other providers + await kad.addProvider(roomKey.get()) + var providers: HashSet[Provider] + try: + providers = await kad.getProviders(roomKey.get()) + except DialFailedError as exc: + debug "Kad provider lookup failed to dial", description = exc.msg + await sleepAsync(DiscoveryInterval) continue - if provider.addrs.len == 0: + except LPStreamError as exc: + debug "Kad provider lookup stream error", description = exc.msg + await sleepAsync(DiscoveryInterval) continue - try: - await switch.connect(peerId, provider.addrs) - info "Connected to peer via Kad-DHT", peerId = $peerId - except CancelledError as exc: - raise exc - except DialFailedError as exc: - debug "Failed to connect to discovered peer", peerId = $peerId, description = exc.msg + for provider in providers.items: + let peerId = PeerId.init(provider.id).valueOr: + continue + if peerId == switch.peerInfo.peerId or switch.isConnected(peerId): + continue + if provider.addrs.len == 0: + continue - await sleepAsync(DiscoveryInterval) + try: + await switch.connect(peerId, provider.addrs) + info "Connected to peer via Kad-DHT", peerId = $peerId + except DialFailedError as exc: + debug "Failed to connect to discovered peer", peerId = $peerId, description = exc.msg + + await sleepAsync(DiscoveryInterval) + except CancelledError: + discard proc start( addrs: Opt[MultiAddress], headless: bool, room: string, port: int @@ -230,7 +229,7 @@ proc start( # chat and file handlers actually need to be validators instead of regular handlers # validators allow us to get information about which peer sent a message let onChatMsg = proc( - topic: string, msg: Message + topic: string, msg: pubsub_message.Message ): Future[ValidationResult] {.async, gcsafe.} = let strMsg = cast[string](msg.data) await recvQ.put(shortPeerId(msg.fromPeer) & ": " & strMsg) @@ -243,7 +242,7 @@ proc start( # when a new file is announced, download it let onNewFile = proc( - topic: string, msg: Message + topic: string, msg: pubsub_message.Message ): Future[ValidationResult] {.async, gcsafe.} = let fileId = sanitizeFileId(cast[string](msg.data)) # this will only work if we're connected to `fromPeer` (since we don't have kad-dht) From 4c2ab10c215c1145c417e76e0a9eabd896816d62 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:30:54 -0400 Subject: [PATCH 07/11] more fixes --- nim-peer/src/nim_peer.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index e9891b94..255ea820 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -143,7 +143,7 @@ proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. proc start( addrs: Opt[MultiAddress], headless: bool, room: string, port: int -) {.async: (raises: [CancelledError]).} = +) {.async.} = # Handle Ctrl+C setControlCHook(cleanup) @@ -314,9 +314,9 @@ proc cli(connect = "", room = ChatTopic, port = ListenPort, headless = false) = if connect.len > 0: addrs = Opt.some(MultiAddress.init(connect).get()) try: - waitFor start(addrs, headless, room, port) - except CancelledError: - echo "Operation cancelled" + waitFor noCancel(start(addrs, headless, room, port)) + except CatchableError as exc: + echo "Operation failed: " & exc.msg when isMainModule: dispatch cli, From 64e07a49211e6ca716efb69560bd86caf4ef08cc Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:42:32 -0400 Subject: [PATCH 08/11] add bootstrap nodes --- nim-peer/src/nim_peer.nim | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index 255ea820..df47a387 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -20,6 +20,12 @@ const MaxKeyLen: int = 4096 ListenPort: int = 9093 DiscoveryInterval = 10.seconds + KadBootstrapPeerAddrs = [ + "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", + ] proc cleanup() {.noconv: (raises: []).} = try: @@ -98,6 +104,26 @@ proc seedKadRoutingTable(kad: KadDHT, switch: Switch) {.raises: [].} = if peers.len > 0: kad.updatePeers(peers) +proc kadBootstrapNodes(): seq[(PeerId, seq[MultiAddress])] {.raises: [].} = + const PeerIdTag = "/p2p/" + + for addr in KadBootstrapPeerAddrs: + let multiAddr = MultiAddress.init(addr).valueOr: + error "Invalid Kad bootstrap multiaddr", address = addr, description = error + continue + + let tagPos = addr.rfind(PeerIdTag) + if tagPos < 0: + error "Missing /p2p/ segment in Kad bootstrap multiaddr", address = addr + continue + + let peerIdStr = addr[tagPos + PeerIdTag.len .. ^1] + let peerId = PeerId.init(peerIdStr).valueOr: + error "Invalid Kad bootstrap peer id", address = addr, peerId = peerIdStr, description = error + continue + + result.add((peerId, @[multiAddr])) + proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. async: (raises: []) .} = @@ -196,7 +222,7 @@ proc start( except InitializationError as exc: echo "Could not initialize gossipsub: " & $exc.msg quit(1) - let kad = KadDHT.new(switch) + let kad = KadDHT.new(switch, bootstrapNodes = kadBootstrapNodes()) try: switch.mount(kad) @@ -245,7 +271,7 @@ proc start( topic: string, msg: pubsub_message.Message ): Future[ValidationResult] {.async, gcsafe.} = let fileId = sanitizeFileId(cast[string](msg.data)) - # this will only work if we're connected to `fromPeer` (since we don't have kad-dht) + # File transfer still requires a direct stream to the announcing peer. let conn = await switch.dial(msg.fromPeer, FileExchangeCodec) let filePath = getTempDir() / fileId let fileContents = await fileExchange.requestFile(conn, fileId) From c1390eae5555bbd4d53d2d64da2a5e4fe1c1b1f2 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 6 Mar 2026 09:53:12 -0400 Subject: [PATCH 09/11] add resolver --- nim-peer/src/nim_peer.nim | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index df47a387..9792a97a 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -6,6 +6,7 @@ import std/sets import libp2p, chronos, cligen, chronicles import libp2p/protocols/kademlia import libp2p/protocols/pubsub/rpc/message as pubsub_message +import libp2p/nameresolving/dnsresolver from illwave as iw import nil, `[]`, `[]=`, `==`, width, height from terminal import nil @@ -119,14 +120,15 @@ proc kadBootstrapNodes(): seq[(PeerId, seq[MultiAddress])] {.raises: [].} = let peerIdStr = addr[tagPos + PeerIdTag.len .. ^1] let peerId = PeerId.init(peerIdStr).valueOr: - error "Invalid Kad bootstrap peer id", address = addr, peerId = peerIdStr, description = error + error "Invalid Kad bootstrap peer id", + address = addr, peerId = peerIdStr, description = error continue result.add((peerId, @[multiAddr])) -proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. - async: (raises: []) -.} = +proc discoverPeersWithKad( + switch: Switch, kad: KadDHT, room: string +) {.async: (raises: []).} = let roomKey = roomToKadKey(room) if roomKey.isNone(): return @@ -161,7 +163,8 @@ proc discoverPeersWithKad(switch: Switch, kad: KadDHT, room: string) {. await switch.connect(peerId, provider.addrs) info "Connected to peer via Kad-DHT", peerId = $peerId except DialFailedError as exc: - debug "Failed to connect to discovered peer", peerId = $peerId, description = exc.msg + debug "Failed to connect to discovered peer", + peerId = $peerId, description = exc.msg await sleepAsync(DiscoveryInterval) except CancelledError: @@ -180,24 +183,26 @@ proc start( type WriterStr = LogOutputStr # Early (bootstrap) writer: mirror logs to stdout so nothing is dropped - defaultChroniclesStream.output.writer = - proc (lvl: LogLevel, rec: WriterStr) {.closure, gcsafe, raises: [].} = - let s = cast[string](rec) - try: - for line in s.splitLines(): - stdout.writeLine(line) - stdout.flushFile() - except IOError: - discard - + defaultChroniclesStream.output.writer = proc( + lvl: LogLevel, rec: WriterStr + ) {.closure, gcsafe, raises: [].} = + let s = cast[string](rec) + try: + for line in s.splitLines(): + stdout.writeLine(line) + stdout.flushFile() + except IOError: + discard var rng = newRng() + let nameResolver = DnsResolver.new(@[initTAddress("1.1.1.1:53")]) let switch = try: SwitchBuilder .new() .withRng(rng) + .withNameResolver(nameResolver) .withTcpTransport() .withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/" & $port).tryGet()]) .withYamux() From 2dc7bd00f307ea9cdf2b78c68c4726fb17ab95c7 Mon Sep 17 00:00:00 2001 From: Gabriel Cruz Date: Fri, 6 Mar 2026 13:05:47 -0300 Subject: [PATCH 10/11] fix everything --- nim-peer/src/nim_peer.nim | 72 +++++++++++++++------------------------ nim-peer/src/ui/root.nim | 2 +- nim-peer/src/utils.nim | 4 +-- 3 files changed, 30 insertions(+), 48 deletions(-) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index 9792a97a..c7af7ee4 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -7,6 +7,7 @@ import libp2p, chronos, cligen, chronicles import libp2p/protocols/kademlia import libp2p/protocols/pubsub/rpc/message as pubsub_message import libp2p/nameresolving/dnsresolver +import libp2p/nameresolving/nameresolver from illwave as iw import nil, `[]`, `[]=`, `==`, width, height from terminal import nil @@ -21,12 +22,8 @@ const MaxKeyLen: int = 4096 ListenPort: int = 9093 DiscoveryInterval = 10.seconds - KadBootstrapPeerAddrs = [ - "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", - ] + KadBootstrapPeerAddrs = + ["/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"] proc cleanup() {.noconv: (raises: []).} = try: @@ -95,57 +92,44 @@ proc roomToKadKey(room: string): Opt[Key] {.raises: [].} = return Opt.none(Key) Opt.some(digest.toKey()) -proc seedKadRoutingTable(kad: KadDHT, switch: Switch) {.raises: [].} = - var peers: seq[(PeerId, seq[MultiAddress])] - for peerId, addrs in switch.peerStore[AddressBook].book.pairs: - if peerId == switch.peerInfo.peerId or addrs.len == 0: - continue - peers.add((peerId, addrs)) - - if peers.len > 0: - kad.updatePeers(peers) - -proc kadBootstrapNodes(): seq[(PeerId, seq[MultiAddress])] {.raises: [].} = +proc kadBootstrapNodes( + resolver: DnsResolver +): Future[seq[(PeerId, seq[MultiAddress])]] {.async.} = const PeerIdTag = "/p2p/" for addr in KadBootstrapPeerAddrs: - let multiAddr = MultiAddress.init(addr).valueOr: - error "Invalid Kad bootstrap multiaddr", address = addr, description = error - continue - let tagPos = addr.rfind(PeerIdTag) if tagPos < 0: - error "Missing /p2p/ segment in Kad bootstrap multiaddr", address = addr + error "Missing /p2p/ segment", address = addr continue let peerIdStr = addr[tagPos + PeerIdTag.len .. ^1] let peerId = PeerId.init(peerIdStr).valueOr: - error "Invalid Kad bootstrap peer id", - address = addr, peerId = peerIdStr, description = error + error "Invalid peer id", peerId = peerIdStr + continue + + let baseAddr = addr[0 ..< tagPos] + + let maddr = MultiAddress.init(baseAddr).valueOr: + error "Invalid multiaddr", address = baseAddr continue - result.add((peerId, @[multiAddr])) + result.add((peerId, @[maddr])) proc discoverPeersWithKad( switch: Switch, kad: KadDHT, room: string ) {.async: (raises: []).} = - let roomKey = roomToKadKey(room) - if roomKey.isNone(): + let roomKey = roomToKadKey(room).valueOr: + error "Unable to convert room to kad key" return try: while true: - seedKadRoutingTable(kad, switch) - # announce ourselves as a provider for this room and query for other providers - await kad.addProvider(roomKey.get()) + await kad.addProvider(roomKey) var providers: HashSet[Provider] try: - providers = await kad.getProviders(roomKey.get()) - except DialFailedError as exc: - debug "Kad provider lookup failed to dial", description = exc.msg - await sleepAsync(DiscoveryInterval) - continue + providers = await kad.getProviders(roomKey) except LPStreamError as exc: debug "Kad provider lookup stream error", description = exc.msg await sleepAsync(DiscoveryInterval) @@ -161,7 +145,7 @@ proc discoverPeersWithKad( try: await switch.connect(peerId, provider.addrs) - info "Connected to peer via Kad-DHT", peerId = $peerId + info "Kad Connected to peer via Kad-DHT", peerId = $peerId except DialFailedError as exc: debug "Failed to connect to discovered peer", peerId = $peerId, description = exc.msg @@ -227,7 +211,7 @@ proc start( except InitializationError as exc: echo "Could not initialize gossipsub: " & $exc.msg quit(1) - let kad = KadDHT.new(switch, bootstrapNodes = kadBootstrapNodes()) + let kad = KadDHT.new(switch, bootstrapNodes = await kadBootstrapNodes(nameResolver)) try: switch.mount(kad) @@ -253,9 +237,6 @@ proc start( asyncSpawn discoverPeersWithKad(switch, kad, room) - # wait so that gossipsub can form mesh - await sleepAsync(3.seconds) - # topic handlers # chat and file handlers actually need to be validators instead of regular handlers # validators allow us to get information about which peer sent a message @@ -301,8 +282,8 @@ proc start( gossip.addValidator(room, onChatMsg) # receive files offerings - gossip.subscribe(ChatFileTopic, nil) - gossip.addValidator(ChatFileTopic, onNewFile) + gossip.subscribe(FileChatTopic, nil) + gossip.addValidator(FileChatTopic, onNewFile) # receive newly connected peers through gossipsub gossip.subscribe(PeerDiscoveryTopic, onNewPeer) @@ -322,7 +303,10 @@ proc start( switch.addPeerEventHandler(onPeerLeft, PeerEventKind.Left) # add already connected peers - for peerId in switch.peerStore[AddressBook].book.keys: + for peerId in switch.connectedPeers(Direction.Out): + await peerQ.put((peerId, PeerEventKind.Joined)) + + for peerId in switch.connectedPeers(Direction.In): await peerQ.put((peerId, PeerEventKind.Joined)) if headless: @@ -355,5 +339,3 @@ when isMainModule: "connect": "full multiaddress (with /p2p/ peerId) of the node to connect to", "room": "Room name", "port": "TCP listen port", - "headless": "No UI, can only receive messages", - } diff --git a/nim-peer/src/ui/root.nim b/nim-peer/src/ui/root.nim index 2a21ed68..604a15c5 100644 --- a/nim-peer/src/ui/root.nim +++ b/nim-peer/src/ui/root.nim @@ -130,7 +130,7 @@ proc runUI*( copyFile(path, getTempDir().joinPath(fileId)) # publish /tmp/{filename} try: - discard await gossip.publish(ChatFileTopic, cast[seq[byte]](@(fileId))) + discard await gossip.publish(FileChatTopic, cast[seq[byte]](@(fileId))) systemPanel.push("Offering file " & fileId) except Exception as exc: systemPanel.push("Unable to offer file: " & exc.msg) diff --git a/nim-peer/src/utils.nim b/nim-peer/src/utils.nim index 938c94f3..bf73485e 100644 --- a/nim-peer/src/utils.nim +++ b/nim-peer/src/utils.nim @@ -4,8 +4,8 @@ import libp2p const ChatTopic*: string = "universal-connectivity" - ChatFileTopic*: string = "universal-connectivity-file" - PeerDiscoveryTopic*: string = "universal-connectivity-browser-peer-discovery" + FileChatTopic*: string = ChatTopic & "-file" + PeerDiscoveryTopic*: string = ChatTopic & "-browser-peer-discovery" const SanitizationRules = [ ({'\0' .. '\31'}, ' '), # Control chars -> space From fdbb329dbe125493b968c909a97c1c2e5420a209 Mon Sep 17 00:00:00 2001 From: Gabriel Cruz <8129788+gmelodie@users.noreply.github.com> Date: Sat, 7 Mar 2026 08:20:17 -0300 Subject: [PATCH 11/11] Update nim-peer/src/nim_peer.nim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: richΛrd --- nim-peer/src/nim_peer.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nim-peer/src/nim_peer.nim b/nim-peer/src/nim_peer.nim index c7af7ee4..624390be 100644 --- a/nim-peer/src/nim_peer.nim +++ b/nim-peer/src/nim_peer.nim @@ -339,3 +339,5 @@ when isMainModule: "connect": "full multiaddress (with /p2p/ peerId) of the node to connect to", "room": "Room name", "port": "TCP listen port", + "headless": "No UI, can only receive messages", + }