import std/json import chronos, chronicles, results, ffi import libp2p/peerid # pull PeerId pretty string formatting import logos_delivery/waku/common/base64 import logos_delivery, logos_delivery/waku/node/waku_node, logos_delivery/api/types, logos_delivery/waku/api/events/health_events, logos_delivery/waku/api/events/peer_events, logos_delivery/api/conf/logos_delivery_conf_json, ../declare_lib, ../json_event # Add JSON serialization for RequestId proc `%`*(id: RequestId): JsonNode = %($id) proc logosdelivery_create_node( configJson: string ): Future[Result[LogosDelivery, string]] {.ffiCtor.} = let conf = parseLogosDeliveryConf(configJson).valueOr: error "Failed to parse Logos Delivery configuration JSON", error = error, configJson = configJson return err("failed parseLogosDeliveryConf " & error) let lib = (await LogosDelivery.new(conf)).valueOr: let errMsg = $error chronicles.error "CreateNodeRequest failed", err = errMsg return err(errMsg) return ok(lib) proc logosdelivery_destroy(self: LogosDelivery) {.ffiDtor.} = discard proc registerFFIEventListeners(self: LogosDelivery): Result[void, string] = ## Bridges every broker event the library re-publishes onto the FFI event ## registry. Keep in step with `dropFFIEventListeners`. MessageSentEvent.listen( self.waku.brokerCtx, proc(event: MessageSentEvent) {.async: (raises: []).} = emitEvent("onMessageSent"): $newJsonEvent("message_sent", event), ).isOkOr: chronicles.error "MessageSentEvent.listen failed", err = $error return err("MessageSentEvent.listen failed: " & $error) MessageErrorEvent.listen( self.waku.brokerCtx, proc(event: MessageErrorEvent) {.async: (raises: []).} = emitEvent("onMessageError"): $newJsonEvent("message_error", event), ).isOkOr: chronicles.error "MessageErrorEvent.listen failed", err = $error return err("MessageErrorEvent.listen failed: " & $error) MessagePropagatedEvent.listen( self.waku.brokerCtx, proc(event: MessagePropagatedEvent) {.async: (raises: []).} = emitEvent("onMessagePropagated"): $newJsonEvent("message_propagated", event), ).isOkOr: chronicles.error "MessagePropagatedEvent.listen failed", err = $error return err("MessagePropagatedEvent.listen failed: " & $error) MessageReceivedEvent.listen( self.waku.brokerCtx, proc(event: MessageReceivedEvent) {.async: (raises: []).} = emitEvent("onMessageReceived"): $newJsonEvent("message_received", event), ).isOkOr: chronicles.error "MessageReceivedEvent.listen failed", err = $error return err("MessageReceivedEvent.listen failed: " & $error) EventConnectionStatusChange.listen( self.waku.brokerCtx, proc(event: EventConnectionStatusChange) {.async: (raises: []).} = emitEvent("onConnectionStatusChange"): $newJsonEvent("connection_status_change", event), ).isOkOr: chronicles.error "ConnectionStatusChange.listen failed", err = $error return err("ConnectionStatusChange.listen failed: " & $error) EventShardTopicHealthChange.listen( self.waku.brokerCtx, proc(event: EventShardTopicHealthChange) {.async: (raises: []).} = emitEvent("onTopicHealthChange"): $( %*{ "eventType": "relay_topic_health_change", "pubsubTopic": $event.topic, "topicHealth": $event.health, } ), ).isOkOr: chronicles.error "EventShardTopicHealthChange.listen failed", err = $error return err("EventShardTopicHealthChange.listen failed: " & $error) WakuPeerEvent.listen( self.waku.brokerCtx, proc(event: WakuPeerEvent) {.async: (raises: []).} = emitEvent("onConnectionChange"): $( %*{ "eventType": "connection_change", "peerId": $event.peerId, "peerEvent": $event.kind, } ), ).isOkOr: chronicles.error "WakuPeerEvent.listen failed", err = $error return err("WakuPeerEvent.listen failed: " & $error) ChannelMessageReceivedEvent.listen( self.waku.brokerCtx, proc(event: ChannelMessageReceivedEvent) {.async: (raises: []).} = emitEvent("onChannelMessageReceived"): $( %*{ "eventType": "channel_message_received", "channelId": string(event.channelId), "senderId": $event.senderId, "payload": string(base64.encode(event.payload)), } ), ).isOkOr: chronicles.error "ChannelMessageReceivedEvent.listen failed", err = $error return err("ChannelMessageReceivedEvent.listen failed: " & $error) ChannelMessageSentEvent.listen( self.waku.brokerCtx, proc(event: ChannelMessageSentEvent) {.async: (raises: []).} = emitEvent("onChannelMessageSent"): $newJsonEvent("channel_message_sent", event), ).isOkOr: chronicles.error "ChannelMessageSentEvent.listen failed", err = $error return err("ChannelMessageSentEvent.listen failed: " & $error) ChannelMessageErrorEvent.listen( self.waku.brokerCtx, proc(event: ChannelMessageErrorEvent) {.async: (raises: []).} = emitEvent("onChannelMessageError"): $newJsonEvent("channel_message_error", event), ).isOkOr: chronicles.error "ChannelMessageErrorEvent.listen failed", err = $error return err("ChannelMessageErrorEvent.listen failed: " & $error) return ok() proc dropFFIEventListeners(self: LogosDelivery) {.async.} = ## Reverse of `registerFFIEventListeners`. await MessageErrorEvent.dropAllListeners(self.waku.brokerCtx) await MessageSentEvent.dropAllListeners(self.waku.brokerCtx) await MessagePropagatedEvent.dropAllListeners(self.waku.brokerCtx) await MessageReceivedEvent.dropAllListeners(self.waku.brokerCtx) await EventConnectionStatusChange.dropAllListeners(self.waku.brokerCtx) await EventShardTopicHealthChange.dropAllListeners(self.waku.brokerCtx) await WakuPeerEvent.dropAllListeners(self.waku.brokerCtx) await ChannelMessageReceivedEvent.dropAllListeners(self.waku.brokerCtx) await ChannelMessageSentEvent.dropAllListeners(self.waku.brokerCtx) await ChannelMessageErrorEvent.dropAllListeners(self.waku.brokerCtx) proc logosdelivery_start_node( self: LogosDelivery ): Future[Result[string, string]] {.ffi.} = self.registerFFIEventListeners().isOkOr: return err(error) (await self.start()).isOkOr: let errMsg = $error chronicles.error "START_NODE failed", err = errMsg return err("failed to start: " & errMsg) return ok("") proc logosdelivery_stop_node( self: LogosDelivery ): Future[Result[string, string]] {.ffi.} = await self.dropFFIEventListeners() (await self.stop()).isOkOr: let errMsg = $error chronicles.error "STOP_NODE failed", err = errMsg return err("failed to stop: " & errMsg) return ok("")