mirror of
https://github.com/logos-storage/logos-storage-nim-dht.git
synced 2026-01-02 13:33:08 +00:00
68 lines
2.0 KiB
Nim
68 lines
2.0 KiB
Nim
import
|
|
".."/../[rlp],
|
|
"."/[messages, enr]
|
|
|
|
from stew/objects import checkedEnumAssign
|
|
|
|
type
|
|
DecodeResult*[T] = Result[T, cstring]
|
|
|
|
proc numFields(T: typedesc): int =
|
|
for k, v in fieldPairs(default(T)): inc result
|
|
|
|
proc encodeMessage*[T: SomeMessage](p: T, reqId: RequestId): seq[byte] =
|
|
result = newSeqOfCap[byte](64)
|
|
result.add(messageKind(T).ord)
|
|
|
|
const sz = numFields(T)
|
|
var writer = initRlpList(sz + 1)
|
|
writer.append(reqId)
|
|
for k, v in fieldPairs(p):
|
|
writer.append(v)
|
|
result.add(writer.finish())
|
|
|
|
proc decodeMessage*(body: openArray[byte]): DecodeResult[Message] =
|
|
## Decodes to the specific `Message` type.
|
|
if body.len < 1:
|
|
return err("No message data")
|
|
|
|
var kind: MessageKind
|
|
if not checkedEnumAssign(kind, body[0]):
|
|
return err("Invalid message type")
|
|
|
|
var message = Message(kind: kind)
|
|
var rlp = rlpFromBytes(body.toOpenArray(1, body.high))
|
|
if rlp.enterList:
|
|
try:
|
|
message.reqId = rlp.read(RequestId)
|
|
except RlpError, ValueError:
|
|
return err("Invalid request-id")
|
|
|
|
proc decode[T](rlp: var Rlp, v: var T)
|
|
{.nimcall, raises:[RlpError, ValueError, Defect].} =
|
|
for k, v in v.fieldPairs:
|
|
v = rlp.read(typeof(v))
|
|
|
|
try:
|
|
case kind
|
|
of unused: return err("Invalid message type")
|
|
of ping: rlp.decode(message.ping)
|
|
of pong: rlp.decode(message.pong)
|
|
of findNode: rlp.decode(message.findNode)
|
|
of nodes: rlp.decode(message.nodes)
|
|
of talkReq: rlp.decode(message.talkReq)
|
|
of talkResp: rlp.decode(message.talkResp)
|
|
of regTopic, ticket, regConfirmation, topicQuery:
|
|
# We just pass the empty type of this message without attempting to
|
|
# decode, so that the protocol knows what was received.
|
|
# But we ignore the message as per specification as "the content and
|
|
# semantics of this message are not final".
|
|
discard
|
|
except RlpError, ValueError:
|
|
return err("Invalid message encoding")
|
|
|
|
ok(message)
|
|
else:
|
|
err("Invalid message encoding: no rlp list")
|
|
|