mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-01-04 06:53:12 +00:00
* Upgrade lpt to new config methods * Make choice of legacy and v3 lightpush configurable on cli * Adjust runner script to allow easy lightpush version selection * Prepare selectable lightpush for infra env runs * Fix misused result vs return * Fixes and more explanatory comments added * Fix ~pure virtual~ notice to =discard
263 lines
7.9 KiB
Nim
263 lines
7.9 KiB
Nim
{.push raises: [].}
|
||
|
||
import
|
||
std/[options, strutils, os, sequtils, net],
|
||
chronicles,
|
||
chronos,
|
||
metrics,
|
||
libbacktrace,
|
||
system/ansi_c,
|
||
libp2p/crypto/crypto,
|
||
confutils
|
||
|
||
import
|
||
waku/[
|
||
common/enr,
|
||
common/logging,
|
||
factory/waku,
|
||
factory/external_config,
|
||
waku_node,
|
||
node/health_monitor,
|
||
node/waku_metrics,
|
||
node/peer_manager,
|
||
waku_api/rest/builder as rest_server_builder,
|
||
waku_lightpush/common,
|
||
waku_filter_v2,
|
||
waku_peer_exchange/protocol,
|
||
waku_core/peers,
|
||
waku_core/multiaddrstr,
|
||
],
|
||
./tester_config,
|
||
./publisher,
|
||
./receiver,
|
||
./diagnose_connections,
|
||
./service_peer_management
|
||
|
||
logScope:
|
||
topics = "liteprotocoltester main"
|
||
|
||
proc logConfig(conf: LiteProtocolTesterConf) =
|
||
info "Configuration: Lite protocol tester", conf = $conf
|
||
|
||
{.pop.}
|
||
when isMainModule:
|
||
## Node setup happens in 6 phases:
|
||
## 1. Set up storage
|
||
## 2. Initialize node
|
||
## 3. Mount and initialize configured protocols
|
||
## 4. Start node and mounted protocols
|
||
## 5. Start monitoring tools and external interfaces
|
||
## 6. Setup graceful shutdown hooks
|
||
|
||
const versionString = "version / git commit hash: " & waku.git_version
|
||
|
||
let confRes = LiteProtocolTesterConf.load(version = versionString)
|
||
if confRes.isErr():
|
||
error "failure while loading the configuration", error = confRes.error
|
||
quit(QuitFailure)
|
||
|
||
var conf = confRes.get()
|
||
|
||
## Logging setup
|
||
logging.setupLog(conf.logLevel, conf.logFormat)
|
||
|
||
info "Running Lite Protocol Tester node", version = waku.git_version
|
||
logConfig(conf)
|
||
|
||
##Prepare Waku configuration
|
||
## - load from config file
|
||
## - override according to tester functionality
|
||
##
|
||
|
||
var wConf: WakuNodeConf
|
||
|
||
if conf.configFile.isSome():
|
||
try:
|
||
var configFile {.threadvar.}: InputFile
|
||
configFile = conf.configFile.get()
|
||
wConf = WakuNodeConf.load(
|
||
version = versionString,
|
||
printUsage = false,
|
||
secondarySources = proc(
|
||
wnconf: WakuNodeConf, sources: auto
|
||
) {.gcsafe, raises: [ConfigurationError].} =
|
||
echo "Loading secondary configuration file into WakuNodeConf"
|
||
sources.addConfigFile(Toml, configFile),
|
||
)
|
||
except CatchableError:
|
||
error "Loading Waku configuration failed", error = getCurrentExceptionMsg()
|
||
quit(QuitFailure)
|
||
|
||
wConf.logLevel = conf.logLevel
|
||
wConf.logFormat = conf.logFormat
|
||
wConf.nat = conf.nat
|
||
wConf.maxConnections = 500
|
||
wConf.restAddress = conf.restAddress
|
||
wConf.restPort = conf.restPort
|
||
wConf.restAllowOrigin = conf.restAllowOrigin
|
||
|
||
wConf.dnsAddrsNameServers = @[parseIpAddress("8.8.8.8"), parseIpAddress("1.1.1.1")]
|
||
|
||
wConf.shards = @[conf.shard]
|
||
wConf.contentTopics = conf.contentTopics
|
||
wConf.clusterId = conf.clusterId
|
||
## TODO: Depending on the tester needs we might extend here with shards, clusterId, etc...
|
||
|
||
wConf.metricsServer = true
|
||
wConf.metricsServerAddress = parseIpAddress("0.0.0.0")
|
||
wConf.metricsServerPort = conf.metricsPort
|
||
|
||
# If bootstrap option is chosen we expect our clients will not mounted
|
||
# so we will mount PeerExchange manually to gather possible service peers,
|
||
# if got some we will mount the client protocols afterward.
|
||
wConf.peerExchange = false
|
||
wConf.relay = false
|
||
wConf.filter = false
|
||
wConf.lightpush = false
|
||
wConf.store = false
|
||
|
||
wConf.rest = false
|
||
wConf.relayServiceRatio = "40:60"
|
||
|
||
# NOTE: {.threadvar.} is used to make the global variable GC safe for the closure uses it
|
||
# It will always be called from main thread anyway.
|
||
# Ref: https://nim-lang.org/docs/manual.html#threads-gc-safety
|
||
var nodeHealthMonitor {.threadvar.}: WakuNodeHealthMonitor
|
||
nodeHealthMonitor = WakuNodeHealthMonitor()
|
||
nodeHealthMonitor.setOverallHealth(HealthStatus.INITIALIZING)
|
||
|
||
let wakuConf = wConf.toWakuConf().valueOr:
|
||
error "Waku configuration failed", error = error
|
||
quit(QuitFailure)
|
||
|
||
let restServer: WakuRestServerRef =
|
||
if wakuConf.restServerConf.isSome():
|
||
rest_server_builder.startRestServerEssentials(
|
||
nodeHealthMonitor, wakuConf.restServerConf.get(), wakuConf.portsShift
|
||
).valueOr:
|
||
error "Starting essential REST server failed.", error = $error
|
||
quit(QuitFailure)
|
||
else:
|
||
nil
|
||
|
||
var wakuApp = Waku.new(wakuConf).valueOr:
|
||
error "Waku initialization failed", error = error
|
||
quit(QuitFailure)
|
||
|
||
wakuApp.restServer = restServer
|
||
|
||
nodeHealthMonitor.setNode(wakuApp.node)
|
||
|
||
(waitFor startWaku(addr wakuApp)).isOkOr:
|
||
error "Starting waku failed", error = error
|
||
quit(QuitFailure)
|
||
|
||
if wakuConf.restServerConf.isSome():
|
||
rest_server_builder.startRestServerProtocolSupport(
|
||
restServer,
|
||
wakuApp.node,
|
||
wakuApp.wakuDiscv5,
|
||
wakuConf.restServerConf.get(),
|
||
wakuConf.relay,
|
||
wakuConf.lightPush,
|
||
wakuConf.clusterId,
|
||
wakuConf.shards,
|
||
wakuConf.contentTopics,
|
||
).isOkOr:
|
||
error "Starting protocols support REST server failed.", error = $error
|
||
quit(QuitFailure)
|
||
|
||
if wakuConf.metricsServerConf.isSome():
|
||
wakuApp.metricsServer = waku_metrics.startMetricsServerAndLogging(
|
||
wakuConf.metricsServerConf.get(), wakuConf.portsShift
|
||
).valueOr:
|
||
error "Starting monitoring and external interfaces failed", error = error
|
||
quit(QuitFailure)
|
||
|
||
nodeHealthMonitor.setOverallHealth(HealthStatus.READY)
|
||
|
||
debug "Setting up shutdown hooks"
|
||
## Setup shutdown hooks for this process.
|
||
## Stop node gracefully on shutdown.
|
||
|
||
proc asyncStopper(wakuApp: Waku) {.async: (raises: [Exception]).} =
|
||
nodeHealthMonitor.setOverallHealth(HealthStatus.SHUTTING_DOWN)
|
||
await wakuApp.stop()
|
||
quit(QuitSuccess)
|
||
|
||
# Handle Ctrl-C SIGINT
|
||
proc handleCtrlC() {.noconv.} =
|
||
when defined(windows):
|
||
# workaround for https://github.com/nim-lang/Nim/issues/4057
|
||
setupForeignThreadGc()
|
||
notice "Shutting down after receiving SIGINT"
|
||
asyncSpawn asyncStopper(wakuApp)
|
||
|
||
setControlCHook(handleCtrlC)
|
||
|
||
# Handle SIGTERM
|
||
when defined(posix):
|
||
proc handleSigterm(signal: cint) {.noconv.} =
|
||
notice "Shutting down after receiving SIGTERM"
|
||
asyncSpawn asyncStopper(wakuApp)
|
||
|
||
c_signal(ansi_c.SIGTERM, handleSigterm)
|
||
|
||
# Handle SIGSEGV
|
||
when defined(posix):
|
||
proc handleSigsegv(signal: cint) {.noconv.} =
|
||
# Require --debugger:native
|
||
fatal "Shutting down after receiving SIGSEGV", stacktrace = getBacktrace()
|
||
|
||
# Not available in -d:release mode
|
||
writeStackTrace()
|
||
|
||
waitFor wakuApp.stop()
|
||
quit(QuitFailure)
|
||
|
||
c_signal(ansi_c.SIGSEGV, handleSigsegv)
|
||
|
||
info "Node setup complete"
|
||
|
||
let codec = conf.getCodec()
|
||
# mounting relevant client, for PX filter client must be mounted ahead
|
||
|
||
var lookForServiceNode = false
|
||
var serviceNodePeerInfo: RemotePeerInfo
|
||
if conf.serviceNode.len == 0:
|
||
if conf.bootstrapNode.len > 0:
|
||
info "Bootstrapping with PeerExchange to gather random service node"
|
||
let futForServiceNode = pxLookupServiceNode(wakuApp.node, conf)
|
||
if not (waitFor futForServiceNode.withTimeout(20.minutes)):
|
||
error "Service node not found in time via PX"
|
||
quit(QuitFailure)
|
||
|
||
if futForServiceNode.read().isErr():
|
||
error "Service node for test not found via PX"
|
||
quit(QuitFailure)
|
||
|
||
serviceNodePeerInfo = selectRandomServicePeer(
|
||
wakuApp.node.peerManager, none(RemotePeerInfo), codec
|
||
).valueOr:
|
||
error "Service node selection failed"
|
||
quit(QuitFailure)
|
||
else:
|
||
error "No service or bootstrap node provided"
|
||
quit(QuitFailure)
|
||
else:
|
||
# support for both ENR and URI formatted service node addresses
|
||
serviceNodePeerInfo = translateToRemotePeerInfo(conf.serviceNode).valueOr:
|
||
error "failed to parse service-node", node = conf.serviceNode
|
||
quit(QuitFailure)
|
||
|
||
info "Service node to be used", serviceNode = $serviceNodePeerInfo
|
||
|
||
logSelfPeers(wakuApp.node.peerManager)
|
||
|
||
if conf.testFunc == TesterFunctionality.SENDER:
|
||
setupAndPublish(wakuApp.node, conf, serviceNodePeerInfo)
|
||
else:
|
||
setupAndListen(wakuApp.node, conf, serviceNodePeerInfo)
|
||
|
||
runForever()
|