140 lines
3.6 KiB
Nim
140 lines
3.6 KiB
Nim
# Nim-LibP2P
|
|
# Copyright (c) 2023 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
# at your option.
|
|
# This file may not be copied, modified, or distributed except according to
|
|
# those terms.
|
|
|
|
{.push raises: [].}
|
|
|
|
import stew/[results, objects]
|
|
import chronos, chronicles
|
|
import ../../../multiaddress,
|
|
../../../peerid,
|
|
../../../errors
|
|
|
|
logScope:
|
|
topics = "libp2p autonat"
|
|
|
|
const
|
|
AutonatCodec* = "/libp2p/autonat/1.0.0"
|
|
AddressLimit* = 8
|
|
|
|
type
|
|
AutonatError* = object of LPError
|
|
AutonatUnreachableError* = object of LPError
|
|
|
|
MsgType* = enum
|
|
Dial = 0
|
|
DialResponse = 1
|
|
|
|
ResponseStatus* = enum
|
|
Ok = 0
|
|
DialError = 100
|
|
DialRefused = 101
|
|
BadRequest = 200
|
|
InternalError = 300
|
|
|
|
AutonatPeerInfo* = object
|
|
id*: Opt[PeerId]
|
|
addrs*: seq[MultiAddress]
|
|
|
|
AutonatDial* = object
|
|
peerInfo*: Opt[AutonatPeerInfo]
|
|
|
|
AutonatDialResponse* = object
|
|
status*: ResponseStatus
|
|
text*: Opt[string]
|
|
ma*: Opt[MultiAddress]
|
|
|
|
AutonatMsg* = object
|
|
msgType*: MsgType
|
|
dial*: Opt[AutonatDial]
|
|
response*: Opt[AutonatDialResponse]
|
|
|
|
NetworkReachability* {.pure.} = enum
|
|
Unknown, NotReachable, Reachable
|
|
|
|
proc encode(p: AutonatPeerInfo): ProtoBuffer =
|
|
result = initProtoBuffer()
|
|
p.id.withValue(id):
|
|
result.write(1, id)
|
|
for ma in p.addrs:
|
|
result.write(2, ma.data.buffer)
|
|
result.finish()
|
|
|
|
proc encode*(d: AutonatDial): ProtoBuffer =
|
|
result = initProtoBuffer()
|
|
result.write(1, MsgType.Dial.uint)
|
|
var dial = initProtoBuffer()
|
|
d.peerInfo.withValue(pinfo):
|
|
dial.write(1, encode(pinfo))
|
|
dial.finish()
|
|
result.write(2, dial.buffer)
|
|
result.finish()
|
|
|
|
proc encode*(r: AutonatDialResponse): ProtoBuffer =
|
|
result = initProtoBuffer()
|
|
result.write(1, MsgType.DialResponse.uint)
|
|
var bufferResponse = initProtoBuffer()
|
|
bufferResponse.write(1, r.status.uint)
|
|
r.text.withValue(text):
|
|
bufferResponse.write(2, text)
|
|
r.ma.withValue(ma):
|
|
bufferResponse.write(3, ma)
|
|
bufferResponse.finish()
|
|
result.write(3, bufferResponse.buffer)
|
|
result.finish()
|
|
|
|
proc encode*(msg: AutonatMsg): ProtoBuffer =
|
|
msg.dial.withValue(dial):
|
|
return encode(dial)
|
|
msg.response.withValue(res):
|
|
return encode(res)
|
|
|
|
proc decode*(_: typedesc[AutonatMsg], buf: seq[byte]): Opt[AutonatMsg] =
|
|
var
|
|
msgTypeOrd: uint32
|
|
pbDial: ProtoBuffer
|
|
pbResponse: ProtoBuffer
|
|
msg: AutonatMsg
|
|
|
|
let pb = initProtoBuffer(buf)
|
|
|
|
if ? pb.getField(1, msgTypeOrd).toOpt() and not checkedEnumAssign(msg.msgType, msgTypeOrd):
|
|
return Opt.none(AutonatMsg)
|
|
if ? pb.getField(2, pbDial).toOpt():
|
|
var
|
|
pbPeerInfo: ProtoBuffer
|
|
dial: AutonatDial
|
|
let r4 = ? pbDial.getField(1, pbPeerInfo).toOpt()
|
|
|
|
var peerInfo: AutonatPeerInfo
|
|
if r4:
|
|
var pid: PeerId
|
|
let
|
|
r5 = ? pbPeerInfo.getField(1, pid).toOpt()
|
|
r6 = ? pbPeerInfo.getRepeatedField(2, peerInfo.addrs).toOpt()
|
|
if r5: peerInfo.id = Opt.some(pid)
|
|
dial.peerInfo = Opt.some(peerInfo)
|
|
msg.dial = Opt.some(dial)
|
|
|
|
if ? pb.getField(3, pbResponse).toOpt():
|
|
var
|
|
statusOrd: uint
|
|
text: string
|
|
ma: MultiAddress
|
|
response: AutonatDialResponse
|
|
|
|
if ? pbResponse.getField(1, statusOrd).optValue():
|
|
if not checkedEnumAssign(response.status, statusOrd):
|
|
return Opt.none(AutonatMsg)
|
|
if ? pbResponse.getField(2, text).optValue():
|
|
response.text = Opt.some(text)
|
|
if ? pbResponse.getField(3, ma).optValue():
|
|
response.ma = Opt.some(ma)
|
|
msg.response = Opt.some(response)
|
|
return Opt.some(msg)
|