mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-06-04 13:09:32 +00:00
176 lines
5.9 KiB
Nim
176 lines
5.9 KiB
Nim
## Kernel-tier FFI surface for `liblogosdelivery.so`. Exposes raw `Waku`
|
|
## lifecycle for fleet/operator callers: `waku_new`, `waku_start`,
|
|
## `waku_stop`, `waku_destroy`. C declarations live in
|
|
## `liblogosdelivery_kernel.h`.
|
|
|
|
import std/[atomics, options]
|
|
import chronos, chronicles, results, ffi
|
|
import brokers/broker_context
|
|
# Imported ahead of the kernel/sequtils-heavy block to keep the messaging
|
|
# broker-macro instantiations first (gensym-order workaround).
|
|
import layers/logos_delivery
|
|
import waku/factory/waku
|
|
import waku/node/waku_node
|
|
import waku/api/requests/subscription
|
|
import waku/waku_core/[topics/content_topic, topics/pubsub_topic]
|
|
import waku/api/ffi/kernel_helpers
|
|
|
|
template requireInitializedKernel(
|
|
ctx: ptr FFIContext[LogosDelivery], opName: string, onError: untyped
|
|
) =
|
|
if isNil(ctx):
|
|
let errMsg {.inject.} = opName & " failed: invalid context"
|
|
onError
|
|
elif isNil(ctx.myLib) or isNil(ctx.myLib[]):
|
|
let errMsg {.inject.} = opName & " failed: node is not initialized"
|
|
onError
|
|
|
|
registerReqFFI(CreateWakuRequest, ctx: ptr FFIContext[LogosDelivery]):
|
|
proc(configJson: cstring): Future[Result[string, string]] {.async.} =
|
|
let waku = (await createWakuFromJson(configJson)).valueOr:
|
|
chronicles.error "CreateWakuRequest: createWakuFromJson failed", err = error
|
|
return err(error)
|
|
ctx.myLib[] = LogosDelivery.new(Waku, waku).valueOr:
|
|
chronicles.error "CreateWakuRequest: LogosDelivery.new(Waku) failed", err = error
|
|
return err(error)
|
|
return ok("")
|
|
|
|
proc waku_new(
|
|
configJson: cstring, callback: FFICallback, userData: pointer
|
|
): pointer {.dynlib, exportc, cdecl.} =
|
|
initializeLibrary()
|
|
|
|
if isNil(callback):
|
|
echo "error: missing callback in waku_new"
|
|
return nil
|
|
|
|
var ctx = ffi.createFFIContext[LogosDelivery]().valueOr:
|
|
let msg = "Error in createFFIContext: " & $error
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
|
|
return nil
|
|
|
|
ctx.userData = userData
|
|
|
|
ffi.sendRequestToFFIThread(
|
|
ctx, CreateWakuRequest.ffiNewReq(callback, userData, configJson)
|
|
).isOkOr:
|
|
let msg = "error in sendRequestToFFIThread: " & $error
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
|
|
ffi.destroyFFIContext(ctx).isOkOr:
|
|
chronicles.error "destroyFFIContext failed after sendRequestToFFIThread error",
|
|
err = $error
|
|
return nil
|
|
|
|
return ctx
|
|
|
|
proc waku_start(
|
|
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
|
|
) {.ffi.} =
|
|
requireInitializedKernel(ctx, "waku_start"):
|
|
return err(errMsg)
|
|
(await ctx.myLib[].start()).isOkOr:
|
|
chronicles.error "waku_start failed", err = error
|
|
return err("failed to start: " & error)
|
|
return ok("")
|
|
|
|
proc waku_stop(
|
|
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
|
|
) {.ffi.} =
|
|
requireInitializedKernel(ctx, "waku_stop"):
|
|
return err(errMsg)
|
|
(await ctx.myLib[].stop()).isOkOr:
|
|
chronicles.error "waku_stop failed", err = error
|
|
return err("failed to stop: " & $error)
|
|
return ok("")
|
|
|
|
proc waku_relay_subscribe_shard(
|
|
ctx: ptr FFIContext[LogosDelivery],
|
|
callback: FFICallBack,
|
|
userData: pointer,
|
|
pubsubTopic: cstring,
|
|
) {.ffi.} =
|
|
requireInitializedKernel(ctx, "waku_relay_subscribe_shard"):
|
|
return err(errMsg)
|
|
RequestRelaySubscribeShard.request(
|
|
ctx.myLib[].brokerCtx, PubsubTopic($pubsubTopic)
|
|
).isOkOr:
|
|
chronicles.error "waku_relay_subscribe_shard failed", err = error
|
|
return err(error)
|
|
return ok("")
|
|
|
|
proc waku_relay_unsubscribe_shard(
|
|
ctx: ptr FFIContext[LogosDelivery],
|
|
callback: FFICallBack,
|
|
userData: pointer,
|
|
pubsubTopic: cstring,
|
|
) {.ffi.} =
|
|
requireInitializedKernel(ctx, "waku_relay_unsubscribe_shard"):
|
|
return err(errMsg)
|
|
RequestRelayUnsubscribeShard.request(
|
|
ctx.myLib[].brokerCtx, PubsubTopic($pubsubTopic)
|
|
).isOkOr:
|
|
chronicles.error "waku_relay_unsubscribe_shard failed", err = error
|
|
return err(error)
|
|
return ok("")
|
|
|
|
proc waku_relay_subscribe_content_topic(
|
|
ctx: ptr FFIContext[LogosDelivery],
|
|
callback: FFICallBack,
|
|
userData: pointer,
|
|
contentTopic: cstring,
|
|
pubsubTopic: cstring,
|
|
) {.ffi.} =
|
|
## Subscribe to a content topic. `pubsubTopic` is the optional shard: pass an
|
|
## empty string to derive it via auto-sharding; under static/manual sharding
|
|
## a non-empty shard must be supplied.
|
|
requireInitializedKernel(ctx, "waku_relay_subscribe_content_topic"):
|
|
return err(errMsg)
|
|
let shardOp =
|
|
if len(pubsubTopic) == 0:
|
|
none[PubsubTopic]()
|
|
else:
|
|
some(PubsubTopic($pubsubTopic))
|
|
RequestRelaySubscribeContentTopic.request(
|
|
ctx.myLib[].brokerCtx, ContentTopic($contentTopic), shardOp
|
|
).isOkOr:
|
|
chronicles.error "waku_relay_subscribe_content_topic failed", err = error
|
|
return err(error)
|
|
return ok("")
|
|
|
|
proc waku_relay_unsubscribe_content_topic(
|
|
ctx: ptr FFIContext[LogosDelivery],
|
|
callback: FFICallBack,
|
|
userData: pointer,
|
|
contentTopic: cstring,
|
|
pubsubTopic: cstring,
|
|
) {.ffi.} =
|
|
## Unsubscribe from a content topic. `pubsubTopic` is the optional shard, same
|
|
## convention as `waku_relay_subscribe_content_topic`.
|
|
requireInitializedKernel(ctx, "waku_relay_unsubscribe_content_topic"):
|
|
return err(errMsg)
|
|
let shardOp =
|
|
if len(pubsubTopic) == 0:
|
|
none[PubsubTopic]()
|
|
else:
|
|
some(PubsubTopic($pubsubTopic))
|
|
RequestRelayUnsubscribeContentTopic.request(
|
|
ctx.myLib[].brokerCtx, ContentTopic($contentTopic), shardOp
|
|
).isOkOr:
|
|
chronicles.error "waku_relay_unsubscribe_content_topic failed", err = error
|
|
return err(error)
|
|
return ok("")
|
|
|
|
proc waku_destroy(
|
|
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
|
|
): cint {.dynlib, exportc, cdecl.} =
|
|
initializeLibrary()
|
|
checkParams(ctx, callback, userData)
|
|
|
|
ffi.destroyFFIContext(ctx).isOkOr:
|
|
let msg = "waku_destroy error: " & $error
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
|
|
return RET_ERR
|
|
|
|
callback(RET_OK, nil, 0, userData)
|
|
return RET_OK
|