2023-07-31 07:52:04 +00:00
|
|
|
{.pragma: exported, exportc, cdecl, raises: [].}
|
|
|
|
{.pragma: callback, cdecl, raises: [], gcsafe.}
|
|
|
|
{.passc: "-fPIC".}
|
|
|
|
|
2024-05-18 13:04:04 +00:00
|
|
|
import std/[options, atomics, os, net]
|
2024-07-09 11:14:28 +00:00
|
|
|
import chronicles, chronos, chronos/threadsync, taskpools/channels_spsc_single, results
|
2023-07-31 07:52:04 +00:00
|
|
|
import
|
2024-07-09 11:14:28 +00:00
|
|
|
waku/factory/waku,
|
2023-09-18 07:21:50 +00:00
|
|
|
./inter_thread_communication/waku_thread_request,
|
|
|
|
./inter_thread_communication/waku_thread_response
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-08-29 20:57:23 +00:00
|
|
|
type WakuContext* = object
|
|
|
|
thread: Thread[(ptr WakuContext)]
|
2024-03-15 23:08:47 +00:00
|
|
|
reqChannel: ChannelSPSCSingle[ptr InterThreadRequest]
|
|
|
|
reqSignal: ThreadSignalPtr
|
|
|
|
respChannel: ChannelSPSCSingle[ptr InterThreadResponse]
|
|
|
|
respSignal: ThreadSignalPtr
|
|
|
|
userData*: pointer
|
|
|
|
eventCallback*: pointer
|
|
|
|
eventUserdata*: pointer
|
2024-11-08 07:59:02 +00:00
|
|
|
running: Atomic[bool] # To control when the thread is running
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-05-13 15:45:48 +00:00
|
|
|
const git_version* {.strdefine.} = "n/a"
|
|
|
|
const versionString = "version / git commit hash: " & waku.git_version
|
|
|
|
|
2024-08-29 20:57:23 +00:00
|
|
|
proc runWaku(ctx: ptr WakuContext) {.async.} =
|
2024-05-22 01:00:22 +00:00
|
|
|
## This is the worker body. This runs the Waku node
|
2023-07-31 07:52:04 +00:00
|
|
|
## and attends library user requests (stop, connect_to, etc.)
|
|
|
|
|
2024-05-03 12:07:15 +00:00
|
|
|
var waku: Waku
|
2023-09-01 06:37:02 +00:00
|
|
|
|
2024-11-08 07:59:02 +00:00
|
|
|
while true:
|
2024-05-22 01:00:22 +00:00
|
|
|
await ctx.reqSignal.wait()
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-11-08 07:59:02 +00:00
|
|
|
if ctx.running.load == false:
|
|
|
|
break
|
|
|
|
|
|
|
|
## Trying to get a request from the libwaku requestor thread
|
2023-09-18 07:21:50 +00:00
|
|
|
var request: ptr InterThreadRequest
|
|
|
|
let recvOk = ctx.reqChannel.tryRecv(request)
|
2024-11-08 07:59:02 +00:00
|
|
|
if not recvOk:
|
|
|
|
error "waku thread could not receive a request"
|
|
|
|
continue
|
|
|
|
|
|
|
|
## Handle the request
|
|
|
|
let resultResponse = waitFor InterThreadRequest.process(request, addr waku)
|
|
|
|
|
|
|
|
## Converting a `Result` into a thread-safe transferable response type
|
|
|
|
let threadSafeResp = InterThreadResponse.createShared(resultResponse)
|
2023-09-18 07:21:50 +00:00
|
|
|
|
2024-11-08 07:59:02 +00:00
|
|
|
## Send the response back to the thread that sent the request
|
|
|
|
let sentOk = ctx.respChannel.trySend(threadSafeResp)
|
|
|
|
if not sentOk:
|
|
|
|
error "could not send a request to the requester thread",
|
|
|
|
original_request = $request[]
|
2023-09-18 07:21:50 +00:00
|
|
|
|
2024-11-08 07:59:02 +00:00
|
|
|
let fireRes = ctx.respSignal.fireSync()
|
|
|
|
if fireRes.isErr():
|
|
|
|
error "could not fireSync back to requester thread", error = fireRes.error
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-08-29 20:57:23 +00:00
|
|
|
proc run(ctx: ptr WakuContext) {.thread.} =
|
2024-05-22 01:00:22 +00:00
|
|
|
## Launch waku worker
|
|
|
|
waitFor runWaku(ctx)
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-08-29 20:57:23 +00:00
|
|
|
proc createWakuThread*(): Result[ptr WakuContext, string] =
|
2023-07-31 07:52:04 +00:00
|
|
|
## This proc is called from the main thread and it creates
|
|
|
|
## the Waku working thread.
|
2024-08-29 20:57:23 +00:00
|
|
|
var ctx = createShared(WakuContext, 1)
|
2023-09-22 14:36:31 +00:00
|
|
|
ctx.reqSignal = ThreadSignalPtr.new().valueOr:
|
|
|
|
return err("couldn't create reqSignal ThreadSignalPtr")
|
|
|
|
ctx.respSignal = ThreadSignalPtr.new().valueOr:
|
|
|
|
return err("couldn't create respSignal ThreadSignalPtr")
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-11-08 07:59:02 +00:00
|
|
|
ctx.running.store(true)
|
2023-07-31 07:52:04 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
createThread(ctx.thread, run, ctx)
|
2023-09-01 06:37:02 +00:00
|
|
|
except ValueError, ResourceExhaustedError:
|
2023-07-31 07:52:04 +00:00
|
|
|
# and freeShared for typed allocations!
|
|
|
|
freeShared(ctx)
|
|
|
|
|
2023-09-01 06:37:02 +00:00
|
|
|
return err("failed to create the Waku thread: " & getCurrentExceptionMsg())
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
return ok(ctx)
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-11-08 07:59:02 +00:00
|
|
|
proc destroyWakuThread*(ctx: ptr WakuContext): Result[void, string] =
|
|
|
|
ctx.running.store(false)
|
|
|
|
|
|
|
|
let signaledOnTime = ctx.reqSignal.fireSync().valueOr:
|
|
|
|
return err("error in destroyWakuThread: " & $error)
|
|
|
|
if not signaledOnTime:
|
|
|
|
return err("failed to signal reqSignal on time in destroyWakuThread")
|
|
|
|
|
2024-05-22 01:00:22 +00:00
|
|
|
joinThread(ctx.thread)
|
2024-11-08 07:59:02 +00:00
|
|
|
?ctx.reqSignal.close()
|
|
|
|
?ctx.respSignal.close()
|
2023-07-31 07:52:04 +00:00
|
|
|
freeShared(ctx)
|
2024-11-08 07:59:02 +00:00
|
|
|
|
2024-03-07 17:53:03 +00:00
|
|
|
return ok()
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc sendRequestToWakuThread*(
|
2024-08-29 20:57:23 +00:00
|
|
|
ctx: ptr WakuContext, reqType: RequestType, reqContent: pointer
|
2024-03-15 23:08:47 +00:00
|
|
|
): Result[string, string] =
|
2023-09-18 07:21:50 +00:00
|
|
|
let req = InterThreadRequest.createShared(reqType, reqContent)
|
|
|
|
## Sending the request
|
|
|
|
let sentOk = ctx.reqChannel.trySend(req)
|
|
|
|
if not sentOk:
|
|
|
|
return err("Couldn't send a request to the waku thread: " & $req[])
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2023-09-22 14:36:31 +00:00
|
|
|
let fireSyncRes = ctx.reqSignal.fireSync()
|
|
|
|
if fireSyncRes.isErr():
|
|
|
|
return err("failed fireSync: " & $fireSyncRes.error)
|
|
|
|
|
|
|
|
if fireSyncRes.get() == false:
|
|
|
|
return err("Couldn't fireSync in time")
|
|
|
|
|
2024-05-22 01:00:22 +00:00
|
|
|
# Waiting for the response
|
|
|
|
let res = waitSync(ctx.respSignal)
|
|
|
|
if res.isErr():
|
|
|
|
return err("Couldnt receive response signal")
|
2023-09-22 14:36:31 +00:00
|
|
|
|
2023-09-18 07:21:50 +00:00
|
|
|
var response: ptr InterThreadResponse
|
|
|
|
var recvOk = ctx.respChannel.tryRecv(response)
|
2023-09-22 14:36:31 +00:00
|
|
|
if recvOk == false:
|
|
|
|
return err("Couldn't receive response from the waku thread: " & $req[])
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2023-09-18 07:21:50 +00:00
|
|
|
## Converting the thread-safe response into a managed/CG'ed `Result`
|
|
|
|
return InterThreadResponse.process(response)
|