mirror of
https://github.com/waku-org/nwaku.git
synced 2025-02-12 15:06:38 +00:00
deploy: c5e75801495ea444524f8de92c0726c9c9c00c77
This commit is contained in:
parent
58b9629e0e
commit
e1c3fca7ae
6
Makefile
6
Makefile
@ -47,7 +47,7 @@ GIT_SUBMODULE_UPDATE := git submodule update --init --recursive
|
||||
else # "variables.mk" was included. Business as usual until the end of this file.
|
||||
|
||||
# default target, because it's the first one that doesn't start with '.'
|
||||
all: | wakunode1 sim1 example1 wakunode2 sim2 example2 chat2 bridge
|
||||
all: | wakunode1 sim1 example1 wakunode2 sim2 example2 chat2 bridge chat2bridge
|
||||
|
||||
# must be included after the default target
|
||||
-include $(BUILD_SYSTEM_DIR)/makefiles/targets.mk
|
||||
@ -141,6 +141,10 @@ bridge: | build deps
|
||||
echo -e $(BUILD_MSG) "build/$@" && \
|
||||
$(ENV_SCRIPT) nim bridge $(NIM_PARAMS) waku.nims
|
||||
|
||||
chat2bridge: | build deps
|
||||
echo -e $(BUILD_MSG) "build/$@" && \
|
||||
$(ENV_SCRIPT) nim chat2bridge $(NIM_PARAMS) waku.nims
|
||||
|
||||
# Builds and run the test suite (Waku v1 + v2)
|
||||
test: | test1 test2
|
||||
|
||||
|
@ -35,9 +35,8 @@ const Help = """
|
||||
|
||||
const
|
||||
PayloadV1* {.booldefine.} = false
|
||||
DefaultTopic = "/waku/2/default-waku/proto"
|
||||
|
||||
DefaultContentTopic = ContentTopic("dingpu")
|
||||
DefaultTopic* = "/waku/2/default-waku/proto"
|
||||
DefaultContentTopic* = ContentTopic("dingpu")
|
||||
|
||||
# XXX Connected is a bit annoying, because incoming connections don't trigger state change
|
||||
# Could poll connection pool or something here, I suppose
|
||||
|
230
examples/v2/matterbridge/chat2bridge.nim
Normal file
230
examples/v2/matterbridge/chat2bridge.nim
Normal file
@ -0,0 +1,230 @@
|
||||
import
|
||||
std/[tables, times, strutils],
|
||||
chronos, confutils, chronicles, chronicles/topics_registry, metrics,
|
||||
stew/[byteutils, endians2],
|
||||
stew/shims/net as stewNet, json_rpc/rpcserver,
|
||||
# Matterbridge client imports
|
||||
../../../waku/common/utils/matterbridge_client,
|
||||
# Waku v2 imports
|
||||
libp2p/crypto/crypto,
|
||||
../../../waku/v2/protocol/waku_filter/waku_filter_types,
|
||||
../../../waku/v2/node/wakunode2,
|
||||
# Chat 2 imports
|
||||
../chat2,
|
||||
# Common cli config
|
||||
./config_chat2bridge
|
||||
|
||||
declarePublicCounter chat2_mb_transfers, "Number of messages transferred between chat2 and Matterbridge", ["type"]
|
||||
|
||||
logScope:
|
||||
topics = "chat2bridge"
|
||||
|
||||
##################
|
||||
# Default values #
|
||||
##################
|
||||
|
||||
const
|
||||
DefaultTopic* = chat2.DefaultTopic
|
||||
DefaultContentTopic* = chat2.DefaultContentTopic
|
||||
|
||||
#########
|
||||
# Types #
|
||||
#########
|
||||
|
||||
type
|
||||
Chat2MatterBridge* = ref object of RootObj
|
||||
mbClient*: MatterbridgeClient
|
||||
nodev2*: WakuNode
|
||||
running: bool
|
||||
pollPeriod: chronos.Duration
|
||||
|
||||
MbMessageHandler* = proc (jsonNode: JsonNode) {.gcsafe.}
|
||||
|
||||
###################
|
||||
# Helper funtions #
|
||||
###################S
|
||||
|
||||
proc toWakuMessage(jsonNode: JsonNode): WakuMessage =
|
||||
# Translates a Matterbridge API JSON response to a Waku v2 message
|
||||
let msgFields = jsonNode.getFields()
|
||||
|
||||
# @TODO error handling here - verify expected fields
|
||||
|
||||
let chat2pb = Chat2Message(timestamp: getTime().toUnix(), # @TODO use provided timestamp
|
||||
nick: msgFields["username"].getStr(),
|
||||
payload: msgFields["text"].getStr().toBytes()).encode()
|
||||
|
||||
WakuMessage(payload: chat2pb.buffer,
|
||||
contentTopic: DefaultContentTopic,
|
||||
version: 0)
|
||||
|
||||
proc toChat2(cmb: Chat2MatterBridge, jsonNode: JsonNode) {.async.} =
|
||||
chat2_mb_transfers.inc(labelValues = ["v1_to_v2"])
|
||||
|
||||
trace "Post Matterbridge message to chat2"
|
||||
|
||||
await cmb.nodev2.publish(DefaultTopic, jsonNode.toWakuMessage())
|
||||
|
||||
proc toMatterbridge(cmb: Chat2MatterBridge, msg: WakuMessage) {.gcsafe.} =
|
||||
chat2_mb_transfers.inc(labelValues = ["v2_to_v1"])
|
||||
|
||||
trace "Post chat2 message to Matterbridge"
|
||||
|
||||
let chat2Msg = Chat2Message.init(msg.payload)
|
||||
|
||||
assert chat2Msg.isOk
|
||||
|
||||
cmb.mbClient.postMessage(text = string.fromBytes(chat2Msg[].payload),
|
||||
username = chat2Msg[].nick)
|
||||
|
||||
proc pollMatterbridge(cmb: Chat2MatterBridge, handler: MbMessageHandler) {.async.} =
|
||||
while cmb.running:
|
||||
for jsonNode in cmb.mbClient.getMessages():
|
||||
handler(jsonNode)
|
||||
|
||||
await sleepAsync(cmb.pollPeriod)
|
||||
|
||||
##############
|
||||
# Public API #
|
||||
##############
|
||||
proc new*(T: type Chat2MatterBridge,
|
||||
# Matterbridge initialisation
|
||||
mbHostUri: string,
|
||||
mbGateway: string,
|
||||
# NodeV2 initialisation
|
||||
nodev2Key: crypto.PrivateKey,
|
||||
nodev2BindIp: ValidIpAddress, nodev2BindPort: Port,
|
||||
nodev2ExtIp = none[ValidIpAddress](), nodev2ExtPort = none[Port]()): T =
|
||||
|
||||
# Setup Matterbridge
|
||||
let
|
||||
mbClient = MatterbridgeClient.new(mbHostUri, mbGateway)
|
||||
|
||||
# Setup Waku v2 node
|
||||
let
|
||||
nodev2 = WakuNode.init(nodev2Key,
|
||||
nodev2BindIp, nodev2BindPort,
|
||||
nodev2ExtIp, nodev2ExtPort)
|
||||
|
||||
return Chat2MatterBridge(mbClient: mbClient, nodev2: nodev2, running: false, pollPeriod: chronos.seconds(1))
|
||||
|
||||
proc start*(cmb: Chat2MatterBridge) {.async.} =
|
||||
info "Starting Chat2MatterBridge"
|
||||
|
||||
cmb.running = true
|
||||
|
||||
debug "Start polling Matterbridge"
|
||||
|
||||
# Start Matterbridge polling (@TODO: use streaming interface)
|
||||
proc mbHandler(jsonNode: JsonNode) {.gcsafe.} =
|
||||
trace "Bridging message from Matterbridge to chat2", jsonNode=jsonNode
|
||||
waitFor cmb.toChat2(jsonNode)
|
||||
|
||||
asyncSpawn cmb.pollMatterbridge(mbHandler)
|
||||
|
||||
# Start Waku v2 node
|
||||
debug "Start listening on Waku v2"
|
||||
await cmb.nodev2.start()
|
||||
|
||||
cmb.nodev2.mountRelay() # Always mount relay for bridge
|
||||
|
||||
# Bridging
|
||||
# Handle messages on Waku v2 and bridge to Matterbridge
|
||||
proc relayHandler(pubsubTopic: string, data: seq[byte]) {.async, gcsafe.} =
|
||||
let msg = WakuMessage.init(data)
|
||||
if msg.isOk():
|
||||
trace "Bridging message from Chat2 to Matterbridge", msg=msg[]
|
||||
cmb.toMatterbridge(msg[])
|
||||
|
||||
cmb.nodev2.subscribe(DefaultTopic, relayHandler)
|
||||
|
||||
proc stop*(cmb: Chat2MatterBridge) {.async.} =
|
||||
info "Stopping Chat2MatterBridge"
|
||||
|
||||
cmb.running = false
|
||||
|
||||
await cmb.nodev2.stop()
|
||||
|
||||
when isMainModule:
|
||||
import
|
||||
../../../waku/common/utils/nat,
|
||||
../../../waku/v2/node/jsonrpc/[debug_api,
|
||||
filter_api,
|
||||
relay_api,
|
||||
store_api]
|
||||
|
||||
proc startV2Rpc(node: WakuNode, rpcServer: RpcHttpServer, conf: Chat2MatterbridgeConf) =
|
||||
installDebugApiHandlers(node, rpcServer)
|
||||
|
||||
# Install enabled API handlers:
|
||||
if conf.relay:
|
||||
let topicCache = newTable[string, seq[WakuMessage]]()
|
||||
installRelayApiHandlers(node, rpcServer, topicCache)
|
||||
|
||||
if conf.filter:
|
||||
let messageCache = newTable[ContentTopic, seq[WakuMessage]]()
|
||||
installFilterApiHandlers(node, rpcServer, messageCache)
|
||||
|
||||
if conf.store:
|
||||
installStoreApiHandlers(node, rpcServer)
|
||||
|
||||
rpcServer.start()
|
||||
|
||||
let
|
||||
rng = newRng()
|
||||
conf = Chat2MatterbridgeConf.load()
|
||||
|
||||
if conf.logLevel != LogLevel.NONE:
|
||||
setLogLevel(conf.logLevel)
|
||||
|
||||
# Load address configuration
|
||||
let
|
||||
(nodev2ExtIp, nodev2ExtPort, _) = setupNat(conf.nat, clientId,
|
||||
Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
|
||||
Port(uint16(conf.udpPort) + conf.portsShift))
|
||||
|
||||
let
|
||||
bridge = Chat2Matterbridge.new(
|
||||
mbHostUri = conf.mbHostUri,
|
||||
mbGateway = conf.mbGateway,
|
||||
nodev2Key = conf.nodeKeyv2,
|
||||
nodev2BindIp = conf.listenAddress, nodev2BindPort = Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
|
||||
nodev2ExtIp = nodev2ExtIp, nodev2ExtPort = nodev2ExtPort)
|
||||
|
||||
waitFor bridge.start()
|
||||
|
||||
# Now load rest of config
|
||||
# Mount configured Waku v2 protocols
|
||||
if conf.store:
|
||||
mountStore(bridge.nodev2)
|
||||
|
||||
if conf.filter:
|
||||
mountFilter(bridge.nodev2)
|
||||
|
||||
if conf.staticnodesv2.len > 0:
|
||||
waitFor connectToNodes(bridge.nodev2, conf.staticnodesv2)
|
||||
|
||||
if conf.storenode != "":
|
||||
setStorePeer(bridge.nodev2, conf.storenode)
|
||||
|
||||
if conf.filternode != "":
|
||||
setFilterPeer(bridge.nodev2, conf.filternode)
|
||||
|
||||
if conf.rpc:
|
||||
let ta = initTAddress(conf.rpcAddress,
|
||||
Port(conf.rpcPort + conf.portsShift))
|
||||
var rpcServer = newRpcHttpServer([ta])
|
||||
# Waku v2 rpc
|
||||
startV2Rpc(bridge.nodev2, rpcServer, conf)
|
||||
|
||||
rpcServer.start()
|
||||
|
||||
when defined(insecure):
|
||||
if conf.metricsServer:
|
||||
let
|
||||
address = conf.metricsServerAddress
|
||||
port = conf.metricsServerPort + conf.portsShift
|
||||
info "Starting metrics HTTP server", address, port
|
||||
metrics.startHttpServer($address, Port(port))
|
||||
|
||||
runForever()
|
149
examples/v2/matterbridge/config_chat2bridge.nim
Normal file
149
examples/v2/matterbridge/config_chat2bridge.nim
Normal file
@ -0,0 +1,149 @@
|
||||
import
|
||||
confutils, confutils/defs, confutils/std/net, chronicles, chronos,
|
||||
libp2p/crypto/[crypto, secp],
|
||||
eth/keys
|
||||
|
||||
type
|
||||
Chat2MatterbridgeConf* = object
|
||||
logLevel* {.
|
||||
desc: "Sets the log level"
|
||||
defaultValue: LogLevel.INFO
|
||||
name: "log-level" .}: LogLevel
|
||||
|
||||
listenAddress* {.
|
||||
defaultValue: defaultListenAddress(config)
|
||||
desc: "Listening address for the LibP2P traffic"
|
||||
name: "listen-address"}: ValidIpAddress
|
||||
|
||||
libp2pTcpPort* {.
|
||||
desc: "Libp2p TCP listening port (for Waku v2)"
|
||||
defaultValue: 9000
|
||||
name: "libp2p-tcp-port" .}: uint16
|
||||
|
||||
udpPort* {.
|
||||
desc: "UDP listening port"
|
||||
defaultValue: 9000
|
||||
name: "udp-port" .}: uint16
|
||||
|
||||
portsShift* {.
|
||||
desc: "Add a shift to all default port numbers"
|
||||
defaultValue: 0
|
||||
name: "ports-shift" .}: uint16
|
||||
|
||||
nat* {.
|
||||
desc: "Specify method to use for determining public address. " &
|
||||
"Must be one of: any, none, upnp, pmp, extip:<IP>"
|
||||
defaultValue: "any" .}: string
|
||||
|
||||
rpc* {.
|
||||
desc: "Enable Waku RPC server"
|
||||
defaultValue: false
|
||||
name: "rpc" .}: bool
|
||||
|
||||
rpcAddress* {.
|
||||
desc: "Listening address of the RPC server",
|
||||
defaultValue: ValidIpAddress.init("127.0.0.1")
|
||||
name: "rpc-address" }: ValidIpAddress
|
||||
|
||||
rpcPort* {.
|
||||
desc: "Listening port of the RPC server"
|
||||
defaultValue: 8545
|
||||
name: "rpc-port" .}: uint16
|
||||
|
||||
metricsServer* {.
|
||||
desc: "Enable the metrics server"
|
||||
defaultValue: false
|
||||
name: "metrics-server" .}: bool
|
||||
|
||||
metricsServerAddress* {.
|
||||
desc: "Listening address of the metrics server"
|
||||
defaultValue: ValidIpAddress.init("127.0.0.1")
|
||||
name: "metrics-server-address" }: ValidIpAddress
|
||||
|
||||
metricsServerPort* {.
|
||||
desc: "Listening HTTP port of the metrics server"
|
||||
defaultValue: 8008
|
||||
name: "metrics-server-port" .}: uint16
|
||||
|
||||
### Waku v2 options
|
||||
staticnodesv2* {.
|
||||
desc: "Multiaddr of peer to directly connect with. Argument may be repeated"
|
||||
name: "staticnodev2" }: seq[string]
|
||||
|
||||
nodekeyv2* {.
|
||||
desc: "P2P node private key as hex"
|
||||
defaultValue: crypto.PrivateKey.random(Secp256k1, newRng()[]).tryGet()
|
||||
name: "nodekeyv2" }: crypto.PrivateKey
|
||||
|
||||
topics* {.
|
||||
desc: "Default topics to subscribe to (space separated list)"
|
||||
defaultValue: "/waku/2/default-waku/proto"
|
||||
name: "topics" .}: string
|
||||
|
||||
store* {.
|
||||
desc: "Flag whether to start store protocol",
|
||||
defaultValue: true
|
||||
name: "store" }: bool
|
||||
|
||||
filter* {.
|
||||
desc: "Flag whether to start filter protocol",
|
||||
defaultValue: false
|
||||
name: "filter" }: bool
|
||||
|
||||
relay* {.
|
||||
desc: "Flag whether to start relay protocol",
|
||||
defaultValue: true
|
||||
name: "relay" }: bool
|
||||
|
||||
storenode* {.
|
||||
desc: "Multiaddr of peer to connect with for waku store protocol"
|
||||
defaultValue: ""
|
||||
name: "storenode" }: string
|
||||
|
||||
filternode* {.
|
||||
desc: "Multiaddr of peer to connect with for waku filter protocol"
|
||||
defaultValue: ""
|
||||
name: "filternode" }: string
|
||||
|
||||
# Matterbridge options
|
||||
mbHostUri* {.
|
||||
desc: "Matterbridge host API address"
|
||||
defaultValue: "http://127.0.0.1:4242"
|
||||
name: "mb-host-uri" }: string
|
||||
|
||||
mbGateway* {.
|
||||
desc: "Matterbridge gateway"
|
||||
defaultValue: "gateway1"
|
||||
name: "mb-gateway" }: string
|
||||
|
||||
proc parseCmdArg*(T: type keys.KeyPair, p: TaintedString): T =
|
||||
try:
|
||||
let privkey = keys.PrivateKey.fromHex(string(p)).tryGet()
|
||||
result = privkey.toKeyPair()
|
||||
except CatchableError:
|
||||
raise newException(ConfigurationError, "Invalid private key")
|
||||
|
||||
proc completeCmdArg*(T: type keys.KeyPair, val: TaintedString): seq[string] =
|
||||
return @[]
|
||||
|
||||
proc parseCmdArg*(T: type crypto.PrivateKey, p: TaintedString): T =
|
||||
let key = SkPrivateKey.init(p)
|
||||
if key.isOk():
|
||||
crypto.PrivateKey(scheme: Secp256k1, skkey: key.get())
|
||||
else:
|
||||
raise newException(ConfigurationError, "Invalid private key")
|
||||
|
||||
proc completeCmdArg*(T: type crypto.PrivateKey, val: TaintedString): seq[string] =
|
||||
return @[]
|
||||
|
||||
proc parseCmdArg*(T: type ValidIpAddress, p: TaintedString): T =
|
||||
try:
|
||||
result = ValidIpAddress.init(p)
|
||||
except CatchableError:
|
||||
raise newException(ConfigurationError, "Invalid IP address")
|
||||
|
||||
proc completeCmdArg*(T: type ValidIpAddress, val: TaintedString): seq[string] =
|
||||
return @[]
|
||||
|
||||
func defaultListenAddress*(conf: Chat2MatterbridgeConf): ValidIpAddress =
|
||||
(static ValidIpAddress.init("0.0.0.0"))
|
@ -2,7 +2,7 @@
|
||||
|
||||
# libtool - Provide generalized library-building support services.
|
||||
# Generated automatically by config.status (libbacktrace) version-unused
|
||||
# Libtool was configured on host fv-az275-461:
|
||||
# Libtool was configured on host fv-az182-381:
|
||||
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
|
||||
#
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
|
||||
|
@ -87,3 +87,8 @@ task chat2, "Build example Waku v2 chat usage":
|
||||
|
||||
task bridge, "Build Waku v1 - v2 bridge":
|
||||
buildBinary "wakubridge", "waku/common/", "-d:chronicles_log_level=DEBUG"
|
||||
|
||||
task chat2bridge, "Build chat2-matterbridge":
|
||||
let name = "chat2bridge"
|
||||
|
||||
buildBinary name, "examples/v2/matterbridge/", "-d:chronicles_log_level=DEBUG"
|
@ -5,3 +5,4 @@ This folder contains (a) modules that use both Waku v1 and Waku v2. and (b) util
|
||||
Examples include:
|
||||
- Bridge between v1 and v2
|
||||
- NAT traversal
|
||||
- interworking with protocols external to Waku (such as Matterbridge)
|
||||
|
55
waku/common/utils/matterbridge_client.nim
Normal file
55
waku/common/utils/matterbridge_client.nim
Normal file
@ -0,0 +1,55 @@
|
||||
import
|
||||
std/[httpclient, json, uri, options]
|
||||
|
||||
const
|
||||
# Resource locators
|
||||
stream* = "/api/stream"
|
||||
messages* = "/api/messages"
|
||||
message* = "/api/message"
|
||||
health* = "/api/health"
|
||||
|
||||
type
|
||||
MatterbridgeClient* = ref object of RootObj
|
||||
hostClient*: HttpClient
|
||||
host*: Uri
|
||||
gateway*: string
|
||||
|
||||
proc new*(T: type MatterbridgeClient,
|
||||
hostUri: string,
|
||||
gateway = "gateway1"): MatterbridgeClient =
|
||||
let mbClient = MatterbridgeClient()
|
||||
|
||||
mbClient.hostClient = newHttpClient()
|
||||
mbClient.hostClient.headers = newHttpHeaders({ "Content-Type": "application/json" })
|
||||
|
||||
mbClient.host = parseUri(hostUri)
|
||||
mbClient.gateway = gateway
|
||||
|
||||
return mbClient
|
||||
|
||||
proc getMessages*(mb: MatterbridgeClient): seq[JsonNode] =
|
||||
let response = mb.hostClient.get($(mb.host / messages))
|
||||
assert response.status == "200 OK"
|
||||
|
||||
return parseJson(response.body()).getElems()
|
||||
|
||||
proc postMessage*(mb: MatterbridgeClient, msg: JsonNode) =
|
||||
let response = mb.hostClient.request($(mb.host / message),
|
||||
httpMethod = HttpPost,
|
||||
body = $msg)
|
||||
|
||||
assert response.status == "200 OK"
|
||||
|
||||
# @TODO: better error-handling here
|
||||
|
||||
proc postMessage*(mb: MatterbridgeClient, text: string, username: string) =
|
||||
let jsonNode = %* {"text": text,
|
||||
"username": username,
|
||||
"gateway": mb.gateway}
|
||||
|
||||
mb.postMessage(jsonNode)
|
||||
|
||||
proc isHealthy*(mb: MatterbridgeClient): bool =
|
||||
let response = mb.hostClient.get($(mb.host / health))
|
||||
|
||||
return response.status == "200 OK" and response.body == "OK"
|
@ -376,7 +376,7 @@ proc mountSwap*(node: WakuNode) =
|
||||
# NYI - Do we need this?
|
||||
#node.subscriptions.subscribe(WakuSwapCodec, node.wakuSwap.subscription())
|
||||
|
||||
proc mountStore*(node: WakuNode, store: MessageStore = nil, persistMessages: bool) =
|
||||
proc mountStore*(node: WakuNode, store: MessageStore = nil, persistMessages: bool = false) =
|
||||
info "mounting store"
|
||||
|
||||
if node.wakuSwap.isNil:
|
||||
|
Loading…
x
Reference in New Issue
Block a user