Skip to content

Commit 14fee3b

Browse files
committed
add support for setting protocol handlers with {.raises.} annotation
All of the internal protocol handlers are restricted to `{.raises.}` of `[CancelledError]`. However, the `LPProtoHandler` type is part of the public interface, and example / test code raises more errors than just `[CancelledError]`. The caller is aware of that and `CatchableError` is caught. To allow annotating the internal handlers with the proper `{.raises`.} annotation, support for an extra `LPProtoHandler2` is added. This is backward compatible as the old `LPProtoHandler` is still allowed. Examples still compile fine. There is one test that needs a slight adjustment as it accesses the internal `handler` field directly. That field needs to be renamed so that the `template` is used instead. Eventually, `LPProtoHandler` may be phased out, with appropriate notices to users who define custom handlers and the migration requiring errors to be handled inside the handler instead of raising them. At this time, such a deprecation is not yet applied, especially while the internal logic is still relying on the previous handler flow.
1 parent 08a48fa commit 14fee3b

File tree

3 files changed

+42
-17
lines changed

3 files changed

+42
-17
lines changed

libp2p/multistream.nim

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Nim-LibP2P
2-
# Copyright (c) 2023 Status Research & Development GmbH
2+
# Copyright (c) 2023-2024 Status Research & Development GmbH
33
# Licensed under either of
44
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
55
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
@@ -230,7 +230,7 @@ proc addHandler*(m: MultistreamSelect,
230230

231231
proc addHandler*(m: MultistreamSelect,
232232
codec: string,
233-
handler: LPProtoHandler,
233+
handler: LPProtoHandler|LPProtoHandler2,
234234
matcher: Matcher = nil) =
235235
## helper to allow registering pure handlers
236236
trace "registering proto handler", proto = codec

libp2p/protocols/protocol.nim

+38-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Nim-LibP2P
2-
# Copyright (c) 2023 Status Research & Development GmbH
2+
# Copyright (c) 2023-2024 Status Research & Development GmbH
33
# Licensed under either of
44
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
55
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
@@ -19,14 +19,16 @@ const
1919

2020
type
2121
LPProtoHandler* = proc (
22-
conn: Connection,
23-
proto: string):
24-
Future[void]
25-
{.gcsafe, raises: [].}
22+
conn: Connection,
23+
proto: string): Future[void] {.async.}
24+
25+
LPProtoHandler2* = proc (
26+
conn: Connection,
27+
proto: string): Future[void] {.async: (raises: [CancelledError]).}
2628

2729
LPProtocol* = ref object of RootObj
2830
codecs*: seq[string]
29-
handler*: LPProtoHandler ## this handler gets invoked by the protocol negotiator
31+
handlerImpl: LPProtoHandler ## invoked by the protocol negotiator
3032
started*: bool
3133
maxIncomingStreams: Opt[int]
3234

@@ -41,23 +43,47 @@ proc `maxIncomingStreams=`*(p: LPProtocol, val: int) =
4143
p.maxIncomingStreams = Opt.some(val)
4244

4345
func codec*(p: LPProtocol): string =
44-
assert(p.codecs.len > 0, "Codecs sequence was empty!")
46+
doAssert(p.codecs.len > 0, "Codecs sequence was empty!")
4547
p.codecs[0]
4648

4749
func `codec=`*(p: LPProtocol, codec: string) =
4850
# always insert as first codec
4951
# if we use this abstraction
5052
p.codecs.insert(codec, 0)
5153

54+
template `handler`*(p: LPProtocol): LPProtoHandler =
55+
p.handlerImpl
56+
57+
template `handler`*(
58+
p: LPProtocol, conn: Connection, proto: string): Future[void] =
59+
p.handlerImpl(conn, proto)
60+
61+
func `handler=`*(p: LPProtocol, handler: LPProtoHandler) =
62+
p.handlerImpl = handler
63+
64+
func `handler=`*(p: LPProtocol, handler: LPProtoHandler2) =
65+
proc wrap(conn: Connection, proto: string): Future[void] {.async.} =
66+
await handler(conn, proto)
67+
p.handlerImpl = wrap
68+
5269
proc new*(
53-
T: type LPProtocol,
54-
codecs: seq[string],
55-
handler: LPProtoHandler,
56-
maxIncomingStreams: Opt[int] | int = Opt.none(int)): T =
70+
T: type LPProtocol,
71+
codecs: seq[string],
72+
handler: LPProtoHandler,
73+
maxIncomingStreams: Opt[int] | int = Opt.none(int)): T =
5774
T(
5875
codecs: codecs,
59-
handler: handler,
76+
handlerImpl: handler,
6077
maxIncomingStreams:
6178
when maxIncomingStreams is int: Opt.some(maxIncomingStreams)
6279
else: maxIncomingStreams
6380
)
81+
82+
proc new*(
83+
T: type LPProtocol,
84+
codecs: seq[string],
85+
handler: LPProtoHandler2,
86+
maxIncomingStreams: Opt[int] | int = Opt.none(int)): T =
87+
proc wrap(conn: Connection, proto: string): Future[void] {.async.} =
88+
await handler(conn, proto)
89+
T.new(codec, wrap, maxIncomingStreams)

tests/testtortransport.nim

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{.used.}
22

33
# Nim-Libp2p
4-
# Copyright (c) 2023 Status Research & Development GmbH
4+
# Copyright (c) 2023-2024 Status Research & Development GmbH
55
# Licensed under either of
66
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
77
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
@@ -88,7 +88,6 @@ suite "Tor transport":
8888

8989
# every incoming connections will be in handled in this closure
9090
proc handle(conn: Connection, proto: string) {.async.} =
91-
9291
var resp: array[6, byte]
9392
await conn.readExactly(addr resp, 6)
9493
check string.fromBytes(resp) == "client"
@@ -97,7 +96,7 @@ suite "Tor transport":
9796
# We must close the connections ourselves when we're done with it
9897
await conn.close()
9998

100-
return T(codecs: @[TestCodec], handler: handle)
99+
return T.new(codecs = @[TestCodec], handler = handle)
101100

102101
let rng = newRng()
103102

0 commit comments

Comments
 (0)