mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-08-05 03:13:35 +00:00
Squash of the kernel-wiring work (d86f0651..535fe2c9): - Don't exercise FFI of Brokers - Fix tests and examples to compile; verify product unchanged - bump nim-brokers to v3.1.3 - Events dropListeners changed to async - WIP + finalize KernelInterface <-> Waku wiring
210 lines
7.8 KiB
Nim
210 lines
7.8 KiB
Nim
## LogosDelivery — the LogosDeliveryInterface facade implementation.
|
|
##
|
|
## Owns a `Waku` (node + messagingClient + reliableChannelManager) and exposes
|
|
## the three sub-interfaces through cached getters. Mirrors the persistence
|
|
## example's `PersistenceImpl` (nim-brokers/examples/persistence/nimlib): a
|
|
## `ref object of <iface>` with `BrokerImplement`, sub-instances built on a
|
|
## `newInstanceCtx(self.brokerCtx)`, plus a `provideFactory`.
|
|
##
|
|
## Scope (decided): `initializeRequest(configPath)` creates + mounts the node but
|
|
## does NOT start it. `kernel()` is a stub until a KernelImpl exists.
|
|
|
|
import results, chronos
|
|
import std/options # some()/Option for WakuNodeConf.mode
|
|
import std/json # newJArray/newJObject/%*/pretty in getAvailableConfigs
|
|
|
|
import brokers/broker_context, brokers/broker_interface, brokers/broker_implement
|
|
import logos_delivery/api/logos_delivery_interface as logosdelivery_iface
|
|
import logos_delivery/api/types as api_types
|
|
import logos_delivery/api/kernel_interface as kernel_iface
|
|
|
|
import
|
|
logos_delivery/waku/factory/waku,
|
|
logos_delivery/waku/factory/waku_state_info,
|
|
logos_delivery/messaging/messaging_client,
|
|
logos_delivery/channels/reliable_channel_manager
|
|
# Waku, getNodeInfoItem, mountMessagingClient, mountReliableChannelManager, stop
|
|
import tools/confutils/[cli_args, config_option_meta] # WakuNodeConf (+ .load)
|
|
|
|
type LogosDelivery* = ref object of LogosDeliveryInterface
|
|
waku: Waku ## the owned node facade (built in initializeRequest)
|
|
messagingClient: MessagingClient
|
|
reliableChannelManager: ReliableChannelManager
|
|
|
|
proc loadConf(configPath: string): Result[WakuNodeConf, string] =
|
|
## Delegates to cli_args' concrete loader so confutils' `load` macro expands in
|
|
## cli_args' full scope (avoids leaking undeclared identifiers / WakuMode clash here).
|
|
loadWakuNodeConfFromFile(configPath)
|
|
|
|
proc createNode(conf: WakuNodeConf): Future[Result[Waku, string]] {.async.} =
|
|
let wakuConf = conf.toWakuConf().valueOr:
|
|
return err("Failed to handle the configuration: " & error)
|
|
|
|
## We are not defining app callbacks at node creation
|
|
let wakuRes = (await Waku.createUnderContext(globalBrokerContext(), wakuConf)).valueOr:
|
|
error "waku initialization failed", error = error
|
|
return err("Failed setting up Waku: " & $error)
|
|
|
|
return ok(wakuRes)
|
|
|
|
proc initMessagingClient(self: LogosDelivery): Result[MessagingClient, string] =
|
|
return ok(
|
|
MessagingClient.createUnderContext(
|
|
globalBrokerContext(), self.waku.conf.p2pReliability, self.waku.node
|
|
)
|
|
)
|
|
|
|
proc initReliableChannelManager(
|
|
self: LogosDelivery
|
|
): Result[ReliableChannelManager, string] =
|
|
return ok(
|
|
ReliableChannelManager.createUnderContext(
|
|
globalBrokerContext(), self.messagingClient
|
|
)
|
|
)
|
|
|
|
BrokerImplement LogosDelivery of LogosDeliveryInterface:
|
|
method kernel(
|
|
self: LogosDelivery
|
|
): Future[Result[KernelInterface, string]] {.async.} =
|
|
if self.waku.isNil():
|
|
return err("not initialized; call startAsClient first")
|
|
|
|
return ok(KernelInterface(self.waku))
|
|
|
|
method messaging(
|
|
self: LogosDelivery
|
|
): Future[Result[MessagingClientInterface, string]] {.async.} =
|
|
if self.waku.isNil():
|
|
return err("not initialized; call startAsClient first")
|
|
if self.messagingClient.isNil():
|
|
return err("messaging client not mounted")
|
|
return ok(MessagingClientInterface(self.messagingClient))
|
|
|
|
method channels(
|
|
self: LogosDelivery
|
|
): Future[Result[ReliableChannelManagerInterface, string]] {.async.} =
|
|
if self.waku.isNil():
|
|
return err("not initialized; call startAsClient first")
|
|
if self.messagingClient.isNil():
|
|
return err("not initialized; call startAsClient first")
|
|
|
|
if self.reliableChannelManager.isNil():
|
|
self.reliableChannelManager = initReliableChannelManager(self).valueOr:
|
|
return err("failed to initialize ReliableChannelManager: " & error)
|
|
self.reliableChannelManager.start().isOkOr:
|
|
return err("failed to start ReliableChannelManager: " & error)
|
|
|
|
return ok(ReliableChannelManagerInterface(self.reliableChannelManager))
|
|
|
|
method startAsNode(
|
|
self: LogosDelivery, config: string
|
|
): Future[Result[void, string]] {.async.} =
|
|
if not self.waku.isNil():
|
|
return err("already initialized")
|
|
let conf = loadConf(config).valueOr:
|
|
return err("failed to load config: " & error)
|
|
# The restamp forces {.async: (raises: []).}, but createNode can raise.
|
|
try:
|
|
self.waku = (await createNode(conf)).valueOr:
|
|
return err("failed to create node: " & error)
|
|
|
|
(await self.waku.start()).isOkOr:
|
|
return err("failed to start node: " & $error)
|
|
|
|
return ok()
|
|
except CatchableError as e:
|
|
return err("initialize failed: " & e.msg)
|
|
|
|
method startAsClient(
|
|
self: LogosDelivery, mode: api_types.WakuMode, preset: string
|
|
): Future[Result[MessagingClientInterface, string]] {.async.} =
|
|
if not self.messagingClient.isNil():
|
|
return err("already initialized")
|
|
if not self.waku.isNil():
|
|
return err(
|
|
"already started as node; cannot start as client, but you can use as client"
|
|
)
|
|
|
|
try:
|
|
var conf: WakuNodeConf = ?defaultWakuNodeConf()
|
|
conf.mode = some(mode)
|
|
conf.preset = preset
|
|
|
|
self.waku = (await createNode(conf)).valueOr:
|
|
return err("failed to create node: " & error)
|
|
|
|
self.messagingClient = initMessagingClient(self).valueOr:
|
|
return err("failed to mount messaging client: " & error)
|
|
|
|
(await self.waku.start()).isOkOr:
|
|
return err("failed to start node: " & $error)
|
|
self.messagingClient.start().isOkOr:
|
|
return err("failed to start messaging client: " & $error)
|
|
|
|
return ok(MessagingClientInterface(self.messagingClient))
|
|
except CatchableError as e:
|
|
return err("initialize failed: " & e.msg)
|
|
|
|
method stop(self: LogosDelivery): Future[Result[void, string]] {.async.} =
|
|
if not self.reliableChannelManager.isNil():
|
|
try:
|
|
await self.reliableChannelManager.stop()
|
|
self.reliableChannelManager.close()
|
|
self.reliableChannelManager = nil
|
|
except CatchableError as e:
|
|
return err("ReliableChannelManager stop failed: " & e.msg)
|
|
|
|
if not self.messagingClient.isNil():
|
|
try:
|
|
await self.messagingClient.stop()
|
|
self.messagingClient.close()
|
|
self.messagingClient = nil
|
|
except CatchableError as e:
|
|
return err("MessagingClient stop failed: " & e.msg)
|
|
|
|
if not self.waku.isNil():
|
|
try:
|
|
(await self.waku.stop()).isOkOr:
|
|
return err("Node stop failed: " & $error)
|
|
# `Waku` is a plain ref object (not a BrokerImplement) — `stop()` is its
|
|
# only teardown; there is no `close()`.
|
|
self.waku = nil
|
|
except CatchableError as e:
|
|
return err("Node stop failed: " & e.msg)
|
|
|
|
return ok()
|
|
|
|
method shutdown(self: LogosDelivery): Future[Result[void, string]] {.async.} =
|
|
return await self.stop()
|
|
|
|
method getNodeInfo(
|
|
self: LogosDelivery, id: NodeInfoId
|
|
): Future[Result[string, string]] {.async.} =
|
|
return ok(self.waku.stateInfo.getNodeInfoItem(id))
|
|
|
|
method getAvailableConfigs(
|
|
self: LogosDelivery
|
|
): Future[Result[string, string]] {.async.} =
|
|
let optionMetas: seq[ConfigOptionMeta] = extractConfigOptionMeta(WakuNodeConf)
|
|
var configOptionDetails = newJArray()
|
|
|
|
for meta in optionMetas:
|
|
configOptionDetails.add(
|
|
%*{
|
|
meta.fieldName: meta.typeName & "(" & meta.defaultValue & ")",
|
|
"desc": meta.desc,
|
|
}
|
|
)
|
|
|
|
var jsonNode = newJObject()
|
|
jsonNode["configOptions"] = configOptionDetails
|
|
let asString = pretty(jsonNode)
|
|
return ok(pretty(jsonNode))
|
|
|
|
# DI factory registration: non ffi - nim lib users needs it.
|
|
LogosDeliveryInterface.provideFactory(
|
|
proc(): Result[LogosDeliveryInterface, string] {.gcsafe.} =
|
|
ok(LogosDeliveryInterface(LogosDelivery.createUnderContext(globalBrokerContext())))
|
|
)
|