mirror of
https://github.com/logos-messaging/logos-messaging-legacy.git
synced 2026-01-02 05:53:10 +00:00
feat: add examples
This commit is contained in:
parent
efc3ce5c17
commit
a2375d2eb4
42
examples/README.md
Normal file
42
examples/README.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Waku v1 example
|
||||
## Introduction
|
||||
This is a basic Waku v1 example to show the Waku v1 API usage.
|
||||
|
||||
It can be run as a single node, in which case it will just post and receive its
|
||||
own messages.
|
||||
|
||||
Or multiple nodes can be started and can connect to each other, so that
|
||||
messages can be passed around.
|
||||
|
||||
## How to build
|
||||
```sh
|
||||
make example1
|
||||
```
|
||||
|
||||
## How to run
|
||||
### Single node
|
||||
```sh
|
||||
# Lauch example node
|
||||
./build/example
|
||||
```
|
||||
|
||||
Messages will be posted and received.
|
||||
|
||||
### Multiple nodes
|
||||
|
||||
```sh
|
||||
# Launch first example node
|
||||
./build/example
|
||||
```
|
||||
|
||||
Now look for an `INFO` log containing the enode address, e.g.:
|
||||
`enode://26..5b@0.0.0.0:30303` (but with full address)
|
||||
|
||||
Copy the full enode string of the first node and start the second
|
||||
node with that enode string as staticnode config option:
|
||||
```sh
|
||||
# Launch second example node, providing the enode address of the first node
|
||||
./build/example --staticnode:enode://26..5b@0.0.0.0:30303 --ports-shift:1
|
||||
```
|
||||
|
||||
Now both nodes will receive also messages from each other.
|
||||
65
examples/config_example.nim
Normal file
65
examples/config_example.nim
Normal file
@ -0,0 +1,65 @@
|
||||
import
|
||||
confutils/defs, chronicles, chronos, eth/keys
|
||||
|
||||
type
|
||||
WakuNodeCmd* = enum
|
||||
noCommand
|
||||
|
||||
WakuNodeConf* = object
|
||||
logLevel* {.
|
||||
desc: "Sets the log level."
|
||||
defaultValue: LogLevel.INFO
|
||||
name: "log-level" .}: LogLevel
|
||||
|
||||
case cmd* {.
|
||||
command
|
||||
defaultValue: noCommand .}: WakuNodeCmd
|
||||
|
||||
of noCommand:
|
||||
tcpPort* {.
|
||||
desc: "TCP listening port."
|
||||
defaultValue: 30303
|
||||
name: "tcp-port" .}: uint16
|
||||
|
||||
udpPort* {.
|
||||
desc: "UDP listening port."
|
||||
defaultValue: 30303
|
||||
name: "udp-port" .}: uint16
|
||||
|
||||
portsShift* {.
|
||||
desc: "Add a shift to all 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
|
||||
|
||||
staticnodes* {.
|
||||
desc: "Enode URL to directly connect with. Argument may be repeated."
|
||||
name: "staticnode" .}: seq[string]
|
||||
|
||||
nodekey* {.
|
||||
desc: "P2P node private key as hex.",
|
||||
defaultValue: KeyPair.random(keys.newRng()[])
|
||||
name: "nodekey" .}: KeyPair
|
||||
|
||||
proc parseCmdArg*(T: type KeyPair, p: string): T =
|
||||
try:
|
||||
let privkey = PrivateKey.fromHex(string(p)).tryGet()
|
||||
result = privkey.toKeyPair()
|
||||
except CatchableError as e:
|
||||
raise newException(ConfigurationError, "Invalid private key")
|
||||
|
||||
proc completeCmdArg*(T: type KeyPair, val: string): seq[string] =
|
||||
return @[]
|
||||
|
||||
proc parseCmdArg*(T: type IpAddress, p: string): T =
|
||||
try:
|
||||
result = parseIpAddress(p)
|
||||
except CatchableError as e:
|
||||
raise newException(ConfigurationError, "Invalid IP address")
|
||||
|
||||
proc completeCmdArg*(T: type IpAddress, val: string): seq[string] =
|
||||
return @[]
|
||||
119
examples/example.nim
Normal file
119
examples/example.nim
Normal file
@ -0,0 +1,119 @@
|
||||
import
|
||||
confutils, chronicles, chronos, stew/byteutils, stew/shims/net as stewNet,
|
||||
eth/[keys, p2p],
|
||||
../waku/protocol/waku_protocol,
|
||||
../waku/node/waku_helpers,
|
||||
../waku/common/utils/nat,
|
||||
./config_example
|
||||
|
||||
## This is a simple Waku v1 example to show the Waku v1 API usage.
|
||||
|
||||
const clientId = "Waku example v1"
|
||||
|
||||
proc run(config: WakuNodeConf, rng: ref HmacDrbgContext) =
|
||||
|
||||
let natRes = setupNat(config.nat, clientId,
|
||||
Port(config.tcpPort + config.portsShift),
|
||||
Port(config.udpPort + config.portsShift))
|
||||
if natRes.isErr():
|
||||
fatal "setupNat failed", error = natRes.error
|
||||
quit(1)
|
||||
|
||||
# Set up the address according to NAT information.
|
||||
let (ipExt, tcpPortExt, udpPortExt) = natRes.get()
|
||||
# TODO: EthereumNode should have a better split of binding address and
|
||||
# external address. Also, can't have different ports as it stands now.
|
||||
let address = if ipExt.isNone():
|
||||
Address(ip: parseIpAddress("0.0.0.0"),
|
||||
tcpPort: Port(config.tcpPort + config.portsShift),
|
||||
udpPort: Port(config.udpPort + config.portsShift))
|
||||
else:
|
||||
Address(ip: ipExt.get(),
|
||||
tcpPort: Port(config.tcpPort + config.portsShift),
|
||||
udpPort: Port(config.udpPort + config.portsShift))
|
||||
|
||||
# Create Ethereum Node
|
||||
var node = newEthereumNode(config.nodekey, # Node identifier
|
||||
address, # Address reachable for incoming requests
|
||||
NetworkId(1), # Network Id, only applicable for ETH protocol
|
||||
clientId, # Client id string
|
||||
addAllCapabilities = false, # Disable default all RLPx capabilities
|
||||
bindUdpPort = address.udpPort, # Assume same as external
|
||||
bindTcpPort = address.tcpPort, # Assume same as external
|
||||
rng = rng)
|
||||
|
||||
node.addCapability Waku # Enable only the Waku protocol.
|
||||
|
||||
# Set up the Waku configuration.
|
||||
let wakuConfig = WakuConfig(powRequirement: 0.002,
|
||||
bloom: some(fullBloom()), # Full bloom filter
|
||||
isLightNode: false, # Full node
|
||||
maxMsgSize: waku_protocol.defaultMaxMsgSize,
|
||||
topics: none(seq[waku_protocol.Topic]) # empty topic interest
|
||||
)
|
||||
node.configureWaku(wakuConfig)
|
||||
|
||||
# Optionally direct connect to a set of nodes.
|
||||
if config.staticnodes.len > 0:
|
||||
connectToNodes(node, config.staticnodes)
|
||||
|
||||
# Connect to the network, which will make the node start listening and/or
|
||||
# connect to bootnodes, and/or start discovery.
|
||||
# This will block until first connection is made, which in this case can only
|
||||
# happen if we directly connect to nodes (step above) or if an incoming
|
||||
# connection occurs, which is why we use a callback to exit on errors instead of
|
||||
# using `await`.
|
||||
# TODO: This looks a bit awkward and the API should perhaps be altered here.
|
||||
let connectedFut = node.connectToNetwork(
|
||||
true, # Enable listening
|
||||
false # Disable discovery (only discovery v4 is currently supported)
|
||||
)
|
||||
connectedFut.callback = proc(data: pointer) {.gcsafe.} =
|
||||
{.gcsafe.}:
|
||||
if connectedFut.failed:
|
||||
fatal "connectToNetwork failed", msg = connectedFut.readError.msg
|
||||
quit(1)
|
||||
|
||||
# Using a hardcoded symmetric key for encryption of the payload for the sake of
|
||||
# simplicity.
|
||||
var symKey: SymKey
|
||||
symKey[31] = 1
|
||||
# Asymmetric keypair to sign the payload.
|
||||
let signKeyPair = KeyPair.random(rng[])
|
||||
|
||||
# Code to be executed on receival of a message on filter.
|
||||
proc handler(msg: ReceivedMessage) =
|
||||
if msg.decoded.src.isSome():
|
||||
echo "Received message from ", $msg.decoded.src.get(), ": ",
|
||||
string.fromBytes(msg.decoded.payload)
|
||||
|
||||
# Create and subscribe filter with above handler.
|
||||
let
|
||||
topic = [byte 0, 0, 0, 0]
|
||||
filter = initFilter(symKey = some(symKey), topics = @[topic])
|
||||
discard node.subscribeFilter(filter, handler)
|
||||
|
||||
# Repeat the posting of a message every 5 seconds.
|
||||
# https://github.com/nim-lang/Nim/issues/17369
|
||||
var repeatMessage: proc(udata: pointer) {.gcsafe, raises: [Defect].}
|
||||
repeatMessage = proc(udata: pointer) =
|
||||
{.gcsafe.}:
|
||||
# Post a waku message on the network, encrypted with provided symmetric key,
|
||||
# signed with asymmetric key, on topic and with ttl of 30 seconds.
|
||||
let posted = node.postMessage(
|
||||
symKey = some(symKey), src = some(signKeyPair.seckey),
|
||||
ttl = 30, topic = topic, payload = @[byte 0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
||||
|
||||
if posted: echo "Posted message as ", $signKeyPair.pubkey
|
||||
else: echo "Posting message failed."
|
||||
|
||||
discard setTimer(Moment.fromNow(5.seconds), repeatMessage)
|
||||
discard setTimer(Moment.fromNow(5.seconds), repeatMessage)
|
||||
|
||||
runForever()
|
||||
|
||||
when isMainModule:
|
||||
let
|
||||
rng = keys.newRng()
|
||||
conf = WakuNodeConf.load()
|
||||
run(conf, rng)
|
||||
2
examples/nim.cfg
Normal file
2
examples/nim.cfg
Normal file
@ -0,0 +1,2 @@
|
||||
-d:chronicles_line_numbers
|
||||
-d:chronicles_runtime_filtering:on
|
||||
Loading…
x
Reference in New Issue
Block a user