diff --git a/libp2p/multistreamselect.nim b/libp2p/multistreamselect.nim index 4e38d2a..be5f661 100644 --- a/libp2p/multistreamselect.nim +++ b/libp2p/multistreamselect.nim @@ -7,5 +7,70 @@ ## This file may not be copied, modified, or distributed except according to ## those terms. -type MultisteamSelect = ref object of RootObj - +import sequtils +import chronos +import connection, varint, vbuffer + +const Codec* = "/multistream/1.0.0" +const Na = "na\n" +const Ls = "ls\n" + +type + MultisteamSelectException = object of CatchableError + + Handler* = proc (conn: Connection, proto: string): Future[void] + Matcher* = proc (proto: string): bool + + HandlerHolder* = object + proto: string + handler: Handler + match: Matcher + + MultisteamSelect* = ref object of RootObj + handlers*: seq[HandlerHolder] + codec*: seq[byte] + na*: seq[byte] + ls*: seq[byte] + +proc lp*(data: string): seq[byte] = + var buf = initVBuffer(newSeq[byte](256)) + buf.writeSeq(data) + var lpData = newSeq[byte](buf.length) + if buf.readSeq(lpData) < 0: + raise newException(MultisteamSelectException, "Error: failed to lenght prefix") + result = lpData + +proc newMultistream*(): MultisteamSelect = + new result + result.codec = lp(Codec & "\n") + result.na = lp(Na) + result.ls = lp(Ls) + +proc select*(m: MultisteamSelect, conn: Connection, proto: string): Future[bool] {.async.} = + ## select a remote protocol + await conn.write(m.codec) + await conn.write(lp(proto)) # select proto + + let ms = await conn.readLine(0, "\n") + if ms != Codec: + raise newException(MultisteamSelectException, "Error: invalid multistream codec" & $ms) + + let remote = await conn.readLine(0, "\n") + result = remote == proto + +proc ls*(m: MultisteamSelect): seq[string] {.async.} = + ## list all remote protocol strings + discard + +proc handle*(m: MultisteamSelect, conn: Connection) {.async.} = + ## handle requests on connection + discard + +proc addHandle*(m: MultisteamSelect, + proto: string, + handler: Handler, + matcher: Matcher = nil) = + ## register a handler for the protocol + m.handlers.add(HandlerHolder(proto: proto, + handler: handler, + match: matcher))