mirror of
https://github.com/logos-messaging/nim-sds.git
synced 2026-01-02 14:13:07 +00:00
start refactor
This commit is contained in:
parent
bd4c81c73d
commit
a1835cc678
4
Makefile
Normal file
4
Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
.PHONY: libsds
|
||||
|
||||
libsds:
|
||||
nim c --app:lib --mm:refc --outdir:build library/libsds.nim
|
||||
Binary file not shown.
@ -3,29 +3,34 @@ import chronos
|
||||
import results
|
||||
import ../src/[reliability, reliability_utils, message]
|
||||
|
||||
type
|
||||
CReliabilityManagerHandle* = pointer
|
||||
type CReliabilityManagerHandle* = pointer
|
||||
|
||||
type
|
||||
# Callback Types (Imported from C Header)
|
||||
CEventType* {.importc: "CEventType", header: "bindings.h", pure.} = enum
|
||||
EVENT_MESSAGE_READY = 1,
|
||||
EVENT_MESSAGE_SENT = 2,
|
||||
EVENT_MISSING_DEPENDENCIES = 3,
|
||||
CEventType* {.importc: "CEventType", header: "libsds.h", pure.} = enum
|
||||
EVENT_MESSAGE_READY = 1
|
||||
EVENT_MESSAGE_SENT = 2
|
||||
EVENT_MISSING_DEPENDENCIES = 3
|
||||
EVENT_PERIODIC_SYNC = 4
|
||||
|
||||
CEventCallback* = proc(handle: pointer, eventType: CEventType, data1: pointer, data2: pointer, data3: csize_t) {.cdecl.} # Use csize_t
|
||||
CEventCallback* = proc(
|
||||
handle: pointer,
|
||||
eventType: CEventType,
|
||||
data1: pointer,
|
||||
data2: pointer,
|
||||
data3: csize_t,
|
||||
) {.cdecl.} # Use csize_t
|
||||
|
||||
CResult* {.importc: "CResult", header: "bindings.h", bycopy.} = object
|
||||
CResult* {.importc: "CResult", header: "libsds.h", bycopy.} = object
|
||||
is_ok*: bool
|
||||
error_message*: cstring
|
||||
|
||||
CWrapResult* {.importc: "CWrapResult", header: "bindings.h", bycopy.} = object
|
||||
CWrapResult* {.importc: "CWrapResult", header: "libsds.h", bycopy.} = object
|
||||
base_result*: CResult
|
||||
message*: pointer
|
||||
message_len*: csize_t
|
||||
|
||||
CUnwrapResult* {.importc: "CUnwrapResult", header: "bindings.h", bycopy.} = object
|
||||
CUnwrapResult* {.importc: "CUnwrapResult", header: "libsds.h", bycopy.} = object
|
||||
base_result*: CResult
|
||||
message*: pointer
|
||||
message_len*: csize_t
|
||||
@ -33,8 +38,7 @@ type
|
||||
missing_deps_count*: csize_t
|
||||
|
||||
# --- Callback Registry ---
|
||||
type
|
||||
CallbackRegistry = Table[CReliabilityManagerHandle, CEventCallback]
|
||||
type CallbackRegistry = Table[CReliabilityManagerHandle, CEventCallback]
|
||||
|
||||
var
|
||||
callbackRegistry: CallbackRegistry
|
||||
@ -45,41 +49,48 @@ initLock(registryLock)
|
||||
# --- Memory Management Helpers ---
|
||||
|
||||
proc allocCString*(s: string): cstring {.inline, gcsafe.} =
|
||||
if s.len == 0: return nil
|
||||
if s.len == 0:
|
||||
return nil
|
||||
result = cast[cstring](allocShared(s.len + 1))
|
||||
copyMem(result, s.cstring, s.len + 1)
|
||||
|
||||
proc allocSeqByte*(s: seq[byte]): (pointer, csize_t) {.inline, gcsafe.} =
|
||||
if s.len == 0: return (nil, 0)
|
||||
if s.len == 0:
|
||||
return (nil, 0)
|
||||
let len = s.len
|
||||
let bufferPtr = allocShared(len)
|
||||
if len > 0:
|
||||
copyMem(bufferPtr, cast[pointer](s[0].unsafeAddr), len.Natural)
|
||||
return (bufferPtr, len.csize_t)
|
||||
|
||||
proc allocSeqCString*(s: seq[string]): (ptr cstring, csize_t) {.inline, gcsafe, cdecl.} =
|
||||
if s.len == 0: return (nil, 0)
|
||||
proc allocSeqCString*(
|
||||
s: seq[string]
|
||||
): (ptr cstring, csize_t) {.inline, gcsafe, cdecl.} =
|
||||
if s.len == 0:
|
||||
return (nil, 0)
|
||||
let count = s.len
|
||||
# Allocate memory for 'count' cstring pointers, cast to ptr UncheckedArray
|
||||
let arrPtr = cast[ptr UncheckedArray[cstring]](allocShared(count * sizeof(cstring)))
|
||||
for i in 0..<count:
|
||||
for i in 0 ..< count:
|
||||
# Allocate each string and store its pointer in the array using unchecked array indexing
|
||||
arrPtr[i] = allocCString(s[i])
|
||||
# Return pointer to the first element, cast back to ptr cstring
|
||||
return (cast[ptr cstring](arrPtr), count.csize_t)
|
||||
|
||||
proc freeCString*(cs: cstring) {.inline, gcsafe.} =
|
||||
if cs != nil: deallocShared(cs)
|
||||
if cs != nil:
|
||||
deallocShared(cs)
|
||||
|
||||
proc freeSeqByte*(bufferPtr: pointer) {.inline, gcsafe, cdecl.} =
|
||||
if bufferPtr != nil: deallocShared(bufferPtr)
|
||||
if bufferPtr != nil:
|
||||
deallocShared(bufferPtr)
|
||||
|
||||
# Corrected to accept ptr cstring
|
||||
proc freeSeqCString*(arrPtr: ptr cstring, count: csize_t) {.inline, gcsafe, cdecl.} =
|
||||
if arrPtr != nil:
|
||||
# Cast to ptr UncheckedArray for proper iteration/indexing before freeing
|
||||
let arr = cast[ptr UncheckedArray[cstring]](arrPtr)
|
||||
for i in 0..<count:
|
||||
for i in 0 ..< count:
|
||||
freeCString(arr[i]) # Free each individual cstring
|
||||
deallocShared(arrPtr) # Free the array pointer itself
|
||||
|
||||
@ -106,7 +117,7 @@ proc nimMessageReadyCallback(rm: ReliabilityManager, messageId: MessageID) =
|
||||
echo "[Nim Binding] No callback registered for handle: ", cast[int](handle)
|
||||
return
|
||||
cb = callbackRegistry[handle]
|
||||
|
||||
|
||||
# Pass handle, event type, and messageId (as data1)
|
||||
cb(handle, EVENT_MESSAGE_READY, cast[pointer](messageId.cstring), nil, 0)
|
||||
|
||||
@ -119,11 +130,14 @@ proc nimMessageSentCallback(rm: ReliabilityManager, messageId: MessageID) =
|
||||
echo "[Nim Binding] No callback registered for handle: ", cast[int](handle)
|
||||
return
|
||||
cb = callbackRegistry[handle]
|
||||
|
||||
|
||||
cb(handle, EVENT_MESSAGE_SENT, cast[pointer](messageId.cstring), nil, 0)
|
||||
|
||||
proc nimMissingDependenciesCallback(rm: ReliabilityManager, messageId: MessageID, missingDeps: seq[MessageID]) =
|
||||
echo "[Nim Binding] nimMissingDependenciesCallback called for: ", messageId, " with deps: ", $missingDeps
|
||||
proc nimMissingDependenciesCallback(
|
||||
rm: ReliabilityManager, messageId: MessageID, missingDeps: seq[MessageID]
|
||||
) =
|
||||
echo "[Nim Binding] nimMissingDependenciesCallback called for: ",
|
||||
messageId, " with deps: ", $missingDeps
|
||||
let handle = cast[CReliabilityManagerHandle](rm)
|
||||
var cb: CEventCallback
|
||||
withLock registryLock:
|
||||
@ -143,7 +157,13 @@ proc nimMissingDependenciesCallback(rm: ReliabilityManager, messageId: MessageID
|
||||
cDepsPtr = cast[ptr cstring](cDepsNim[0].addr)
|
||||
cDepsCount = missingDeps.len.csize_t
|
||||
|
||||
cb(handle, EVENT_MISSING_DEPENDENCIES, cast[pointer](messageId.cstring), cast[pointer](cDepsPtr), cDepsCount)
|
||||
cb(
|
||||
handle,
|
||||
EVENT_MISSING_DEPENDENCIES,
|
||||
cast[pointer](messageId.cstring),
|
||||
cast[pointer](cDepsPtr),
|
||||
cDepsCount,
|
||||
)
|
||||
|
||||
proc nimPeriodicSyncCallback(rm: ReliabilityManager) =
|
||||
echo "[Nim Binding] nimPeriodicSyncCallback called"
|
||||
@ -154,12 +174,14 @@ proc nimPeriodicSyncCallback(rm: ReliabilityManager) =
|
||||
echo "[Nim Binding] No callback registered for handle: ", cast[int](handle)
|
||||
return
|
||||
cb = callbackRegistry[handle]
|
||||
|
||||
|
||||
cb(handle, EVENT_PERIODIC_SYNC, nil, nil, 0)
|
||||
|
||||
# --- Exported C Functions - Using Opaque Pointer ---
|
||||
|
||||
proc NewReliabilityManager*(channelIdCStr: cstring): CReliabilityManagerHandle {.exportc, dynlib, cdecl, gcsafe.} =
|
||||
proc NewReliabilityManager*(
|
||||
channelIdCStr: cstring
|
||||
): CReliabilityManagerHandle {.exportc, dynlib, cdecl, gcsafe.} =
|
||||
let channelId = $channelIdCStr
|
||||
if channelId.len == 0:
|
||||
echo "Error creating ReliabilityManager: Channel ID cannot be empty"
|
||||
@ -169,10 +191,14 @@ proc NewReliabilityManager*(channelIdCStr: cstring): CReliabilityManagerHandle {
|
||||
let rm = rmResult.get()
|
||||
# Assign anonymous procs that capture 'rm' and call the wrappers
|
||||
# Ensure signatures match the non-gcsafe fields in ReliabilityManager
|
||||
rm.onMessageReady = proc(msgId: MessageID) = nimMessageReadyCallback(rm, msgId)
|
||||
rm.onMessageSent = proc(msgId: MessageID) = nimMessageSentCallback(rm, msgId)
|
||||
rm.onMissingDependencies = proc(msgId: MessageID, deps: seq[MessageID]) = nimMissingDependenciesCallback(rm, msgId, deps)
|
||||
rm.onPeriodicSync = proc() = nimPeriodicSyncCallback(rm)
|
||||
rm.onMessageReady = proc(msgId: MessageID) =
|
||||
nimMessageReadyCallback(rm, msgId)
|
||||
rm.onMessageSent = proc(msgId: MessageID) =
|
||||
nimMessageSentCallback(rm, msgId)
|
||||
rm.onMissingDependencies = proc(msgId: MessageID, deps: seq[MessageID]) =
|
||||
nimMissingDependenciesCallback(rm, msgId, deps)
|
||||
rm.onPeriodicSync = proc() =
|
||||
nimPeriodicSyncCallback(rm)
|
||||
|
||||
# Return the Nim ref object cast to the opaque pointer type
|
||||
let handle = cast[CReliabilityManagerHandle](rm)
|
||||
@ -182,7 +208,9 @@ proc NewReliabilityManager*(channelIdCStr: cstring): CReliabilityManagerHandle {
|
||||
echo "Error creating ReliabilityManager: ", rmResult.error
|
||||
return nil # Return nil pointer
|
||||
|
||||
proc CleanupReliabilityManager*(handle: CReliabilityManagerHandle) {.exportc, dynlib, cdecl.} =
|
||||
proc CleanupReliabilityManager*(
|
||||
handle: CReliabilityManagerHandle
|
||||
) {.exportc, dynlib, cdecl.} =
|
||||
let handlePtr = handle
|
||||
if handlePtr != nil:
|
||||
# Go side should handle removing the handle from its registry.
|
||||
@ -196,7 +224,9 @@ proc CleanupReliabilityManager*(handle: CReliabilityManagerHandle) {.exportc, dy
|
||||
else:
|
||||
echo "Warning: CleanupReliabilityManager called with NULL handle"
|
||||
|
||||
proc ResetReliabilityManager*(handle: CReliabilityManagerHandle): CResult {.exportc, dynlib, cdecl, gcsafe.} =
|
||||
proc ResetReliabilityManager*(
|
||||
handle: CReliabilityManagerHandle
|
||||
): CResult {.exportc, dynlib, cdecl, gcsafe.} =
|
||||
if handle == nil:
|
||||
return toCResultErrStr("ReliabilityManager handle is NULL")
|
||||
let rm = cast[ReliabilityManager](handle)
|
||||
@ -206,15 +236,23 @@ proc ResetReliabilityManager*(handle: CReliabilityManagerHandle): CResult {.expo
|
||||
else:
|
||||
return toCResultErr(result.error)
|
||||
|
||||
proc WrapOutgoingMessage*(handle: CReliabilityManagerHandle, messageC: pointer, messageLen: csize_t, messageIdCStr: cstring): CWrapResult {.exportc, dynlib, cdecl.} = # Keep non-gcsafe
|
||||
proc WrapOutgoingMessage*(
|
||||
handle: CReliabilityManagerHandle,
|
||||
messageC: pointer,
|
||||
messageLen: csize_t,
|
||||
messageIdCStr: cstring,
|
||||
): CWrapResult {.exportc, dynlib, cdecl.} = # Keep non-gcsafe
|
||||
if handle == nil:
|
||||
return CWrapResult(base_result: toCResultErrStr("ReliabilityManager handle is NULL"))
|
||||
return
|
||||
CWrapResult(base_result: toCResultErrStr("ReliabilityManager handle is NULL"))
|
||||
let rm = cast[ReliabilityManager](handle)
|
||||
|
||||
if messageC == nil and messageLen > 0:
|
||||
return CWrapResult(base_result: toCResultErrStr("Message pointer is NULL but length > 0"))
|
||||
return CWrapResult(
|
||||
base_result: toCResultErrStr("Message pointer is NULL but length > 0")
|
||||
)
|
||||
if messageIdCStr == nil:
|
||||
return CWrapResult(base_result: toCResultErrStr("Message ID pointer is NULL"))
|
||||
return CWrapResult(base_result: toCResultErrStr("Message ID pointer is NULL"))
|
||||
|
||||
let messageId = $messageIdCStr
|
||||
var messageNim: seq[byte]
|
||||
@ -228,20 +266,23 @@ proc WrapOutgoingMessage*(handle: CReliabilityManagerHandle, messageC: pointer,
|
||||
if wrapResult.isOk:
|
||||
let (wrappedDataPtr, wrappedDataLen) = allocSeqByte(wrapResult.get())
|
||||
return CWrapResult(
|
||||
base_result: toCResultOk(),
|
||||
message: wrappedDataPtr,
|
||||
message_len: wrappedDataLen
|
||||
base_result: toCResultOk(), message: wrappedDataPtr, message_len: wrappedDataLen
|
||||
)
|
||||
else:
|
||||
return CWrapResult(base_result: toCResultErr(wrapResult.error))
|
||||
|
||||
proc UnwrapReceivedMessage*(handle: CReliabilityManagerHandle, messageC: pointer, messageLen: csize_t): CUnwrapResult {.exportc, dynlib, cdecl.} = # Keep non-gcsafe
|
||||
proc UnwrapReceivedMessage*(
|
||||
handle: CReliabilityManagerHandle, messageC: pointer, messageLen: csize_t
|
||||
): CUnwrapResult {.exportc, dynlib, cdecl.} = # Keep non-gcsafe
|
||||
if handle == nil:
|
||||
return CUnwrapResult(base_result: toCResultErrStr("ReliabilityManager handle is NULL"))
|
||||
return
|
||||
CUnwrapResult(base_result: toCResultErrStr("ReliabilityManager handle is NULL"))
|
||||
let rm = cast[ReliabilityManager](handle)
|
||||
|
||||
if messageC == nil and messageLen > 0:
|
||||
return CUnwrapResult(base_result: toCResultErrStr("Message pointer is NULL but length > 0"))
|
||||
return CUnwrapResult(
|
||||
base_result: toCResultErrStr("Message pointer is NULL but length > 0")
|
||||
)
|
||||
|
||||
var messageNim: seq[byte]
|
||||
if messageLen > 0:
|
||||
@ -260,12 +301,14 @@ proc UnwrapReceivedMessage*(handle: CReliabilityManagerHandle, messageC: pointer
|
||||
message: contentPtr,
|
||||
message_len: contentLen,
|
||||
missing_deps: depsPtr,
|
||||
missing_deps_count: depsCount
|
||||
missing_deps_count: depsCount,
|
||||
)
|
||||
else:
|
||||
return CUnwrapResult(base_result: toCResultErr(unwrapResult.error))
|
||||
|
||||
proc MarkDependenciesMet*(handle: CReliabilityManagerHandle, messageIDsC: ptr cstring, count: csize_t): CResult {.exportc, dynlib, cdecl.} = # Keep non-gcsafe
|
||||
proc MarkDependenciesMet*(
|
||||
handle: CReliabilityManagerHandle, messageIDsC: ptr cstring, count: csize_t
|
||||
): CResult {.exportc, dynlib, cdecl.} = # Keep non-gcsafe
|
||||
if handle == nil:
|
||||
return toCResultErrStr("ReliabilityManager handle is NULL")
|
||||
let rm = cast[ReliabilityManager](handle)
|
||||
@ -276,7 +319,7 @@ proc MarkDependenciesMet*(handle: CReliabilityManagerHandle, messageIDsC: ptr cs
|
||||
var messageIDsNim = newSeq[string](count)
|
||||
# Cast to ptr UncheckedArray for indexing
|
||||
let messageIDsCArray = cast[ptr UncheckedArray[cstring]](messageIDsC)
|
||||
for i in 0..<count:
|
||||
for i in 0 ..< count:
|
||||
let currentCStr = messageIDsCArray[i] # Use unchecked array indexing
|
||||
if currentCStr != nil:
|
||||
messageIDsNim[i] = $currentCStr
|
||||
@ -289,9 +332,11 @@ proc MarkDependenciesMet*(handle: CReliabilityManagerHandle, messageIDsC: ptr cs
|
||||
else:
|
||||
return toCResultErr(result.error)
|
||||
|
||||
proc RegisterCallback*(handle: CReliabilityManagerHandle,
|
||||
cEventCallback: CEventCallback,
|
||||
cUserDataPtr: pointer) {.exportc, dynlib, cdecl.} =
|
||||
proc RegisterCallback*(
|
||||
handle: CReliabilityManagerHandle,
|
||||
cEventCallback: CEventCallback,
|
||||
cUserDataPtr: pointer,
|
||||
) {.exportc, dynlib, cdecl.} =
|
||||
withLock registryLock:
|
||||
callbackRegistry[handle] = cEventCallback
|
||||
echo "[Nim Binding] Registered callback for handle: ", cast[int](handle)
|
||||
@ -17,16 +17,13 @@ task test, "Run the test suite":
|
||||
|
||||
task bindings, "Generate bindings":
|
||||
proc compile(libName: string, flags = "") =
|
||||
exec "nim c -f " & flags & " -d:release --app:lib --mm:arc --tlsEmulation:off --out:" & libName & " --outdir:bindings/generated bindings/bindings.nim"
|
||||
|
||||
# Create required directories
|
||||
mkDir "bindings/generated"
|
||||
exec "nim c -f " & flags & " -d:release --app:lib --mm:arc --tlsEmulation:off --out:" & libName & " --outdir:build library/libsds.nim"
|
||||
|
||||
when defined(windows):
|
||||
compile "reliability.dll"
|
||||
elif defined(macosx):
|
||||
compile "libsds.dylib.arm", "--cpu:arm64 -l:'-target arm64-apple-macos11' -t:'-target arm64-apple-macos11'"
|
||||
compile "libsds.dylib.x64", "--cpu:amd64 -l:'-target x86_64-apple-macos10.12' -t:'-target x86_64-apple-macos10.12'"
|
||||
exec "lipo bindings/generated/libsds.dylib.arm bindings/generated/libsds.dylib.x64 -output bindings/generated/libsds.dylib -create"
|
||||
exec "lipo build/libsds.dylib.arm build/libsds.dylib.x64 -output build/libsds.dylib -create"
|
||||
else:
|
||||
compile "libsds.so"
|
||||
@ -1,12 +1,12 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I${SRCDIR}/bindings
|
||||
#cgo LDFLAGS: -L${SRCDIR}/bindings/generated -lbindings
|
||||
#cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/bindings/generated
|
||||
#cgo CFLAGS: -I${SRCDIR}/library
|
||||
#cgo LDFLAGS: -L${SRCDIR}/build -lbindings
|
||||
#cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/build
|
||||
|
||||
#include <stdlib.h> // For C.free
|
||||
#include "bindings/bindings.h" // Update include path
|
||||
#include "library/libsds.h" // Update include path
|
||||
|
||||
// Forward declaration for the single Go callback relay function
|
||||
extern void globalCallbackRelay(void* handle, CEventType eventType, void* data1, void* data2, size_t data3);
|
||||
@ -229,6 +229,7 @@ func StartPeriodicTasks(handle ReliabilityManagerHandle) error {
|
||||
|
||||
// globalCallbackRelay is called by Nim for all events.
|
||||
// It uses the handle to find the correct Go Callbacks struct and dispatch the call.
|
||||
//
|
||||
//export globalCallbackRelay
|
||||
func globalCallbackRelay(handle unsafe.Pointer, eventType C.CEventType, data1 unsafe.Pointer, data2 unsafe.Pointer, data3 C.size_t) {
|
||||
goHandle := ReliabilityManagerHandle(handle)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user