2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
{.pragma: exported, exportc, cdecl, raises: [].}
|
|
|
|
{.pragma: callback, cdecl, raises: [], gcsafe.}
|
|
|
|
{.passc: "-fPIC".}
|
|
|
|
|
2023-05-12 16:08:41 +00:00
|
|
|
import
|
2023-10-23 06:37:28 +00:00
|
|
|
std/[json,sequtils,times,strformat,options,atomics,strutils]
|
2023-05-12 16:08:41 +00:00
|
|
|
import
|
|
|
|
chronicles,
|
2023-07-31 07:52:04 +00:00
|
|
|
chronos
|
2023-05-12 16:08:41 +00:00
|
|
|
import
|
2023-08-09 17:11:50 +00:00
|
|
|
../../waku/waku_core/message/message,
|
|
|
|
../../waku/node/waku_node,
|
|
|
|
../../waku/waku_core/topics/pubsub_topic,
|
|
|
|
../../../waku/waku_relay/protocol,
|
2023-07-31 07:52:04 +00:00
|
|
|
./events/json_message_event,
|
2023-08-02 08:45:15 +00:00
|
|
|
./waku_thread/waku_thread,
|
2023-09-18 07:21:50 +00:00
|
|
|
./waku_thread/inter_thread_communication/requests/node_lifecycle_request,
|
|
|
|
./waku_thread/inter_thread_communication/requests/peer_manager_request,
|
|
|
|
./waku_thread/inter_thread_communication/requests/protocols/relay_request,
|
|
|
|
./waku_thread/inter_thread_communication/waku_thread_request,
|
2023-07-31 07:52:04 +00:00
|
|
|
./alloc
|
2023-05-12 16:08:41 +00:00
|
|
|
|
|
|
|
################################################################################
|
|
|
|
### Wrapper around the waku node
|
|
|
|
################################################################################
|
|
|
|
|
|
|
|
################################################################################
|
|
|
|
### Exported types
|
2023-07-07 08:53:00 +00:00
|
|
|
|
|
|
|
const RET_OK: cint = 0
|
|
|
|
const RET_ERR: cint = 1
|
|
|
|
const RET_MISSING_CALLBACK: cint = 2
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
type
|
2023-10-23 06:37:28 +00:00
|
|
|
WakuCallBack* = proc(callerRet: cint,
|
|
|
|
msg: ptr cchar,
|
|
|
|
len: csize_t) {.cdecl, gcsafe.}
|
2023-07-31 07:52:04 +00:00
|
|
|
|
2023-05-12 16:08:41 +00:00
|
|
|
### End of exported types
|
|
|
|
################################################################################
|
|
|
|
|
|
|
|
################################################################################
|
|
|
|
### Not-exported components
|
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
# May keep a reference to a callback defined externally
|
2023-07-31 07:52:04 +00:00
|
|
|
var extEventCallback*: WakuCallBack = nil
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
proc relayEventCallback(pubsubTopic: PubsubTopic,
|
|
|
|
msg: WakuMessage): Future[void] {.async, gcsafe.} =
|
2023-05-12 16:08:41 +00:00
|
|
|
# Callback that hadles the Waku Relay events. i.e. messages or errors.
|
2023-07-31 07:52:04 +00:00
|
|
|
if not isNil(extEventCallback):
|
2023-05-12 16:08:41 +00:00
|
|
|
try:
|
2023-07-07 08:53:00 +00:00
|
|
|
let event = $JsonMessageEvent.new(pubsubTopic, msg)
|
2023-10-23 06:37:28 +00:00
|
|
|
extEventCallback(RET_OK, unsafeAddr event[0], cast[csize_t](len(event)))
|
2023-07-07 08:53:00 +00:00
|
|
|
except Exception,CatchableError:
|
2023-10-23 06:37:28 +00:00
|
|
|
let msg = "Exception when calling 'eventCallBack': " &
|
|
|
|
getCurrentExceptionMsg()
|
|
|
|
extEventCallback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-05-12 16:08:41 +00:00
|
|
|
else:
|
2023-07-31 07:52:04 +00:00
|
|
|
error "extEventCallback is nil"
|
2023-05-12 16:08:41 +00:00
|
|
|
|
|
|
|
### End of not-exported components
|
|
|
|
################################################################################
|
|
|
|
|
|
|
|
################################################################################
|
|
|
|
### Exported procs
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_init(callback: WakuCallback): pointer {.dynlib, exportc, cdecl.} =
|
|
|
|
## Initializes the waku library.
|
2023-07-07 08:53:00 +00:00
|
|
|
|
2023-09-01 06:37:02 +00:00
|
|
|
## Create the Waku thread that will keep waiting for req from the main thread.
|
2023-10-23 06:37:28 +00:00
|
|
|
var ctx = waku_thread.createWakuThread().valueOr:
|
2023-09-01 06:37:02 +00:00
|
|
|
let msg = "Error in createWakuThread: " & $error
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
|
|
|
return nil
|
|
|
|
|
|
|
|
return ctx
|
|
|
|
|
|
|
|
proc waku_new(ctx: ptr ptr Context,
|
|
|
|
configJson: cstring,
|
|
|
|
callback: WakuCallback,
|
|
|
|
userData: pointer): cint
|
|
|
|
{.dynlib, exportc, cdecl.} =
|
|
|
|
## Creates a new instance of the WakuNode.
|
|
|
|
## Notice that the ConfigNode type is also exported and available for users.
|
|
|
|
|
|
|
|
ctx[][].userData = userData
|
|
|
|
|
|
|
|
if isNil(callback):
|
|
|
|
return RET_MISSING_CALLBACK
|
2023-09-01 06:37:02 +00:00
|
|
|
|
|
|
|
let sendReqRes = waku_thread.sendRequestToWakuThread(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[],
|
2023-09-18 07:21:50 +00:00
|
|
|
RequestType.LIFECYCLE,
|
|
|
|
NodeLifecycleRequest.createShared(
|
|
|
|
NodeLifecycleMsgType.CREATE_NODE,
|
|
|
|
configJson))
|
2023-09-01 06:37:02 +00:00
|
|
|
if sendReqRes.isErr():
|
|
|
|
let msg = $sendReqRes.error
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_ERR
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_OK
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_version(ctx: ptr ptr Context,
|
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint {.dynlib, exportc.} =
|
|
|
|
|
|
|
|
ctx[][].userData = userData
|
|
|
|
|
|
|
|
if isNil(callback):
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_MISSING_CALLBACK
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_OK, cast[ptr cchar](WakuNodeVersionString),
|
|
|
|
cast[csize_t](len(WakuNodeVersionString)))
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_OK
|
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
proc waku_set_event_callback(callback: WakuCallBack) {.dynlib, exportc.} =
|
|
|
|
extEventCallback = callback
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_content_topic(ctx: ptr ptr Context,
|
|
|
|
appName: cstring,
|
2023-07-07 08:53:00 +00:00
|
|
|
appVersion: cuint,
|
2023-05-12 16:08:41 +00:00
|
|
|
contentTopicName: cstring,
|
|
|
|
encoding: cstring,
|
2023-10-23 06:37:28 +00:00
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint {.dynlib, exportc.} =
|
2023-05-12 16:08:41 +00:00
|
|
|
# https://rfc.vac.dev/spec/36/#extern-char-waku_content_topicchar-applicationname-unsigned-int-applicationversion-char-contenttopicname-char-encoding
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[][].userData = userData
|
|
|
|
|
|
|
|
if isNil(callback):
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_MISSING_CALLBACK
|
|
|
|
|
|
|
|
let appStr = appName.alloc()
|
|
|
|
let ctnStr = contentTopicName.alloc()
|
|
|
|
let encodingStr = encoding.alloc()
|
|
|
|
|
|
|
|
let contentTopic = fmt"/{$appStr}/{appVersion}/{$ctnStr}/{$encodingStr}"
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_OK, unsafeAddr contentTopic[0], cast[csize_t](len(contentTopic)))
|
2023-07-07 08:53:00 +00:00
|
|
|
|
|
|
|
deallocShared(appStr)
|
|
|
|
deallocShared(ctnStr)
|
|
|
|
deallocShared(encodingStr)
|
|
|
|
|
|
|
|
return RET_OK
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_pubsub_topic(ctx: ptr ptr Context,
|
|
|
|
topicName: cstring,
|
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint {.dynlib, exportc, cdecl.} =
|
|
|
|
# https://rfc.vac.dev/spec/36/#extern-char-waku_pubsub_topicchar-name-char-encoding
|
|
|
|
|
|
|
|
ctx[][].userData = userData
|
|
|
|
|
|
|
|
if isNil(callback):
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_MISSING_CALLBACK
|
|
|
|
|
|
|
|
let topicNameStr = topicName.alloc()
|
|
|
|
|
|
|
|
let outPubsubTopic = fmt"/waku/2/{$topicNameStr}"
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_OK, unsafeAddr outPubsubTopic[0], cast[csize_t](len(outPubsubTopic)))
|
2023-07-07 08:53:00 +00:00
|
|
|
|
|
|
|
deallocShared(topicNameStr)
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_OK
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_default_pubsub_topic(ctx: ptr ptr Context,
|
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint {.dynlib, exportc.} =
|
2023-05-12 16:08:41 +00:00
|
|
|
# https://rfc.vac.dev/spec/36/#extern-char-waku_default_pubsub_topic
|
2023-10-23 06:37:28 +00:00
|
|
|
|
|
|
|
ctx[][].userData = userData
|
|
|
|
|
|
|
|
if isNil(callback):
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_MISSING_CALLBACK
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_OK, cast[ptr cchar](DefaultPubsubTopic), cast[csize_t](len(DefaultPubsubTopic)))
|
2023-07-07 08:53:00 +00:00
|
|
|
|
|
|
|
return RET_OK
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_relay_publish(ctx: ptr ptr Context,
|
|
|
|
pubSubTopic: cstring,
|
2023-05-12 16:08:41 +00:00
|
|
|
jsonWakuMessage: cstring,
|
2023-07-07 08:53:00 +00:00
|
|
|
timeoutMs: cuint,
|
2023-10-23 06:37:28 +00:00
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint
|
2023-05-12 16:08:41 +00:00
|
|
|
|
|
|
|
{.dynlib, exportc, cdecl.} =
|
|
|
|
# https://rfc.vac.dev/spec/36/#extern-char-waku_relay_publishchar-messagejson-char-pubsubtopic-int-timeoutms
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[][].userData = userData
|
|
|
|
|
|
|
|
if isNil(callback):
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_MISSING_CALLBACK
|
|
|
|
|
|
|
|
let jwm = jsonWakuMessage.alloc()
|
2023-05-12 16:08:41 +00:00
|
|
|
var jsonContent:JsonNode
|
|
|
|
try:
|
2023-07-07 08:53:00 +00:00
|
|
|
jsonContent = parseJson($jwm)
|
2023-05-12 16:08:41 +00:00
|
|
|
except JsonParsingError:
|
2023-07-07 08:53:00 +00:00
|
|
|
deallocShared(jwm)
|
|
|
|
let msg = fmt"Error parsing json message: {getCurrentExceptionMsg()}"
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_ERR
|
|
|
|
|
|
|
|
deallocShared(jwm)
|
2023-05-12 16:08:41 +00:00
|
|
|
|
|
|
|
var wakuMessage: WakuMessage
|
|
|
|
try:
|
|
|
|
var version = 0'u32
|
|
|
|
if jsonContent.hasKey("version"):
|
|
|
|
version = (uint32) jsonContent["version"].getInt()
|
|
|
|
|
|
|
|
wakuMessage = WakuMessage(
|
|
|
|
# Visit https://rfc.vac.dev/spec/14/ for further details
|
|
|
|
payload: jsonContent["payload"].getStr().toSeq().mapIt(byte (it)),
|
|
|
|
contentTopic: $jsonContent["content_topic"].getStr(),
|
|
|
|
version: version,
|
|
|
|
timestamp: getTime().toUnix(),
|
|
|
|
ephemeral: false
|
|
|
|
)
|
|
|
|
except KeyError:
|
2023-07-07 08:53:00 +00:00
|
|
|
let msg = fmt"Problem building the WakuMessage: {getCurrentExceptionMsg()}"
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_ERR
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
let pst = pubSubTopic.alloc()
|
|
|
|
|
|
|
|
let targetPubSubTopic = if len(pst) == 0:
|
2023-05-12 16:08:41 +00:00
|
|
|
DefaultPubsubTopic
|
|
|
|
else:
|
2023-07-07 08:53:00 +00:00
|
|
|
$pst
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-08-02 08:45:15 +00:00
|
|
|
let sendReqRes = waku_thread.sendRequestToWakuThread(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[],
|
2023-09-18 07:21:50 +00:00
|
|
|
RequestType.RELAY,
|
|
|
|
RelayRequest.createShared(RelayMsgType.PUBLISH,
|
|
|
|
PubsubTopic($pst),
|
|
|
|
WakuRelayHandler(relayEventCallback),
|
|
|
|
wakuMessage))
|
2023-07-31 07:52:04 +00:00
|
|
|
deallocShared(pst)
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
if sendReqRes.isErr():
|
|
|
|
let msg = $sendReqRes.error
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_ERR
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
return RET_OK
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_start(ctx: ptr ptr Context,
|
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint {.dynlib, exportc.} =
|
|
|
|
|
|
|
|
ctx[][].userData = userData
|
|
|
|
## TODO: handle the error
|
2023-08-02 08:45:15 +00:00
|
|
|
discard waku_thread.sendRequestToWakuThread(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[],
|
2023-09-18 07:21:50 +00:00
|
|
|
RequestType.LIFECYCLE,
|
|
|
|
NodeLifecycleRequest.createShared(
|
|
|
|
NodeLifecycleMsgType.START_NODE))
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_stop(ctx: ptr ptr Context,
|
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint {.dynlib, exportc.} =
|
|
|
|
ctx[][].userData = userData
|
|
|
|
## TODO: handle the error
|
2023-08-02 08:45:15 +00:00
|
|
|
discard waku_thread.sendRequestToWakuThread(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[],
|
2023-09-18 07:21:50 +00:00
|
|
|
RequestType.LIFECYCLE,
|
|
|
|
NodeLifecycleRequest.createShared(
|
|
|
|
NodeLifecycleMsgType.STOP_NODE))
|
2023-05-12 16:08:41 +00:00
|
|
|
|
|
|
|
proc waku_relay_subscribe(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx: ptr ptr Context,
|
2023-05-12 16:08:41 +00:00
|
|
|
pubSubTopic: cstring,
|
2023-10-23 06:37:28 +00:00
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint
|
2023-05-12 16:08:41 +00:00
|
|
|
{.dynlib, exportc.} =
|
2023-07-07 08:53:00 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[][].userData = userData
|
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
let pst = pubSubTopic.alloc()
|
2023-09-18 07:21:50 +00:00
|
|
|
|
2023-08-02 08:45:15 +00:00
|
|
|
let sendReqRes = waku_thread.sendRequestToWakuThread(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[],
|
2023-09-18 07:21:50 +00:00
|
|
|
RequestType.RELAY,
|
|
|
|
RelayRequest.createShared(RelayMsgType.SUBSCRIBE,
|
|
|
|
PubsubTopic($pst),
|
|
|
|
WakuRelayHandler(relayEventCallback)))
|
2023-07-31 07:52:04 +00:00
|
|
|
deallocShared(pst)
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
if sendReqRes.isErr():
|
|
|
|
let msg = $sendReqRes.error
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_ERR
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_OK
|
2023-05-12 16:08:41 +00:00
|
|
|
|
|
|
|
proc waku_relay_unsubscribe(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx: ptr ptr Context,
|
2023-05-12 16:08:41 +00:00
|
|
|
pubSubTopic: cstring,
|
2023-10-23 06:37:28 +00:00
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint
|
2023-05-12 16:08:41 +00:00
|
|
|
{.dynlib, exportc.} =
|
2023-07-07 08:53:00 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[][].userData = userData
|
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
let pst = pubSubTopic.alloc()
|
2023-09-18 07:21:50 +00:00
|
|
|
|
2023-08-02 08:45:15 +00:00
|
|
|
let sendReqRes = waku_thread.sendRequestToWakuThread(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[],
|
2023-09-18 07:21:50 +00:00
|
|
|
RequestType.RELAY,
|
|
|
|
RelayRequest.createShared(RelayMsgType.SUBSCRIBE,
|
|
|
|
PubsubTopic($pst),
|
|
|
|
WakuRelayHandler(relayEventCallback)))
|
2023-07-31 07:52:04 +00:00
|
|
|
deallocShared(pst)
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-31 07:52:04 +00:00
|
|
|
if sendReqRes.isErr():
|
|
|
|
let msg = $sendReqRes.error
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_ERR
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_OK
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
proc waku_connect(ctx: ptr ptr Context,
|
|
|
|
peerMultiAddr: cstring,
|
2023-07-07 08:53:00 +00:00
|
|
|
timeoutMs: cuint,
|
2023-10-23 06:37:28 +00:00
|
|
|
callback: WakuCallBack,
|
|
|
|
userData: pointer): cint
|
2023-05-12 16:08:41 +00:00
|
|
|
{.dynlib, exportc.} =
|
|
|
|
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[][].userData = userData
|
|
|
|
|
2023-08-02 08:45:15 +00:00
|
|
|
let connRes = waku_thread.sendRequestToWakuThread(
|
2023-10-23 06:37:28 +00:00
|
|
|
ctx[],
|
2023-09-18 07:21:50 +00:00
|
|
|
RequestType.PEER_MANAGER,
|
|
|
|
PeerManagementRequest.createShared(
|
2023-07-31 07:52:04 +00:00
|
|
|
PeerManagementMsgType.CONNECT_TO,
|
|
|
|
$peerMultiAddr,
|
|
|
|
chronos.milliseconds(timeoutMs)))
|
|
|
|
if connRes.isErr():
|
|
|
|
let msg = $connRes.error
|
2023-10-23 06:37:28 +00:00
|
|
|
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)))
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_ERR
|
2023-05-12 16:08:41 +00:00
|
|
|
|
2023-07-07 08:53:00 +00:00
|
|
|
return RET_OK
|
2023-05-12 16:08:41 +00:00
|
|
|
|
|
|
|
### End of exported procs
|
2023-06-29 19:59:53 +00:00
|
|
|
################################################################################
|