2022-07-01 18:19:57 +00:00
|
|
|
# Nim-Libp2p
|
2023-01-20 14:47:40 +00:00
|
|
|
# Copyright (c) 2023 Status Research & Development GmbH
|
2022-07-01 18:19:57 +00:00
|
|
|
# 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.
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
## This module implements MultiAddress.
|
2020-05-31 14:22:49 +00:00
|
|
|
|
2023-06-07 11:12:49 +00:00
|
|
|
{.push raises: [].}
|
2022-07-01 18:19:57 +00:00
|
|
|
{.push public.}
|
2020-05-31 14:22:49 +00:00
|
|
|
|
2024-09-10 13:24:58 +00:00
|
|
|
import pkg/[chronos, chronicles, results]
|
2024-05-08 12:33:26 +00:00
|
|
|
import std/[nativesockets, net, hashes]
|
|
|
|
import tables, strutils, sets
|
2020-07-13 12:43:07 +00:00
|
|
|
import
|
|
|
|
multicodec,
|
|
|
|
multihash,
|
|
|
|
multibase,
|
|
|
|
transcoder,
|
|
|
|
vbuffer,
|
|
|
|
peerid,
|
2022-07-01 18:19:57 +00:00
|
|
|
protobuf/minprotobuf,
|
|
|
|
errors,
|
|
|
|
utility
|
2024-09-10 13:24:58 +00:00
|
|
|
import stew/[base58, base32, endians2]
|
|
|
|
export results, minprotobuf, vbuffer, errors, utility
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2023-04-14 12:05:32 +00:00
|
|
|
logScope:
|
|
|
|
topics = "libp2p multiaddress"
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
type
|
|
|
|
MAKind* = enum
|
|
|
|
None
|
|
|
|
Fixed
|
|
|
|
Length
|
|
|
|
Path
|
|
|
|
Marker
|
|
|
|
|
|
|
|
MAProtocol* = object
|
2018-12-05 15:24:07 +00:00
|
|
|
mcodec*: MultiCodec
|
2018-11-27 12:16:04 +00:00
|
|
|
size*: int
|
|
|
|
kind: MAKind
|
|
|
|
coder*: Transcoder
|
|
|
|
|
|
|
|
MultiAddress* = object
|
2023-04-06 14:19:01 +00:00
|
|
|
data: VBuffer
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2019-03-20 09:41:37 +00:00
|
|
|
MaPatternOp* = enum
|
|
|
|
Eq
|
|
|
|
Or
|
|
|
|
And
|
|
|
|
|
|
|
|
MaPattern* = object
|
|
|
|
operator*: MaPatternOp
|
|
|
|
args*: seq[MaPattern]
|
|
|
|
value*: MultiCodec
|
|
|
|
|
|
|
|
MaPatResult* = object
|
|
|
|
flag*: bool
|
|
|
|
rem*: seq[MultiCodec]
|
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
MaResult*[T] = Result[T, string]
|
|
|
|
|
2021-05-21 16:27:01 +00:00
|
|
|
MaError* = object of LPError
|
2020-11-19 02:06:42 +00:00
|
|
|
MaInvalidAddress* = object of MaError
|
|
|
|
|
2020-06-05 14:11:26 +00:00
|
|
|
IpTransportProtocol* = enum
|
|
|
|
tcpProtocol
|
|
|
|
udpProtocol
|
|
|
|
|
2024-09-10 13:24:58 +00:00
|
|
|
func maErr*(msg: string): ref MaError =
|
|
|
|
(ref MaError)(msg: msg)
|
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
const
|
|
|
|
# These are needed in order to avoid an ambiguity error stemming from
|
|
|
|
# some cint constants with the same name defined in the posix modules
|
|
|
|
IPPROTO_TCP = Protocol.IPPROTO_TCP
|
|
|
|
IPPROTO_UDP = Protocol.IPPROTO_UDP
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2023-04-06 14:19:01 +00:00
|
|
|
proc data*(ma: MultiAddress): VBuffer =
|
|
|
|
## Returns the data buffer of the MultiAddress.
|
|
|
|
return ma.data
|
|
|
|
|
2020-09-21 09:16:29 +00:00
|
|
|
proc hash*(a: MultiAddress): Hash =
|
|
|
|
var h: Hash = 0
|
|
|
|
h = h !& hash(a.data.buffer)
|
|
|
|
h = h !& hash(a.data.offset)
|
|
|
|
!$h
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
proc ip4StB(s: string, vb: var VBuffer): bool =
|
|
|
|
## IPv4 stringToBuffer() implementation.
|
|
|
|
try:
|
|
|
|
var a = parseIpAddress(s)
|
|
|
|
if a.family == IpAddressFamily.IPv4:
|
|
|
|
vb.writeArray(a.address_v4)
|
|
|
|
result = true
|
2023-05-18 08:24:17 +00:00
|
|
|
except CatchableError:
|
2018-11-27 12:16:04 +00:00
|
|
|
discard
|
|
|
|
|
|
|
|
proc ip4BtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## IPv4 bufferToString() implementation.
|
|
|
|
var a = IpAddress(family: IpAddressFamily.IPv4)
|
|
|
|
if vb.readArray(a.address_v4) == 4:
|
|
|
|
s = $a
|
|
|
|
result = true
|
|
|
|
|
|
|
|
proc ip4VB(vb: var VBuffer): bool =
|
|
|
|
## IPv4 validateBuffer() implementation.
|
|
|
|
var a = IpAddress(family: IpAddressFamily.IPv4)
|
|
|
|
if vb.readArray(a.address_v4) == 4:
|
|
|
|
result = true
|
|
|
|
|
|
|
|
proc ip6StB(s: string, vb: var VBuffer): bool =
|
|
|
|
## IPv6 stringToBuffer() implementation.
|
|
|
|
try:
|
|
|
|
var a = parseIpAddress(s)
|
|
|
|
if a.family == IpAddressFamily.IPv6:
|
|
|
|
vb.writeArray(a.address_v6)
|
|
|
|
result = true
|
2023-05-18 08:24:17 +00:00
|
|
|
except CatchableError:
|
2018-11-27 12:16:04 +00:00
|
|
|
discard
|
|
|
|
|
|
|
|
proc ip6BtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## IPv6 bufferToString() implementation.
|
|
|
|
var a = IpAddress(family: IpAddressFamily.IPv6)
|
|
|
|
if vb.readArray(a.address_v6) == 16:
|
|
|
|
s = $a
|
|
|
|
result = true
|
|
|
|
|
|
|
|
proc ip6VB(vb: var VBuffer): bool =
|
|
|
|
## IPv6 validateBuffer() implementation.
|
|
|
|
var a = IpAddress(family: IpAddressFamily.IPv6)
|
|
|
|
if vb.readArray(a.address_v6) == 16:
|
|
|
|
result = true
|
|
|
|
|
2024-02-22 14:57:11 +00:00
|
|
|
template pathStringToBuffer(s: string, vb: var VBuffer): bool =
|
2018-11-27 12:16:04 +00:00
|
|
|
if len(s) > 0:
|
|
|
|
vb.writeSeq(s)
|
2024-02-22 14:57:11 +00:00
|
|
|
true
|
|
|
|
else:
|
|
|
|
false
|
|
|
|
|
|
|
|
template pathBufferToString(vb: var VBuffer, s: var string): bool =
|
|
|
|
s = ""
|
|
|
|
if (vb.readSeq(s) > 0) and (len(s) > 0): true else: false
|
|
|
|
|
|
|
|
template pathBufferToStringNoSlash(vb: var VBuffer, s: var string): bool =
|
|
|
|
s = ""
|
|
|
|
if (vb.readSeq(s) > 0) and (len(s) > 0) and (s.find('/') == -1): true else: false
|
|
|
|
|
|
|
|
template pathValidateBuffer(vb: var VBuffer): bool =
|
|
|
|
var s = ""
|
|
|
|
pathBufferToString(vb, s)
|
|
|
|
|
|
|
|
template pathValidateBufferNoSlash(vb: var VBuffer): bool =
|
|
|
|
var s = ""
|
|
|
|
pathBufferToStringNoSlash(vb, s)
|
|
|
|
|
|
|
|
proc ip6zoneStB(s: string, vb: var VBuffer): bool =
|
|
|
|
## IPv6 stringToBuffer() implementation.
|
|
|
|
pathStringToBuffer(s, vb)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc ip6zoneBtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## IPv6 bufferToString() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathBufferToStringNoSlash(vb, s)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc ip6zoneVB(vb: var VBuffer): bool =
|
|
|
|
## IPv6 validateBuffer() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathValidateBufferNoSlash(vb)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc portStB(s: string, vb: var VBuffer): bool =
|
|
|
|
## Port number stringToBuffer() implementation.
|
|
|
|
var port: array[2, byte]
|
|
|
|
try:
|
|
|
|
var nport = parseInt(s)
|
2018-12-05 00:30:50 +00:00
|
|
|
if (nport >= 0) and (nport < 65536):
|
2018-11-27 12:16:04 +00:00
|
|
|
port[0] = cast[byte]((nport shr 8) and 0xFF)
|
|
|
|
port[1] = cast[byte](nport and 0xFF)
|
|
|
|
vb.writeArray(port)
|
|
|
|
result = true
|
2023-05-18 08:24:17 +00:00
|
|
|
except CatchableError:
|
2018-11-27 12:16:04 +00:00
|
|
|
discard
|
|
|
|
|
|
|
|
proc portBtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## Port number bufferToString() implementation.
|
|
|
|
var port: array[2, byte]
|
|
|
|
if vb.readArray(port) == 2:
|
2024-02-22 14:57:11 +00:00
|
|
|
let nport = (safeConvert[uint16](port[0]) shl 8) or safeConvert[uint16](port[1])
|
2018-11-27 12:16:04 +00:00
|
|
|
s = $nport
|
|
|
|
result = true
|
|
|
|
|
|
|
|
proc portVB(vb: var VBuffer): bool =
|
|
|
|
## Port number validateBuffer() implementation.
|
|
|
|
var port: array[2, byte]
|
|
|
|
if vb.readArray(port) == 2:
|
|
|
|
result = true
|
|
|
|
|
|
|
|
proc p2pStB(s: string, vb: var VBuffer): bool =
|
|
|
|
## P2P address stringToBuffer() implementation.
|
|
|
|
try:
|
|
|
|
var data = Base58.decode(s)
|
2018-12-05 00:30:50 +00:00
|
|
|
var mh: MultiHash
|
2020-05-18 05:25:55 +00:00
|
|
|
if MultiHash.decode(data, mh).isOk:
|
2018-12-05 00:30:50 +00:00
|
|
|
vb.writeSeq(data)
|
|
|
|
result = true
|
2023-05-18 08:24:17 +00:00
|
|
|
except CatchableError:
|
2018-11-27 12:16:04 +00:00
|
|
|
discard
|
|
|
|
|
|
|
|
proc p2pBtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## P2P address bufferToString() implementation.
|
|
|
|
var address = newSeq[byte]()
|
|
|
|
if vb.readSeq(address) > 0:
|
2018-12-05 00:30:50 +00:00
|
|
|
var mh: MultiHash
|
2020-05-18 05:25:55 +00:00
|
|
|
if MultiHash.decode(address, mh).isOk:
|
2018-12-05 00:30:50 +00:00
|
|
|
s = Base58.encode(address)
|
|
|
|
result = true
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc p2pVB(vb: var VBuffer): bool =
|
|
|
|
## P2P address validateBuffer() implementation.
|
|
|
|
var address = newSeq[byte]()
|
|
|
|
if vb.readSeq(address) > 0:
|
2018-12-05 00:30:50 +00:00
|
|
|
var mh: MultiHash
|
2020-05-18 05:25:55 +00:00
|
|
|
if MultiHash.decode(address, mh).isOk:
|
2018-12-05 00:30:50 +00:00
|
|
|
result = true
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc onionStB(s: string, vb: var VBuffer): bool =
|
2018-12-05 00:30:50 +00:00
|
|
|
try:
|
|
|
|
var parts = s.split(':')
|
|
|
|
if len(parts) != 2:
|
|
|
|
return false
|
|
|
|
if len(parts[0]) != 16:
|
|
|
|
return false
|
|
|
|
var address = Base32Lower.decode(parts[0].toLowerAscii())
|
|
|
|
var nport = parseInt(parts[1])
|
|
|
|
if (nport > 0 and nport < 65536) and len(address) == 10:
|
|
|
|
address.setLen(12)
|
|
|
|
address[10] = cast[byte]((nport shr 8) and 0xFF)
|
|
|
|
address[11] = cast[byte](nport and 0xFF)
|
|
|
|
vb.writeArray(address)
|
|
|
|
result = true
|
2023-05-18 08:24:17 +00:00
|
|
|
except CatchableError:
|
2018-12-05 00:30:50 +00:00
|
|
|
discard
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc onionBtS(vb: var VBuffer, s: var string): bool =
|
2018-12-05 00:30:50 +00:00
|
|
|
## ONION address bufferToString() implementation.
|
|
|
|
var buf: array[12, byte]
|
|
|
|
if vb.readArray(buf) == 12:
|
2024-02-22 14:57:11 +00:00
|
|
|
let nport = (safeConvert[uint16](buf[10]) shl 8) or safeConvert[uint16](buf[11])
|
2018-12-05 00:30:50 +00:00
|
|
|
s = Base32Lower.encode(buf.toOpenArray(0, 9))
|
|
|
|
s.add(":")
|
|
|
|
s.add($nport)
|
|
|
|
result = true
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc onionVB(vb: var VBuffer): bool =
|
2018-12-05 00:30:50 +00:00
|
|
|
## ONION address validateBuffer() implementation.
|
|
|
|
var buf: array[12, byte]
|
|
|
|
if vb.readArray(buf) == 12:
|
|
|
|
result = true
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2022-09-08 15:10:11 +00:00
|
|
|
proc onion3StB(s: string, vb: var VBuffer): bool =
|
|
|
|
try:
|
|
|
|
var parts = s.split(':')
|
|
|
|
if len(parts) != 2:
|
|
|
|
return false
|
|
|
|
if len(parts[0]) != 56:
|
|
|
|
return false
|
|
|
|
var address = Base32Lower.decode(parts[0].toLowerAscii())
|
|
|
|
var nport = parseInt(parts[1])
|
|
|
|
if (nport > 0 and nport < 65536) and len(address) == 35:
|
|
|
|
address.setLen(37)
|
|
|
|
address[35] = cast[byte]((nport shr 8) and 0xFF)
|
|
|
|
address[36] = cast[byte](nport and 0xFF)
|
|
|
|
vb.writeArray(address)
|
|
|
|
result = true
|
2023-05-18 08:24:17 +00:00
|
|
|
except CatchableError:
|
2022-09-08 15:10:11 +00:00
|
|
|
discard
|
|
|
|
|
|
|
|
proc onion3BtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## ONION address bufferToString() implementation.
|
|
|
|
var buf: array[37, byte]
|
|
|
|
if vb.readArray(buf) == 37:
|
2024-02-22 14:57:11 +00:00
|
|
|
var nport = (safeConvert[uint16](buf[35]) shl 8) or safeConvert[uint16](buf[36])
|
2022-09-08 15:10:11 +00:00
|
|
|
s = Base32Lower.encode(buf.toOpenArray(0, 34))
|
|
|
|
s.add(":")
|
|
|
|
s.add($nport)
|
|
|
|
result = true
|
|
|
|
|
|
|
|
proc onion3VB(vb: var VBuffer): bool =
|
|
|
|
## ONION address validateBuffer() implementation.
|
|
|
|
var buf: array[37, byte]
|
|
|
|
if vb.readArray(buf) == 37:
|
|
|
|
result = true
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
proc unixStB(s: string, vb: var VBuffer): bool =
|
|
|
|
## Unix socket name stringToBuffer() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathStringToBuffer(s, vb)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc unixBtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## Unix socket name bufferToString() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathBufferToString(vb, s)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc unixVB(vb: var VBuffer): bool =
|
|
|
|
## Unix socket name validateBuffer() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathValidateBuffer(vb)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc dnsStB(s: string, vb: var VBuffer): bool =
|
|
|
|
## DNS name stringToBuffer() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathStringToBuffer(s, vb)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc dnsBtS(vb: var VBuffer, s: var string): bool =
|
|
|
|
## DNS name bufferToString() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathBufferToStringNoSlash(vb, s)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc dnsVB(vb: var VBuffer): bool =
|
|
|
|
## DNS name validateBuffer() implementation.
|
2024-02-22 14:57:11 +00:00
|
|
|
pathValidateBufferNoSlash(vb)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2020-02-12 10:04:12 +00:00
|
|
|
proc mapEq*(codec: string): MaPattern =
|
2019-03-20 09:41:37 +00:00
|
|
|
## ``Equal`` operator for pattern
|
|
|
|
result.operator = Eq
|
|
|
|
result.value = multiCodec(codec)
|
|
|
|
|
2020-02-12 10:04:12 +00:00
|
|
|
proc mapOr*(args: varargs[MaPattern]): MaPattern =
|
2019-03-20 09:41:37 +00:00
|
|
|
## ``Or`` operator for pattern
|
|
|
|
result.operator = Or
|
|
|
|
result.args = @args
|
|
|
|
|
2020-02-12 10:04:12 +00:00
|
|
|
proc mapAnd*(args: varargs[MaPattern]): MaPattern =
|
2019-03-20 09:41:37 +00:00
|
|
|
## ``And`` operator for pattern
|
|
|
|
result.operator = And
|
|
|
|
result.args = @args
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
const
|
|
|
|
TranscoderIP4* =
|
|
|
|
Transcoder(stringToBuffer: ip4StB, bufferToString: ip4BtS, validateBuffer: ip4VB)
|
|
|
|
TranscoderIP6* =
|
|
|
|
Transcoder(stringToBuffer: ip6StB, bufferToString: ip6BtS, validateBuffer: ip6VB)
|
|
|
|
TranscoderIP6Zone* = Transcoder(
|
|
|
|
stringToBuffer: ip6zoneStB, bufferToString: ip6zoneBtS, validateBuffer: ip6zoneVB
|
|
|
|
)
|
|
|
|
TranscoderUnix* =
|
2024-02-22 14:57:11 +00:00
|
|
|
Transcoder(stringToBuffer: unixStB, bufferToString: unixBtS, validateBuffer: unixVB)
|
2018-11-27 12:16:04 +00:00
|
|
|
TranscoderP2P* =
|
2024-02-22 14:57:11 +00:00
|
|
|
Transcoder(stringToBuffer: p2pStB, bufferToString: p2pBtS, validateBuffer: p2pVB)
|
2018-11-27 12:16:04 +00:00
|
|
|
TranscoderPort* =
|
2024-02-22 14:57:11 +00:00
|
|
|
Transcoder(stringToBuffer: portStB, bufferToString: portBtS, validateBuffer: portVB)
|
2018-11-27 12:16:04 +00:00
|
|
|
TranscoderOnion* = Transcoder(
|
|
|
|
stringToBuffer: onionStB, bufferToString: onionBtS, validateBuffer: onionVB
|
|
|
|
)
|
2022-09-08 15:10:11 +00:00
|
|
|
TranscoderOnion3* = Transcoder(
|
|
|
|
stringToBuffer: onion3StB, bufferToString: onion3BtS, validateBuffer: onion3VB
|
2018-11-27 12:16:04 +00:00
|
|
|
)
|
|
|
|
TranscoderDNS* =
|
2024-02-22 14:57:11 +00:00
|
|
|
Transcoder(stringToBuffer: dnsStB, bufferToString: dnsBtS, validateBuffer: dnsVB)
|
2018-11-27 12:16:04 +00:00
|
|
|
ProtocolsList = [
|
2018-12-05 15:24:07 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("ip4"), kind: Fixed, size: 4, coder: TranscoderIP4),
|
|
|
|
MAProtocol(mcodec: multiCodec("tcp"), kind: Fixed, size: 2, coder: TranscoderPort),
|
|
|
|
MAProtocol(mcodec: multiCodec("udp"), kind: Fixed, size: 2, coder: TranscoderPort),
|
|
|
|
MAProtocol(mcodec: multiCodec("ip6"), kind: Fixed, size: 16, coder: TranscoderIP6),
|
|
|
|
MAProtocol(mcodec: multiCodec("dccp"), kind: Fixed, size: 2, coder: TranscoderPort),
|
|
|
|
MAProtocol(mcodec: multiCodec("sctp"), kind: Fixed, size: 2, coder: TranscoderPort),
|
|
|
|
MAProtocol(mcodec: multiCodec("udt"), kind: Marker, size: 0),
|
|
|
|
MAProtocol(mcodec: multiCodec("utp"), kind: Marker, size: 0),
|
|
|
|
MAProtocol(mcodec: multiCodec("http"), kind: Marker, size: 0),
|
|
|
|
MAProtocol(mcodec: multiCodec("https"), kind: Marker, size: 0),
|
|
|
|
MAProtocol(mcodec: multiCodec("quic"), kind: Marker, size: 0),
|
2023-11-20 10:09:56 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("quic-v1"), kind: Marker, size: 0),
|
2018-11-27 12:16:04 +00:00
|
|
|
MAProtocol(
|
2018-12-05 15:24:07 +00:00
|
|
|
mcodec: multiCodec("ip6zone"), kind: Length, size: 0, coder: TranscoderIP6Zone
|
2018-11-27 12:16:04 +00:00
|
|
|
),
|
|
|
|
MAProtocol(
|
2018-12-05 15:24:07 +00:00
|
|
|
mcodec: multiCodec("onion"), kind: Fixed, size: 10, coder: TranscoderOnion
|
2018-11-27 12:16:04 +00:00
|
|
|
),
|
|
|
|
MAProtocol(
|
2018-12-05 15:24:07 +00:00
|
|
|
mcodec: multiCodec("onion3"), kind: Fixed, size: 37, coder: TranscoderOnion3
|
2018-11-27 12:16:04 +00:00
|
|
|
),
|
2018-12-05 15:24:07 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("ws"), kind: Marker, size: 0),
|
2021-08-03 13:48:03 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("wss"), kind: Marker, size: 0),
|
2023-06-12 15:45:53 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("tls"), kind: Marker, size: 0),
|
2018-12-05 15:24:07 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("ipfs"), kind: Length, size: 0, coder: TranscoderP2P),
|
|
|
|
MAProtocol(mcodec: multiCodec("p2p"), kind: Length, size: 0, coder: TranscoderP2P),
|
|
|
|
MAProtocol(mcodec: multiCodec("unix"), kind: Path, size: 0, coder: TranscoderUnix),
|
2021-08-18 07:40:12 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("dns"), kind: Length, size: 0, coder: TranscoderDNS),
|
2018-12-05 15:24:07 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("dns4"), kind: Length, size: 0, coder: TranscoderDNS),
|
|
|
|
MAProtocol(mcodec: multiCodec("dns6"), kind: Length, size: 0, coder: TranscoderDNS),
|
2018-11-27 12:16:04 +00:00
|
|
|
MAProtocol(
|
2018-12-05 15:24:07 +00:00
|
|
|
mcodec: multiCodec("dnsaddr"), kind: Length, size: 0, coder: TranscoderDNS
|
2018-11-27 12:16:04 +00:00
|
|
|
),
|
2023-11-20 10:09:56 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("p2p-circuit"), kind: Marker, size: 0),
|
2021-08-03 13:48:03 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("p2p-websocket-star"), kind: Marker, size: 0),
|
2018-12-05 15:24:07 +00:00
|
|
|
MAProtocol(mcodec: multiCodec("p2p-webrtc-star"), kind: Marker, size: 0),
|
|
|
|
MAProtocol(mcodec: multiCodec("p2p-webrtc-direct"), kind: Marker, size: 0),
|
2018-11-27 12:16:04 +00:00
|
|
|
]
|
|
|
|
|
2021-08-18 07:40:12 +00:00
|
|
|
DNSANY* = mapEq("dns")
|
2020-02-12 10:04:12 +00:00
|
|
|
DNS4* = mapEq("dns4")
|
|
|
|
DNS6* = mapEq("dns6")
|
2021-08-18 07:40:12 +00:00
|
|
|
DNSADDR* = mapEq("dnsaddr")
|
2020-02-12 10:04:12 +00:00
|
|
|
IP4* = mapEq("ip4")
|
|
|
|
IP6* = mapEq("ip6")
|
2021-08-18 07:40:12 +00:00
|
|
|
DNS* = mapOr(DNSANY, DNS4, DNS6, DNSADDR)
|
2020-02-12 10:04:12 +00:00
|
|
|
IP* = mapOr(IP4, IP6)
|
2023-02-09 15:53:46 +00:00
|
|
|
DNS_OR_IP* = mapOr(DNS, IP)
|
2023-05-25 13:47:00 +00:00
|
|
|
TCP_DNS* = mapAnd(DNS, mapEq("tcp"))
|
2023-06-12 15:45:53 +00:00
|
|
|
TCP_IP* = mapAnd(IP, mapEq("tcp"))
|
2023-05-25 13:47:00 +00:00
|
|
|
TCP* = mapOr(TCP_DNS, TCP_IP)
|
|
|
|
UDP_DNS* = mapAnd(DNS, mapEq("udp"))
|
|
|
|
UDP_IP* = mapAnd(IP, mapEq("udp"))
|
|
|
|
UDP* = mapOr(UDP_DNS, UDP_IP)
|
2020-02-12 10:04:12 +00:00
|
|
|
UTP* = mapAnd(UDP, mapEq("utp"))
|
2024-09-12 09:32:14 +00:00
|
|
|
QUIC_IP* = mapAnd(UDP_IP, mapEq("quic"))
|
|
|
|
QUIC_DNS* = mapAnd(UDP_DNS, mapEq("quic"))
|
|
|
|
QUIC* = mapOr(QUIC_DNS, QUIC_IP)
|
|
|
|
QUIC_V1_IP* = mapAnd(UDP_IP, mapEq("quic-v1"))
|
|
|
|
QUIC_V1_DNS* = mapAnd(UDP_DNS, mapEq("quic-v1"))
|
|
|
|
QUIC_V1* = mapOr(QUIC_V1_DNS, QUIC_V1_IP)
|
2020-02-12 10:04:12 +00:00
|
|
|
UNIX* = mapEq("unix")
|
2023-05-25 13:47:00 +00:00
|
|
|
WS_DNS* = mapAnd(TCP_DNS, mapEq("ws"))
|
|
|
|
WS_IP* = mapAnd(TCP_IP, mapEq("ws"))
|
2021-08-03 13:48:03 +00:00
|
|
|
WS* = mapAnd(TCP, mapEq("ws"))
|
2023-06-12 15:45:53 +00:00
|
|
|
TLS_WS* = mapOr(mapEq("wss"), mapAnd(mapEq("tls"), mapEq("ws")))
|
|
|
|
WSS_DNS* = mapAnd(TCP_DNS, TLS_WS)
|
|
|
|
WSS_IP* = mapAnd(TCP_IP, TLS_WS)
|
|
|
|
WSS* = mapAnd(TCP, TLS_WS)
|
2023-05-25 13:47:00 +00:00
|
|
|
WebSockets_DNS* = mapOr(WS_DNS, WSS_DNS)
|
|
|
|
WebSockets_IP* = mapOr(WS_IP, WSS_IP)
|
2021-08-03 13:48:03 +00:00
|
|
|
WebSockets* = mapOr(WS, WSS)
|
2022-11-04 18:20:23 +00:00
|
|
|
Onion3* = mapEq("onion3")
|
|
|
|
TcpOnion3* = mapAnd(TCP, Onion3)
|
2019-03-20 09:41:37 +00:00
|
|
|
|
2020-02-12 10:04:12 +00:00
|
|
|
Unreliable* = mapOr(UDP)
|
2019-03-20 09:41:37 +00:00
|
|
|
|
2021-10-28 17:11:31 +00:00
|
|
|
Reliable* = mapOr(TCP, UTP, QUIC, WebSockets)
|
2019-03-20 09:41:37 +00:00
|
|
|
|
2022-05-18 08:19:37 +00:00
|
|
|
P2PPattern* = mapEq("p2p")
|
|
|
|
|
|
|
|
IPFS* = mapAnd(Reliable, P2PPattern)
|
2019-03-20 09:41:37 +00:00
|
|
|
|
2020-02-12 10:04:12 +00:00
|
|
|
HTTP* = mapOr(
|
|
|
|
mapAnd(TCP, mapEq("http")), mapAnd(IP, mapEq("http")), mapAnd(DNS, mapEq("http"))
|
2019-03-20 09:41:37 +00:00
|
|
|
)
|
|
|
|
|
2020-02-12 10:04:12 +00:00
|
|
|
HTTPS* = mapOr(
|
|
|
|
mapAnd(TCP, mapEq("https")), mapAnd(IP, mapEq("https")), mapAnd(DNS, mapEq("https"))
|
2019-03-20 09:41:37 +00:00
|
|
|
)
|
|
|
|
|
2020-02-12 10:04:12 +00:00
|
|
|
WebRTCDirect* = mapOr(
|
|
|
|
mapAnd(HTTP, mapEq("p2p-webrtc-direct")), mapAnd(HTTPS, mapEq("p2p-webrtc-direct"))
|
2019-03-20 09:41:37 +00:00
|
|
|
)
|
|
|
|
|
2022-05-18 08:19:37 +00:00
|
|
|
CircuitRelay* = mapEq("p2p-circuit")
|
|
|
|
|
2018-12-05 15:24:07 +00:00
|
|
|
proc initMultiAddressCodeTable(): Table[MultiCodec, MAProtocol] {.compileTime.} =
|
2018-11-27 12:16:04 +00:00
|
|
|
for item in ProtocolsList:
|
2018-12-05 15:24:07 +00:00
|
|
|
result[item.mcodec] = item
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
const CodeAddresses = initMultiAddressCodeTable()
|
|
|
|
|
|
|
|
proc trimRight(s: string, ch: char): string =
|
|
|
|
## Consume trailing characters ``ch`` from string ``s`` and return result.
|
|
|
|
var m = 0
|
2020-05-18 05:25:55 +00:00
|
|
|
for i in countdown(s.high, 0):
|
2018-11-27 12:16:04 +00:00
|
|
|
if s[i] == ch:
|
|
|
|
inc(m)
|
|
|
|
else:
|
|
|
|
break
|
2020-05-18 05:25:55 +00:00
|
|
|
result = s[0 .. (s.high - m)]
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
proc protoCode*(ma: MultiAddress): MaResult[MultiCodec] =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Returns MultiAddress ``ma`` protocol code.
|
2018-11-27 20:58:16 +00:00
|
|
|
var header: uint64
|
2022-10-20 12:52:02 +00:00
|
|
|
var vb = ma
|
2018-11-27 20:58:16 +00:00
|
|
|
if vb.data.readVarint(header) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
err("multiaddress: Malformed binary address!")
|
|
|
|
else:
|
|
|
|
let proto = CodeAddresses.getOrDefault(MultiCodec(header))
|
|
|
|
if proto.kind == None:
|
|
|
|
err("multiaddress: Unsupported protocol '" & $header & "'")
|
|
|
|
else:
|
|
|
|
ok(proto.mcodec)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
proc protoName*(ma: MultiAddress): MaResult[string] =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Returns MultiAddress ``ma`` protocol name.
|
2018-11-27 20:58:16 +00:00
|
|
|
var header: uint64
|
2022-10-20 12:52:02 +00:00
|
|
|
var vb = ma
|
2018-11-27 20:58:16 +00:00
|
|
|
if vb.data.readVarint(header) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
err("multiaddress: Malformed binary address!")
|
|
|
|
else:
|
|
|
|
let proto = CodeAddresses.getOrDefault(MultiCodec(header))
|
|
|
|
if proto.kind == None:
|
|
|
|
err("multiaddress: Unsupported protocol '" & $header & "'")
|
|
|
|
else:
|
|
|
|
ok($(proto.mcodec))
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2021-12-16 10:05:20 +00:00
|
|
|
proc protoArgument*(ma: MultiAddress, value: var openArray[byte]): MaResult[int] =
|
2018-11-27 20:58:16 +00:00
|
|
|
## Returns MultiAddress ``ma`` protocol argument value.
|
2018-12-29 12:44:27 +00:00
|
|
|
##
|
2018-11-27 20:58:16 +00:00
|
|
|
## If current MultiAddress do not have argument value, then result will be
|
|
|
|
## ``0``.
|
|
|
|
var header: uint64
|
2022-10-20 12:52:02 +00:00
|
|
|
var vb = ma
|
2018-11-27 20:58:16 +00:00
|
|
|
var buffer: seq[byte]
|
|
|
|
if vb.data.readVarint(header) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
err("multiaddress: Malformed binary address!")
|
|
|
|
else:
|
|
|
|
let proto = CodeAddresses.getOrDefault(MultiCodec(header))
|
|
|
|
if proto.kind == None:
|
|
|
|
err("multiaddress: Unsupported protocol '" & $header & "'")
|
|
|
|
else:
|
|
|
|
var res: int
|
|
|
|
if proto.kind == Fixed:
|
|
|
|
res = proto.size
|
2020-07-13 12:43:07 +00:00
|
|
|
if len(value) >= res and
|
|
|
|
vb.data.readArray(value.toOpenArray(0, proto.size - 1)) != proto.size:
|
2020-05-31 14:22:49 +00:00
|
|
|
err("multiaddress: Decoding protocol error")
|
|
|
|
else:
|
|
|
|
ok(res)
|
2022-09-26 09:03:24 +00:00
|
|
|
elif proto.kind in {MAKind.Length, Path}:
|
2020-05-31 14:22:49 +00:00
|
|
|
if vb.data.readSeq(buffer) == -1:
|
|
|
|
err("multiaddress: Decoding protocol error")
|
|
|
|
else:
|
|
|
|
res = len(buffer)
|
|
|
|
if len(value) >= res:
|
|
|
|
copyMem(addr value[0], addr buffer[0], res)
|
|
|
|
ok(res)
|
|
|
|
else:
|
|
|
|
ok(res)
|
|
|
|
|
|
|
|
proc protoAddress*(ma: MultiAddress): MaResult[seq[byte]] =
|
2019-10-29 13:38:37 +00:00
|
|
|
## Returns MultiAddress ``ma`` protocol address binary blob.
|
|
|
|
##
|
|
|
|
## If current MultiAddress do not have argument value, then result array will
|
|
|
|
## be empty.
|
2020-05-31 14:22:49 +00:00
|
|
|
var buffer = newSeq[byte](len(ma.data.buffer))
|
|
|
|
let res = ?protoArgument(ma, buffer)
|
|
|
|
buffer.setLen(res)
|
|
|
|
ok(buffer)
|
2019-10-29 13:38:37 +00:00
|
|
|
|
2022-09-26 09:03:24 +00:00
|
|
|
proc protoArgument*(ma: MultiAddress): MaResult[seq[byte]] =
|
|
|
|
## Returns MultiAddress ``ma`` protocol address binary blob.
|
|
|
|
##
|
|
|
|
## If current MultiAddress do not have argument value, then result array will
|
|
|
|
## be empty.
|
|
|
|
ma.protoAddress()
|
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
proc getPart(ma: MultiAddress, index: int): MaResult[MultiAddress] =
|
2018-11-27 12:16:04 +00:00
|
|
|
var header: uint64
|
|
|
|
var data = newSeq[byte]()
|
|
|
|
var offset = 0
|
|
|
|
var vb = ma
|
2020-05-31 14:22:49 +00:00
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
2022-09-26 09:03:24 +00:00
|
|
|
|
|
|
|
if index < 0:
|
|
|
|
return err("multiaddress: negative index gived to getPart")
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
while offset <= index:
|
|
|
|
if vb.data.readVarint(header) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
return err("multiaddress: Malformed binary address!")
|
|
|
|
|
2018-12-05 15:24:07 +00:00
|
|
|
let proto = CodeAddresses.getOrDefault(MultiCodec(header))
|
2018-11-27 12:16:04 +00:00
|
|
|
if proto.kind == None:
|
2020-05-31 14:22:49 +00:00
|
|
|
return err("multiaddress: Unsupported protocol '" & $header & "'")
|
2018-11-27 12:16:04 +00:00
|
|
|
elif proto.kind == Fixed:
|
|
|
|
data.setLen(proto.size)
|
|
|
|
if vb.data.readArray(data) != proto.size:
|
2020-05-31 14:22:49 +00:00
|
|
|
return err("multiaddress: Decoding protocol error")
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
if offset == index:
|
2020-05-31 14:22:49 +00:00
|
|
|
res.data.writeVarint(header)
|
|
|
|
res.data.writeArray(data)
|
|
|
|
res.data.finish()
|
2022-09-26 09:03:24 +00:00
|
|
|
elif proto.kind in {MAKind.Length, Path}:
|
2018-11-27 12:16:04 +00:00
|
|
|
if vb.data.readSeq(data) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
return err("multiaddress: Decoding protocol error")
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
if offset == index:
|
2020-05-31 14:22:49 +00:00
|
|
|
res.data.writeVarint(header)
|
|
|
|
res.data.writeSeq(data)
|
|
|
|
res.data.finish()
|
2018-11-27 12:16:04 +00:00
|
|
|
elif proto.kind == Marker:
|
|
|
|
if offset == index:
|
2020-05-31 14:22:49 +00:00
|
|
|
res.data.writeVarint(header)
|
|
|
|
res.data.finish()
|
2018-11-27 12:16:04 +00:00
|
|
|
inc(offset)
|
2020-05-31 14:22:49 +00:00
|
|
|
ok(res)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2024-02-22 14:57:11 +00:00
|
|
|
proc getParts[U, V](ma: MultiAddress, slice: HSlice[U, V]): MaResult[MultiAddress] =
|
2022-08-23 15:49:07 +00:00
|
|
|
when slice.a is BackwardsIndex or slice.b is BackwardsIndex:
|
|
|
|
let maLength = ?len(ma)
|
|
|
|
template normalizeIndex(index): int =
|
|
|
|
when index is BackwardsIndex:
|
|
|
|
maLength - int(index)
|
|
|
|
else:
|
|
|
|
int(index)
|
2024-06-11 15:18:06 +00:00
|
|
|
|
2022-08-23 15:49:07 +00:00
|
|
|
let
|
|
|
|
indexStart = normalizeIndex(slice.a)
|
|
|
|
indexEnd = normalizeIndex(slice.b)
|
|
|
|
var res: MultiAddress
|
|
|
|
for i in indexStart .. indexEnd:
|
|
|
|
?res.append(?ma[i])
|
|
|
|
ok(res)
|
|
|
|
|
2024-02-22 14:57:11 +00:00
|
|
|
proc `[]`*(
|
|
|
|
ma: MultiAddress, i: int | BackwardsIndex
|
|
|
|
): MaResult[MultiAddress] {.inline.} =
|
2018-12-16 02:54:07 +00:00
|
|
|
## Returns part with index ``i`` of MultiAddress ``ma``.
|
2022-09-26 09:03:24 +00:00
|
|
|
when i is BackwardsIndex:
|
|
|
|
let maLength = ?len(ma)
|
|
|
|
ma.getPart(maLength - int(i))
|
|
|
|
else:
|
|
|
|
ma.getPart(i)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2022-08-23 15:49:07 +00:00
|
|
|
proc `[]`*(ma: MultiAddress, slice: HSlice): MaResult[MultiAddress] {.inline.} =
|
|
|
|
## Returns parts with slice ``slice`` of MultiAddress ``ma``.
|
|
|
|
ma.getParts(slice)
|
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
iterator items*(ma: MultiAddress): MaResult[MultiAddress] =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Iterates over all addresses inside of MultiAddress ``ma``.
|
|
|
|
var header: uint64
|
|
|
|
var data = newSeq[byte]()
|
|
|
|
var vb = ma
|
|
|
|
while true:
|
|
|
|
if vb.data.isEmpty():
|
|
|
|
break
|
2020-05-31 14:22:49 +00:00
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
var res = MultiAddress(data: initVBuffer())
|
|
|
|
if vb.data.readVarint(header) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
yield err(MaResult[MultiAddress], "Malformed binary address!")
|
|
|
|
|
2018-12-05 15:24:07 +00:00
|
|
|
let proto = CodeAddresses.getOrDefault(MultiCodec(header))
|
2018-11-27 12:16:04 +00:00
|
|
|
if proto.kind == None:
|
2020-07-13 12:43:07 +00:00
|
|
|
yield err(MaResult[MultiAddress], "Unsupported protocol '" & $header & "'")
|
2018-11-27 12:16:04 +00:00
|
|
|
elif proto.kind == Fixed:
|
|
|
|
data.setLen(proto.size)
|
|
|
|
if vb.data.readArray(data) != proto.size:
|
2020-05-31 14:22:49 +00:00
|
|
|
yield err(MaResult[MultiAddress], "Decoding protocol error")
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
res.data.writeVarint(header)
|
|
|
|
res.data.writeArray(data)
|
2022-09-26 09:03:24 +00:00
|
|
|
elif proto.kind in {MAKind.Length, Path}:
|
2018-11-27 12:16:04 +00:00
|
|
|
if vb.data.readSeq(data) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
yield err(MaResult[MultiAddress], "Decoding protocol error")
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
res.data.writeVarint(header)
|
|
|
|
res.data.writeSeq(data)
|
|
|
|
elif proto.kind == Marker:
|
|
|
|
res.data.writeVarint(header)
|
|
|
|
res.data.finish()
|
2020-05-31 14:22:49 +00:00
|
|
|
yield ok(MaResult[MultiAddress], res)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2022-08-23 15:49:07 +00:00
|
|
|
proc len*(ma: MultiAddress): MaResult[int] =
|
|
|
|
var counter: int
|
|
|
|
for part in ma:
|
|
|
|
if part.isErr:
|
|
|
|
return err(part.error)
|
|
|
|
counter.inc()
|
|
|
|
ok(counter)
|
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
proc contains*(ma: MultiAddress, codec: MultiCodec): MaResult[bool] {.inline.} =
|
2020-02-27 17:26:42 +00:00
|
|
|
## Returns ``true``, if address with MultiCodec ``codec`` present in
|
|
|
|
## MultiAddress ``ma``.
|
|
|
|
for item in ma.items:
|
2020-05-31 14:22:49 +00:00
|
|
|
let code = ?(?item).protoCode()
|
|
|
|
if code == codec:
|
|
|
|
return ok(true)
|
|
|
|
ok(false)
|
2020-02-27 17:26:42 +00:00
|
|
|
|
2020-07-13 12:43:07 +00:00
|
|
|
proc `[]`*(ma: MultiAddress, codec: MultiCodec): MaResult[MultiAddress] {.inline.} =
|
2020-02-27 17:26:42 +00:00
|
|
|
## Returns partial MultiAddress with MultiCodec ``codec`` and present in
|
|
|
|
## MultiAddress ``ma``.
|
|
|
|
for item in ma.items:
|
2020-05-31 14:22:49 +00:00
|
|
|
if ?(?item).protoCode == codec:
|
|
|
|
return item
|
|
|
|
err("multiaddress: Codec is not present in address")
|
2020-02-27 17:26:42 +00:00
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
proc toString*(value: MultiAddress): MaResult[string] =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Return string representation of MultiAddress ``value``.
|
|
|
|
var header: uint64
|
|
|
|
var vb = value
|
|
|
|
var parts = newSeq[string]()
|
|
|
|
var part: string
|
2020-05-31 14:22:49 +00:00
|
|
|
var res: string
|
2018-11-27 12:16:04 +00:00
|
|
|
while true:
|
|
|
|
if vb.data.isEmpty():
|
|
|
|
break
|
|
|
|
if vb.data.readVarint(header) == -1:
|
2020-05-31 14:22:49 +00:00
|
|
|
return err("multiaddress: Malformed binary address!")
|
2018-12-05 15:24:07 +00:00
|
|
|
let proto = CodeAddresses.getOrDefault(MultiCodec(header))
|
2018-11-27 12:16:04 +00:00
|
|
|
if proto.kind == None:
|
2020-05-31 14:22:49 +00:00
|
|
|
return err("multiaddress: Unsupported protocol '" & $header & "'")
|
2018-11-27 12:16:04 +00:00
|
|
|
if proto.kind in {Fixed, Length, Path}:
|
|
|
|
if isNil(proto.coder.bufferToString):
|
2020-07-13 12:43:07 +00:00
|
|
|
return err("multiaddress: Missing protocol '" & $(proto.mcodec) & "' coder")
|
2018-11-27 12:16:04 +00:00
|
|
|
if not proto.coder.bufferToString(vb.data, part):
|
2020-05-31 14:22:49 +00:00
|
|
|
return err("multiaddress: Decoding protocol error")
|
2018-12-05 15:24:07 +00:00
|
|
|
parts.add($(proto.mcodec))
|
2024-02-22 14:57:11 +00:00
|
|
|
if len(part) > 0 and (proto.kind == Path) and (part[0] == '/'):
|
2019-01-09 17:12:15 +00:00
|
|
|
parts.add(part[1 ..^ 1])
|
|
|
|
else:
|
|
|
|
parts.add(part)
|
2018-11-27 12:16:04 +00:00
|
|
|
elif proto.kind == Marker:
|
2018-12-05 15:24:07 +00:00
|
|
|
parts.add($(proto.mcodec))
|
2018-11-27 12:16:04 +00:00
|
|
|
if len(parts) > 0:
|
2020-05-31 14:22:49 +00:00
|
|
|
res = "/" & parts.join("/")
|
|
|
|
ok(res)
|
|
|
|
|
2023-06-07 11:12:49 +00:00
|
|
|
proc `$`*(value: MultiAddress): string =
|
2020-05-31 14:22:49 +00:00
|
|
|
## Return string representation of MultiAddress ``value``.
|
2020-06-09 18:42:52 +00:00
|
|
|
let s = value.toString()
|
|
|
|
if s.isErr:
|
|
|
|
s.error
|
|
|
|
else:
|
|
|
|
s[]
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
proc protocols*(value: MultiAddress): MaResult[seq[MultiCodec]] =
|
2019-03-20 09:41:37 +00:00
|
|
|
## Returns list of protocol codecs inside of MultiAddress ``value``.
|
2020-05-31 14:22:49 +00:00
|
|
|
var res = newSeq[MultiCodec]()
|
2019-03-20 09:41:37 +00:00
|
|
|
for item in value.items():
|
2020-05-31 14:22:49 +00:00
|
|
|
res.add(?(?item).protoCode())
|
|
|
|
ok(res)
|
2019-03-20 09:41:37 +00:00
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
proc hex*(value: MultiAddress): string =
|
|
|
|
## Return hexadecimal string representation of MultiAddress ``value``.
|
2020-05-31 14:22:49 +00:00
|
|
|
$(value.data)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2018-12-16 02:54:07 +00:00
|
|
|
proc write*(vb: var VBuffer, ma: MultiAddress) {.inline.} =
|
|
|
|
## Write MultiAddress value ``ma`` to buffer ``vb``.
|
|
|
|
vb.writeArray(ma.data.buffer)
|
|
|
|
|
|
|
|
proc encode*(
|
|
|
|
mbtype: typedesc[MultiBase], encoding: string, ma: MultiAddress
|
|
|
|
): string {.inline.} =
|
|
|
|
## Get MultiBase encoded representation of ``ma`` using encoding
|
|
|
|
## ``encoding``.
|
|
|
|
result = MultiBase.encode(encoding, ma.data.buffer)
|
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
proc validate*(ma: MultiAddress): bool =
|
|
|
|
## Returns ``true`` if MultiAddress ``ma`` is valid.
|
|
|
|
var header: uint64
|
2022-10-20 12:52:02 +00:00
|
|
|
var vb = ma
|
2018-11-27 12:16:04 +00:00
|
|
|
while true:
|
|
|
|
if vb.data.isEmpty():
|
|
|
|
break
|
|
|
|
if vb.data.readVarint(header) == -1:
|
|
|
|
return false
|
2018-12-05 15:24:07 +00:00
|
|
|
let proto = CodeAddresses.getOrDefault(MultiCodec(header))
|
2018-11-27 12:16:04 +00:00
|
|
|
if proto.kind == None:
|
|
|
|
return false
|
|
|
|
if proto.kind in {Fixed, Length, Path}:
|
|
|
|
if isNil(proto.coder.validateBuffer):
|
|
|
|
return false
|
|
|
|
if not proto.coder.validateBuffer(vb.data):
|
|
|
|
return false
|
|
|
|
else:
|
|
|
|
discard
|
|
|
|
result = true
|
|
|
|
|
2020-06-01 12:41:45 +00:00
|
|
|
proc init*(
|
|
|
|
mtype: typedesc[MultiAddress], protocol: MultiCodec, value: openArray[byte] = []
|
2021-12-16 10:05:20 +00:00
|
|
|
): MaResult[MultiAddress] =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Initialize MultiAddress object from protocol id ``protocol`` and array
|
|
|
|
## of bytes ``value``.
|
|
|
|
let proto = CodeAddresses.getOrDefault(protocol)
|
|
|
|
if proto.kind == None:
|
2020-05-31 14:22:49 +00:00
|
|
|
err("multiaddress: Protocol not found")
|
|
|
|
else:
|
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
|
|
|
res.data.writeVarint(cast[uint64](proto.mcodec))
|
2020-06-01 12:41:45 +00:00
|
|
|
case proto.kind
|
|
|
|
of Fixed, Length, Path:
|
2020-05-31 14:22:49 +00:00
|
|
|
if len(value) == 0:
|
|
|
|
err("multiaddress: Value must not be empty array")
|
|
|
|
else:
|
|
|
|
if proto.kind == Fixed:
|
|
|
|
res.data.writeArray(value)
|
|
|
|
else:
|
2020-06-01 12:41:45 +00:00
|
|
|
res.data.writeSeq(value)
|
|
|
|
res.data.finish()
|
|
|
|
ok(res)
|
|
|
|
of Marker:
|
|
|
|
if len(value) != 0:
|
|
|
|
err("multiaddress: Value must be empty for markers")
|
|
|
|
else:
|
2020-05-31 14:22:49 +00:00
|
|
|
res.data.finish()
|
|
|
|
ok(res)
|
2020-06-01 12:41:45 +00:00
|
|
|
of None:
|
|
|
|
raiseAssert "None checked above"
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2020-07-13 12:43:07 +00:00
|
|
|
proc init*(
|
|
|
|
mtype: typedesc[MultiAddress], protocol: MultiCodec, value: PeerId
|
2021-12-16 10:05:20 +00:00
|
|
|
): MaResult[MultiAddress] {.inline.} =
|
2019-03-05 12:09:26 +00:00
|
|
|
## Initialize MultiAddress object from protocol id ``protocol`` and peer id
|
|
|
|
## ``value``.
|
2019-11-04 18:57:17 +00:00
|
|
|
init(mtype, protocol, value.data)
|
2019-03-05 12:09:26 +00:00
|
|
|
|
2020-07-13 12:43:07 +00:00
|
|
|
proc init*(
|
|
|
|
mtype: typedesc[MultiAddress], protocol: MultiCodec, value: int
|
|
|
|
): MaResult[MultiAddress] =
|
2020-04-23 02:56:31 +00:00
|
|
|
## Initialize MultiAddress object from protocol id ``protocol`` and integer
|
|
|
|
## ``value``. This procedure can be used to instantiate ``tcp``, ``udp``,
|
|
|
|
## ``dccp`` and ``sctp`` MultiAddresses.
|
|
|
|
var allowed =
|
|
|
|
[multiCodec("tcp"), multiCodec("udp"), multiCodec("dccp"), multiCodec("sctp")]
|
|
|
|
if protocol notin allowed:
|
2020-05-31 14:22:49 +00:00
|
|
|
err("multiaddress: Incorrect protocol for integer value")
|
|
|
|
else:
|
|
|
|
let proto = CodeAddresses.getOrDefault(protocol)
|
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
|
|
|
res.data.writeVarint(cast[uint64](proto.mcodec))
|
|
|
|
if value < 0 or value > 65535:
|
|
|
|
err("multiaddress: Incorrect integer value")
|
|
|
|
else:
|
|
|
|
res.data.writeArray(toBytesBE(cast[uint16](value)))
|
|
|
|
res.data.finish()
|
|
|
|
ok(res)
|
2020-04-23 02:56:31 +00:00
|
|
|
|
2018-12-05 15:24:07 +00:00
|
|
|
proc getProtocol(name: string): MAProtocol {.inline.} =
|
|
|
|
let mc = MultiCodec.codec(name)
|
|
|
|
if mc != InvalidMultiCodec:
|
|
|
|
result = CodeAddresses.getOrDefault(mc)
|
|
|
|
|
2020-07-13 12:43:07 +00:00
|
|
|
proc init*(mtype: typedesc[MultiAddress], value: string): MaResult[MultiAddress] =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Initialize MultiAddress object from string representation ``value``.
|
2023-04-06 14:19:01 +00:00
|
|
|
if len(value) == 0 or value == "/":
|
|
|
|
return err("multiaddress: Address must not be empty!")
|
2018-11-27 12:16:04 +00:00
|
|
|
var parts = value.trimRight('/').split('/')
|
|
|
|
if len(parts[0]) != 0:
|
2020-05-31 14:22:49 +00:00
|
|
|
err("multiaddress: Invalid MultiAddress, must start with `/`")
|
|
|
|
else:
|
|
|
|
var offset = 1
|
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
|
|
|
while offset < len(parts):
|
|
|
|
let part = parts[offset]
|
|
|
|
let proto = getProtocol(part)
|
|
|
|
if proto.kind == None:
|
|
|
|
return err("multiaddress: Unsupported protocol '" & part & "'")
|
|
|
|
else:
|
|
|
|
if proto.kind in {Fixed, Length, Path}:
|
|
|
|
if isNil(proto.coder.stringToBuffer):
|
2020-07-13 12:43:07 +00:00
|
|
|
return err("multiaddress: Missing protocol '" & part & "' transcoder")
|
2020-05-31 14:22:49 +00:00
|
|
|
|
|
|
|
if offset + 1 >= len(parts):
|
|
|
|
return err("multiaddress: Missing protocol '" & part & "' argument")
|
|
|
|
|
|
|
|
if proto.kind in {Fixed, Length}:
|
|
|
|
res.data.write(proto.mcodec)
|
|
|
|
let res = proto.coder.stringToBuffer(parts[offset + 1], res.data)
|
|
|
|
if not res:
|
2020-07-13 12:43:07 +00:00
|
|
|
return err(
|
|
|
|
"multiaddress: Error encoding `" & part & "/" & parts[offset + 1] & "`"
|
|
|
|
)
|
2020-05-31 14:22:49 +00:00
|
|
|
offset += 2
|
|
|
|
elif proto.kind == Path:
|
|
|
|
var path = "/" & (parts[(offset + 1) ..^ 1].join("/"))
|
|
|
|
res.data.write(proto.mcodec)
|
|
|
|
if not proto.coder.stringToBuffer(path, res.data):
|
2020-07-13 12:43:07 +00:00
|
|
|
return err("multiaddress: Error encoding `" & part & "/" & path & "`")
|
2020-05-31 14:22:49 +00:00
|
|
|
|
|
|
|
break
|
|
|
|
elif proto.kind == Marker:
|
|
|
|
res.data.write(proto.mcodec)
|
|
|
|
offset += 1
|
|
|
|
res.data.finish()
|
|
|
|
ok(res)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2020-07-13 12:43:07 +00:00
|
|
|
proc init*(
|
2021-12-16 10:05:20 +00:00
|
|
|
mtype: typedesc[MultiAddress], data: openArray[byte]
|
|
|
|
): MaResult[MultiAddress] =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Initialize MultiAddress with array of bytes ``data``.
|
|
|
|
if len(data) == 0:
|
2023-04-06 14:19:01 +00:00
|
|
|
err("multiaddress: Address must not be empty!")
|
2020-05-31 14:22:49 +00:00
|
|
|
else:
|
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
|
|
|
res.data.buffer.setLen(len(data))
|
|
|
|
copyMem(addr res.data.buffer[0], unsafeAddr data[0], len(data))
|
|
|
|
if not res.validate():
|
|
|
|
err("multiaddress: Incorrect MultiAddress!")
|
|
|
|
else:
|
|
|
|
ok(res)
|
2018-11-27 12:16:04 +00:00
|
|
|
|
|
|
|
proc init*(mtype: typedesc[MultiAddress]): MultiAddress =
|
|
|
|
## Initialize empty MultiAddress.
|
|
|
|
result.data = initVBuffer()
|
|
|
|
|
2023-12-12 11:53:36 +00:00
|
|
|
proc init*(
|
|
|
|
mtype: typedesc[MultiAddress],
|
|
|
|
address: IpAddress,
|
2020-10-30 15:52:38 +00:00
|
|
|
protocol: IpTransportProtocol,
|
|
|
|
port: Port,
|
|
|
|
): MultiAddress =
|
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
2020-06-05 14:11:26 +00:00
|
|
|
let
|
2020-10-30 15:52:38 +00:00
|
|
|
networkProto =
|
|
|
|
case address.family
|
2020-06-05 14:11:26 +00:00
|
|
|
of IpAddressFamily.IPv4:
|
|
|
|
getProtocol("ip4")
|
|
|
|
of IpAddressFamily.IPv6:
|
|
|
|
getProtocol("ip6")
|
2024-06-11 15:18:06 +00:00
|
|
|
|
2020-10-30 15:52:38 +00:00
|
|
|
transportProto =
|
|
|
|
case protocol
|
2020-06-05 14:11:26 +00:00
|
|
|
of tcpProtocol:
|
|
|
|
getProtocol("tcp")
|
|
|
|
of udpProtocol:
|
|
|
|
getProtocol("udp")
|
|
|
|
|
2020-10-30 15:52:38 +00:00
|
|
|
res.data.write(networkProto.mcodec)
|
|
|
|
case address.family
|
|
|
|
of IpAddressFamily.IPv4:
|
|
|
|
res.data.writeArray(address.address_v4)
|
|
|
|
of IpAddressFamily.IPv6:
|
|
|
|
res.data.writeArray(address.address_v6)
|
|
|
|
res.data.write(transportProto.mcodec)
|
2020-10-31 01:23:34 +00:00
|
|
|
res.data.writeArray(toBytesBE(uint16(port)))
|
2020-10-30 15:52:38 +00:00
|
|
|
res.data.finish()
|
2020-10-31 04:20:29 +00:00
|
|
|
res
|
2019-06-12 18:18:08 +00:00
|
|
|
|
2019-10-10 04:16:02 +00:00
|
|
|
proc init*(
|
|
|
|
mtype: typedesc[MultiAddress], address: TransportAddress, protocol = IPPROTO_TCP
|
2020-05-31 14:22:49 +00:00
|
|
|
): MaResult[MultiAddress] =
|
2019-10-10 04:16:02 +00:00
|
|
|
## Initialize MultiAddress using chronos.TransportAddress (IPv4/IPv6/Unix)
|
|
|
|
## and protocol information (UDP/TCP).
|
2020-05-31 14:22:49 +00:00
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
2019-10-10 04:16:02 +00:00
|
|
|
let protoProto =
|
|
|
|
case protocol
|
|
|
|
of IPPROTO_TCP:
|
|
|
|
getProtocol("tcp")
|
|
|
|
of IPPROTO_UDP:
|
|
|
|
getProtocol("udp")
|
2020-10-30 12:49:54 +00:00
|
|
|
else:
|
|
|
|
default(MAProtocol)
|
|
|
|
if protoProto.size == 0:
|
|
|
|
return err("multiaddress: protocol should be either TCP or UDP")
|
2019-10-10 04:16:02 +00:00
|
|
|
if address.family == AddressFamily.IPv4:
|
2020-05-31 14:22:49 +00:00
|
|
|
res.data.write(getProtocol("ip4").mcodec)
|
|
|
|
res.data.writeArray(address.address_v4)
|
|
|
|
res.data.write(protoProto.mcodec)
|
|
|
|
discard protoProto.coder.stringToBuffer($address.port, res.data)
|
2019-10-10 04:16:02 +00:00
|
|
|
elif address.family == AddressFamily.IPv6:
|
2020-05-31 14:22:49 +00:00
|
|
|
res.data.write(getProtocol("ip6").mcodec)
|
|
|
|
res.data.writeArray(address.address_v6)
|
|
|
|
res.data.write(protoProto.mcodec)
|
|
|
|
discard protoProto.coder.stringToBuffer($address.port, res.data)
|
2019-10-10 04:16:02 +00:00
|
|
|
elif address.family == AddressFamily.Unix:
|
2020-05-31 14:22:49 +00:00
|
|
|
res.data.write(getProtocol("unix").mcodec)
|
|
|
|
res.data.writeSeq(address.address_un)
|
|
|
|
res.data.finish()
|
|
|
|
ok(res)
|
2019-10-10 04:16:02 +00:00
|
|
|
|
2018-11-27 12:16:04 +00:00
|
|
|
proc isEmpty*(ma: MultiAddress): bool =
|
|
|
|
## Returns ``true``, if MultiAddress ``ma`` is empty or non initialized.
|
|
|
|
result = len(ma.data) == 0
|
|
|
|
|
2020-05-31 14:22:49 +00:00
|
|
|
proc concat*(m1, m2: MultiAddress): MaResult[MultiAddress] =
|
|
|
|
var res: MultiAddress
|
|
|
|
res.data = initVBuffer()
|
|
|
|
res.data.buffer = m1.data.buffer & m2.data.buffer
|
|
|
|
if not res.validate():
|
|
|
|
err("multiaddress: Incorrect MultiAddress!")
|
|
|
|
else:
|
|
|
|
ok(res)
|
|
|
|
|
|
|
|
proc append*(m1: var MultiAddress, m2: MultiAddress): MaResult[void] =
|
|
|
|
m1.data.buffer &= m2.data.buffer
|
|
|
|
if not m1.validate():
|
|
|
|
err("multiaddress: Incorrect MultiAddress!")
|
|
|
|
else:
|
|
|
|
ok()
|
|
|
|
|
2024-09-10 13:24:58 +00:00
|
|
|
proc `&`*(m1, m2: MultiAddress): MultiAddress {.raises: [MaError].} =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Concatenates two addresses ``m1`` and ``m2``, and returns result.
|
|
|
|
##
|
|
|
|
## This procedure performs validation of concatenated result and can raise
|
|
|
|
## exception on error.
|
2024-09-10 13:24:58 +00:00
|
|
|
concat(m1, m2).valueOr:
|
|
|
|
raise maErr error
|
2018-11-27 12:16:04 +00:00
|
|
|
|
2024-09-10 13:24:58 +00:00
|
|
|
proc `&=`*(m1: var MultiAddress, m2: MultiAddress) {.raises: [MaError].} =
|
2018-11-27 12:16:04 +00:00
|
|
|
## Concatenates two addresses ``m1`` and ``m2``.
|
|
|
|
##
|
|
|
|
## This procedure performs validation of concatenated result and can raise
|
|
|
|
## exception on error.
|
2024-09-10 13:24:58 +00:00
|
|
|
m1.append(m2).isOkOr:
|
|
|
|
raise maErr error
|
2018-12-29 12:44:27 +00:00
|
|
|
|
2021-08-18 07:40:12 +00:00
|
|
|
proc `==`*(m1: var MultiAddress, m2: MultiAddress): bool =
|
|
|
|
## Check of two MultiAddress are equal
|
|
|
|
m1.data == m2.data
|
|
|
|
|
2019-03-20 09:41:37 +00:00
|
|
|
proc matchPart(pat: MaPattern, protos: seq[MultiCodec]): MaPatResult =
|
|
|
|
var empty: seq[MultiCodec]
|
|
|
|
var pcs = protos
|
|
|
|
if pat.operator == Or:
|
2021-08-03 13:48:03 +00:00
|
|
|
result = MaPatResult(flag: false, rem: empty)
|
2019-03-20 09:41:37 +00:00
|
|
|
for a in pat.args:
|
|
|
|
let res = a.matchPart(pcs)
|
|
|
|
if res.flag:
|
2021-08-03 13:48:03 +00:00
|
|
|
#Greedy Or
|
|
|
|
if result.flag == false or result.rem.len > res.rem.len:
|
|
|
|
result = res
|
2019-03-20 09:41:37 +00:00
|
|
|
elif pat.operator == And:
|
|
|
|
if len(pcs) < len(pat.args):
|
|
|
|
return MaPatResult(flag: false, rem: empty)
|
|
|
|
for i in 0 ..< len(pat.args):
|
|
|
|
let res = pat.args[i].matchPart(pcs)
|
|
|
|
if not res.flag:
|
|
|
|
return MaPatResult(flag: false, rem: res.rem)
|
|
|
|
pcs = res.rem
|
|
|
|
result = MaPatResult(flag: true, rem: pcs)
|
|
|
|
elif pat.operator == Eq:
|
|
|
|
if len(pcs) == 0:
|
|
|
|
return MaPatResult(flag: false, rem: empty)
|
|
|
|
if pcs[0] == pat.value:
|
|
|
|
return MaPatResult(flag: true, rem: pcs[1 ..^ 1])
|
|
|
|
result = MaPatResult(flag: false, rem: empty)
|
|
|
|
|
|
|
|
proc match*(pat: MaPattern, address: MultiAddress): bool =
|
|
|
|
## Match full ``address`` using pattern ``pat`` and return ``true`` if
|
|
|
|
## ``address`` satisfies pattern.
|
2023-06-28 14:44:58 +00:00
|
|
|
let protos = address.protocols().valueOr:
|
|
|
|
return false
|
|
|
|
let res = matchPart(pat, protos)
|
2020-05-31 14:22:49 +00:00
|
|
|
res.flag and (len(res.rem) == 0)
|
2019-03-20 09:41:37 +00:00
|
|
|
|
|
|
|
proc matchPartial*(pat: MaPattern, address: MultiAddress): bool =
|
|
|
|
## Match prefix part of ``address`` using pattern ``pat`` and return
|
|
|
|
## ``true`` if ``address`` starts with pattern.
|
2023-06-28 14:44:58 +00:00
|
|
|
let protos = address.protocols().valueOr:
|
|
|
|
return false
|
|
|
|
let res = matchPart(pat, protos)
|
2020-05-31 14:22:49 +00:00
|
|
|
res.flag
|
2019-03-20 09:41:37 +00:00
|
|
|
|
|
|
|
proc `$`*(pat: MaPattern): string =
|
|
|
|
## Return pattern ``pat`` as string.
|
|
|
|
var sub = newSeq[string]()
|
|
|
|
for a in pat.args:
|
|
|
|
sub.add($a)
|
|
|
|
if pat.operator == And:
|
|
|
|
result = sub.join("/")
|
|
|
|
elif pat.operator == Or:
|
|
|
|
result = "(" & sub.join("|") & ")"
|
|
|
|
elif pat.operator == Eq:
|
|
|
|
result = $pat.value
|
2020-07-13 12:43:07 +00:00
|
|
|
|
2022-10-30 07:49:02 +00:00
|
|
|
proc bytes*(value: MultiAddress): seq[byte] =
|
|
|
|
value.data.buffer
|
|
|
|
|
2020-07-13 12:43:07 +00:00
|
|
|
proc write*(pb: var ProtoBuffer, field: int, value: MultiAddress) {.inline.} =
|
|
|
|
write(pb, field, value.data.buffer)
|
|
|
|
|
2021-11-24 20:03:40 +00:00
|
|
|
proc getField*(
|
|
|
|
pb: ProtoBuffer, field: int, value: var MultiAddress
|
2020-07-15 08:25:39 +00:00
|
|
|
): ProtoResult[bool] {.inline.} =
|
2020-07-13 12:43:07 +00:00
|
|
|
var buffer: seq[byte]
|
2020-07-15 08:25:39 +00:00
|
|
|
let res = ?pb.getField(field, buffer)
|
|
|
|
if not (res):
|
|
|
|
ok(false)
|
2020-07-13 12:43:07 +00:00
|
|
|
else:
|
2024-02-22 14:57:11 +00:00
|
|
|
value = MultiAddress.init(buffer).valueOr:
|
|
|
|
return err(ProtoError.IncorrectBlob)
|
2023-06-28 14:44:58 +00:00
|
|
|
ok(true)
|
2020-07-13 12:43:07 +00:00
|
|
|
|
2021-10-25 08:26:32 +00:00
|
|
|
proc getRepeatedField*(
|
2020-07-15 08:25:39 +00:00
|
|
|
pb: ProtoBuffer, field: int, value: var seq[MultiAddress]
|
|
|
|
): ProtoResult[bool] {.inline.} =
|
2024-02-22 14:57:11 +00:00
|
|
|
## Read repeated field from protobuf message. ``field`` is field number.
|
|
|
|
## If the message is malformed, an error is returned. If field is not present
|
|
|
|
## in message, then ``ok(false)`` is returned and value is empty. If field is
|
|
|
|
## present, but no items could be parsed, then
|
|
|
|
## ``err(ProtoError.IncorrectBlob)`` is returned and value is empty.
|
|
|
|
## If field is present and some item could be parsed, then ``true`` is
|
|
|
|
## returned and value contains the parsed values.
|
2020-07-13 12:43:07 +00:00
|
|
|
var items: seq[seq[byte]]
|
|
|
|
value.setLen(0)
|
2020-07-15 08:25:39 +00:00
|
|
|
let res = ?pb.getRepeatedField(field, items)
|
|
|
|
if not (res):
|
|
|
|
ok(false)
|
|
|
|
else:
|
|
|
|
for item in items:
|
2023-06-28 14:44:58 +00:00
|
|
|
let ma = MultiAddress.init(item).valueOr:
|
|
|
|
debug "Unsupported MultiAddress in blob", ma = item
|
|
|
|
continue
|
|
|
|
|
|
|
|
value.add(ma)
|
2023-04-14 12:05:32 +00:00
|
|
|
if value.len == 0:
|
|
|
|
err(ProtoError.IncorrectBlob)
|
|
|
|
else:
|
|
|
|
ok(true)
|