mirror of
https://github.com/waku-org/nwaku.git
synced 2025-02-20 19:08:29 +00:00
Filter v2 rest api support implemented Filter rest api documentation updated with v1 and v2 interface support. Separated legacy filter rest interface Fix code and tests of v2 Filter rest api Filter v2 message push test added Applied autoshard to Filter V2 Redesigned FilterPushHandling, code style, catch up apps and tests with filter v2 interface changes Rename of FilterV1SubscriptionsRequest to FilterLegacySubscribeRequest, fix broken chat2 app, fix tests Changed Filter v2 push handler subscription to simple register Separate node's filterUnsubscribe and filterUnsubscribeAll
254 lines
8.0 KiB
Nim
254 lines
8.0 KiB
Nim
when (NimMajor, NimMinor) < (1, 4):
|
|
{.push raises: [Defect].}
|
|
else:
|
|
{.push raises: [].}
|
|
|
|
import
|
|
std/[options, sequtils, strutils, uri],
|
|
stew/results,
|
|
stew/shims/net,
|
|
chronos,
|
|
eth/keys,
|
|
eth/p2p/discoveryv5/enr,
|
|
libp2p/crypto/crypto,
|
|
libp2p/crypto/secp,
|
|
libp2p/errors,
|
|
libp2p/multiaddress,
|
|
libp2p/multicodec,
|
|
libp2p/peerid,
|
|
libp2p/peerinfo,
|
|
libp2p/routing_record,
|
|
json_serialization
|
|
|
|
type
|
|
Connectedness* = enum
|
|
# NotConnected: default state for a new peer. No connection and no further information on connectedness.
|
|
NotConnected,
|
|
# CannotConnect: attempted to connect to peer, but failed.
|
|
CannotConnect,
|
|
# CanConnect: was recently connected to peer and disconnected gracefully.
|
|
CanConnect,
|
|
# Connected: actively connected to peer.
|
|
Connected
|
|
|
|
PeerOrigin* = enum
|
|
UnknownOrigin,
|
|
Discv5,
|
|
Static,
|
|
PeerExcahnge,
|
|
Dns
|
|
|
|
PeerDirection* = enum
|
|
UnknownDirection,
|
|
Inbound,
|
|
Outbound
|
|
|
|
type RemotePeerInfo* = ref object
|
|
peerId*: PeerID
|
|
addrs*: seq[MultiAddress]
|
|
enr*: Option[enr.Record]
|
|
protocols*: seq[string]
|
|
|
|
agent*: string
|
|
protoVersion*: string
|
|
publicKey*: crypto.PublicKey
|
|
connectedness*: Connectedness
|
|
disconnectTime*: int64
|
|
origin*: PeerOrigin
|
|
direction*: PeerDirection
|
|
lastFailedConn*: Moment
|
|
numberFailedConn*: int
|
|
|
|
func `$`*(remotePeerInfo: RemotePeerInfo): string =
|
|
$remotePeerInfo.peerId
|
|
|
|
proc writeValue*(w: var JsonWriter, value: RemotePeerInfo) {.inline, raises: [IOError].} =
|
|
w.writeValue $value
|
|
|
|
proc init*(
|
|
T: typedesc[RemotePeerInfo],
|
|
peerId: PeerID,
|
|
addrs: seq[MultiAddress] = @[],
|
|
enr: Option[enr.Record] = none(enr.Record),
|
|
protocols: seq[string] = @[]): T =
|
|
|
|
RemotePeerInfo(peerId: peerId, addrs: addrs, enr: enr, protocols: protocols)
|
|
|
|
proc init*(T: typedesc[RemotePeerInfo],
|
|
peerId: string,
|
|
addrs: seq[MultiAddress] = @[],
|
|
enr: Option[enr.Record] = none(enr.Record),
|
|
protocols: seq[string] = @[]): T
|
|
{.raises: [Defect, ResultError[cstring], LPError].} =
|
|
|
|
let peerId = PeerID.init(peerId).tryGet()
|
|
RemotePeerInfo(peerId: peerId, addrs: addrs, enr: enr, protocols: protocols)
|
|
|
|
|
|
## Parse
|
|
|
|
proc validWireAddr*(ma: MultiAddress): bool =
|
|
## Check if wire Address is supported
|
|
const
|
|
ValidTransports = mapOr(TCP, WebSockets)
|
|
return ValidTransports.match(ma)
|
|
|
|
proc parsePeerInfo*(peer: RemotePeerInfo): Result[RemotePeerInfo, string] =
|
|
## Parses a fully qualified peer multiaddr, in the
|
|
## format `(ip4|ip6)/tcp/p2p`, into dialable PeerInfo
|
|
ok(peer)
|
|
|
|
proc parsePeerInfo*(peer: MultiAddress): Result[RemotePeerInfo, string] =
|
|
## Parses a fully qualified peer multiaddr, in the
|
|
## format `(ip4|ip6)/tcp/p2p`, into dialable PeerInfo
|
|
var p2pPart: MultiAddress
|
|
var wireAddr = MultiAddress()
|
|
for addrPart in peer.items():
|
|
case addrPart[].protoName()[]
|
|
# All protocols listed here: https://github.com/multiformats/multiaddr/blob/b746a7d014e825221cc3aea6e57a92d78419990f/protocols.csv
|
|
of "p2p":
|
|
p2pPart = ? addrPart.mapErr(proc(err: string): string = "Error getting p2pPart [" & err & "]")
|
|
of "ip4", "ip6", "dns", "dnsaddr", "dns4", "dns6", "tcp", "ws", "wss":
|
|
let val = ? addrPart.mapErr(proc(err: string): string = "Error getting addrPart [" & err & "]")
|
|
? wireAddr.append(val).mapErr(proc(err: string): string = "Error appending addrPart [" & err & "]")
|
|
|
|
let p2pPartStr = p2pPart.toString().get()
|
|
if not p2pPartStr.contains("/"):
|
|
let msg = "Error in parsePeerInfo: p2p part should contain / [p2pPartStr:" & p2pPartStr & "] [peer:" & $peer & "]"
|
|
return err(msg)
|
|
|
|
let peerId = ? PeerID.init(p2pPartStr.split("/")[^1])
|
|
.mapErr(proc(e: cstring): string = $e)
|
|
|
|
if not wireAddr.validWireAddr():
|
|
return err("invalid multiaddress: no supported transport found")
|
|
|
|
return ok(RemotePeerInfo.init(peerId, @[wireAddr]))
|
|
|
|
proc parsePeerInfo*(peer: string): Result[RemotePeerInfo, string] =
|
|
## Parses a fully qualified peer multiaddr, in the
|
|
## format `(ip4|ip6)/tcp/p2p`, into dialable PeerInfo
|
|
let multiAddr = ? MultiAddress.init(peer)
|
|
.mapErr(proc(err: string): string = "MultiAddress.init [" & err & "]")
|
|
|
|
parsePeerInfo(multiAddr)
|
|
|
|
|
|
func getTransportProtocol(typedR: TypedRecord): Option[IpTransportProtocol] =
|
|
if typedR.tcp6.isSome() or typedR.tcp.isSome():
|
|
return some(IpTransportProtocol.tcpProtocol)
|
|
|
|
if typedR.udp6.isSome() or typedR.udp.isSome():
|
|
return some(IpTransportProtocol.udpProtocol)
|
|
|
|
return none(IpTransportProtocol)
|
|
|
|
proc parseUrlPeerAddr*(peerAddr: Option[string]): Result[Option[RemotePeerInfo], string] =
|
|
# Checks whether the peerAddr parameter represents a valid p2p multiaddress.
|
|
# The param must be in the format `(ip4|ip6)/tcp/p2p/$peerId` but URL-encoded
|
|
if not peerAddr.isSome() or peerAddr.get() == "":
|
|
return ok(none(RemotePeerInfo))
|
|
|
|
let parsedAddr = decodeUrl(peerAddr.get())
|
|
let parsedPeerInfo = parsePeerInfo(parsedAddr)
|
|
if parsedPeerInfo.isErr():
|
|
return err("Failed parsing remote peer info [" & parsedPeerInfo.error & "]")
|
|
|
|
return ok(some(parsedPeerInfo.value))
|
|
|
|
proc toRemotePeerInfo*(enr: enr.Record): Result[RemotePeerInfo, cstring] =
|
|
## Converts an ENR to dialable RemotePeerInfo
|
|
let typedR = ? enr.toTypedRecord()
|
|
if not typedR.secp256k1.isSome():
|
|
return err("enr: no secp256k1 key in record")
|
|
|
|
let
|
|
pubKey = ? keys.PublicKey.fromRaw(typedR.secp256k1.get())
|
|
peerId = ? PeerID.init(crypto.PublicKey(scheme: Secp256k1,
|
|
skkey: secp.SkPublicKey(pubKey)))
|
|
|
|
let transportProto = getTransportProtocol(typedR)
|
|
if transportProto.isNone():
|
|
return err("enr: could not determine transport protocol")
|
|
|
|
var addrs = newSeq[MultiAddress]()
|
|
case transportProto.get()
|
|
of tcpProtocol:
|
|
if typedR.ip.isSome() and typedR.tcp.isSome():
|
|
let ip = ipv4(typedR.ip.get())
|
|
addrs.add MultiAddress.init(ip, tcpProtocol, Port(typedR.tcp.get()))
|
|
|
|
if typedR.ip6.isSome():
|
|
let ip = ipv6(typedR.ip6.get())
|
|
if typedR.tcp6.isSome():
|
|
addrs.add MultiAddress.init(ip, tcpProtocol, Port(typedR.tcp6.get()))
|
|
elif typedR.tcp.isSome():
|
|
addrs.add MultiAddress.init(ip, tcpProtocol, Port(typedR.tcp.get()))
|
|
else:
|
|
discard
|
|
|
|
of udpProtocol:
|
|
if typedR.ip.isSome() and typedR.udp.isSome():
|
|
let ip = ipv4(typedR.ip.get())
|
|
addrs.add MultiAddress.init(ip, udpProtocol, Port(typedR.udp.get()))
|
|
|
|
if typedR.ip6.isSome():
|
|
let ip = ipv6(typedR.ip6.get())
|
|
if typedR.udp6.isSome():
|
|
addrs.add MultiAddress.init(ip, udpProtocol, Port(typedR.udp6.get()))
|
|
elif typedR.udp.isSome():
|
|
addrs.add MultiAddress.init(ip, udpProtocol, Port(typedR.udp.get()))
|
|
else:
|
|
discard
|
|
|
|
if addrs.len == 0:
|
|
return err("enr: no addresses in record")
|
|
|
|
return ok(RemotePeerInfo.init(peerId, addrs, some(enr)))
|
|
|
|
converter toRemotePeerInfo*(peerRecord: PeerRecord): RemotePeerInfo =
|
|
## Converts peer records to dialable RemotePeerInfo
|
|
## Useful if signed peer records have been received in an exchange
|
|
RemotePeerInfo.init(
|
|
peerRecord.peerId,
|
|
peerRecord.addresses.mapIt(it.address)
|
|
)
|
|
|
|
converter toRemotePeerInfo*(peerInfo: PeerInfo): RemotePeerInfo =
|
|
## Converts the local peerInfo to dialable RemotePeerInfo
|
|
## Useful for testing or internal connections
|
|
RemotePeerInfo.init(
|
|
peerInfo.peerId,
|
|
peerInfo.listenAddrs,
|
|
none(enr.Record),
|
|
peerInfo.protocols
|
|
)
|
|
|
|
proc hasProtocol*(ma: MultiAddress, proto: string): bool =
|
|
## Checks if a multiaddress contains a given protocol
|
|
## Useful for filtering multiaddresses based on their protocols
|
|
##
|
|
## Returns ``true`` if ``ma`` contains protocol ``proto``.
|
|
let proto = MultiCodec.codec(proto)
|
|
|
|
let protos = ma.protocols()
|
|
if protos.isErr():
|
|
return false
|
|
|
|
return protos.get().anyIt(it == proto)
|
|
|
|
func hasUdpPort*(peer: RemotePeerInfo): bool =
|
|
if peer.enr.isNone():
|
|
return false
|
|
|
|
let
|
|
enr = peer.enr.get()
|
|
typedEnrRes = enr.toTypedRecord()
|
|
|
|
if typedEnrRes.isErr():
|
|
return false
|
|
|
|
let typedEnr = typedEnrRes.get()
|
|
typedEnr.udp.isSome() or typedEnr.udp6.isSome()
|
|
|