mirror of
https://github.com/logos-messaging/nim-sds.git
synced 2026-01-09 09:33:06 +00:00
feat: add bindings script
This commit is contained in:
parent
24d6026750
commit
bce0671c7b
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
|
||||
.DS_Store
|
||||
tests/test_reliability
|
||||
tests/bloom
|
||||
nph
|
||||
bindings/generated*
|
||||
do_not_commit
|
||||
|
||||
242
bindings/bindings.nim
Normal file
242
bindings/bindings.nim
Normal file
@ -0,0 +1,242 @@
|
||||
import genny
|
||||
import std/[times, strutils]
|
||||
import results
|
||||
import ../src/[reliability, message, reliability_utils, rolling_bloom_filter]
|
||||
|
||||
# Define required sequence wrapper types for C FFI
|
||||
type
|
||||
SeqByte* = ref object
|
||||
s*: seq[byte]
|
||||
|
||||
SeqMessageID* = ref object
|
||||
s*: seq[MessageID]
|
||||
|
||||
SeqMessage* = ref object
|
||||
s*: seq[Message]
|
||||
|
||||
SeqUnacknowledgedMessage* = ref object
|
||||
s*: seq[UnacknowledgedMessage]
|
||||
|
||||
# Error handling
|
||||
var lastError: ReliabilityError
|
||||
|
||||
proc takeError(): string =
|
||||
result = $lastError
|
||||
lastError = ReliabilityError.reInternalError # Reset to default
|
||||
|
||||
proc checkError(): bool =
|
||||
result = lastError != ReliabilityError.reInternalError
|
||||
|
||||
# Callback function types for C FFI
|
||||
type
|
||||
CMessageReadyCallback* = proc(messageId: cstring) {.cdecl, gcsafe.}
|
||||
CMessageSentCallback* = proc(messageId: cstring) {.cdecl, gcsafe.}
|
||||
CMissingDepsCallback* = proc(messageId: cstring, missingDeps: cstring, count: cint) {.cdecl, gcsafe.}
|
||||
CPeriodicSyncCallback* = proc() {.cdecl, gcsafe.}
|
||||
|
||||
# Global callback storage
|
||||
var
|
||||
onMessageReadyCallback: CMessageReadyCallback
|
||||
onMessageSentCallback: CMessageSentCallback
|
||||
onMissingDepsCallback: CMissingDepsCallback
|
||||
onPeriodicSyncCallback: CPeriodicSyncCallback
|
||||
|
||||
# Register callbacks
|
||||
proc registerMessageReadyCallback*(callback: CMessageReadyCallback) =
|
||||
onMessageReadyCallback = callback
|
||||
|
||||
proc registerMessageSentCallback*(callback: CMessageSentCallback) =
|
||||
onMessageSentCallback = callback
|
||||
|
||||
proc registerMissingDepsCallback*(callback: CMissingDepsCallback) =
|
||||
onMissingDepsCallback = callback
|
||||
|
||||
proc registerPeriodicSyncCallback*(callback: CPeriodicSyncCallback) =
|
||||
onPeriodicSyncCallback = callback
|
||||
|
||||
# Individual adapter functions
|
||||
proc onMessageReadyAdapter(messageId: MessageID) {.gcsafe, raises: [].} =
|
||||
if onMessageReadyCallback != nil:
|
||||
try:
|
||||
onMessageReadyCallback(cstring(messageId))
|
||||
except:
|
||||
discard # Ignore exceptions
|
||||
|
||||
proc onMessageSentAdapter(messageId: MessageID) {.gcsafe, raises: [].} =
|
||||
if onMessageSentCallback != nil:
|
||||
try:
|
||||
onMessageSentCallback(cstring(messageId))
|
||||
except:
|
||||
discard
|
||||
|
||||
proc onMissingDependenciesAdapter(messageId: MessageID, missingDeps: seq[MessageID]) {.gcsafe, raises: [].} =
|
||||
if onMissingDepsCallback != nil and missingDeps.len > 0:
|
||||
try:
|
||||
let joinedDeps = missingDeps.join(",")
|
||||
onMissingDepsCallback(cstring(messageId), cstring(joinedDeps), cint(missingDeps.len))
|
||||
except:
|
||||
discard
|
||||
|
||||
proc onPeriodicSyncAdapter() {.gcsafe, raises: [].} =
|
||||
if onPeriodicSyncCallback != nil:
|
||||
try:
|
||||
onPeriodicSyncCallback()
|
||||
except:
|
||||
discard
|
||||
|
||||
# Apply registered callbacks to a ReliabilityManager
|
||||
proc applyCallbacks*(rm: ReliabilityManager): bool =
|
||||
if rm == nil:
|
||||
lastError = ReliabilityError.reInvalidArgument
|
||||
return false
|
||||
|
||||
try:
|
||||
rm.setCallbacks(
|
||||
onMessageReadyAdapter,
|
||||
onMessageSentAdapter,
|
||||
onMissingDependenciesAdapter,
|
||||
onPeriodicSyncAdapter
|
||||
)
|
||||
return true
|
||||
except:
|
||||
lastError = ReliabilityError.reInternalError
|
||||
return false
|
||||
|
||||
# Wrapper for creating a ReliabilityManager
|
||||
proc safeNewReliabilityManager(channelId: string, config: ReliabilityConfig = defaultConfig()): ReliabilityManager =
|
||||
let res = newReliabilityManager(channelId, config)
|
||||
if res.isOk:
|
||||
return res.get
|
||||
else:
|
||||
lastError = res.error
|
||||
return nil
|
||||
|
||||
# Wrapper for wrapping outgoing messages
|
||||
proc safeWrapOutgoingMessage(rm: ReliabilityManager, message: seq[byte], messageId: MessageID): seq[byte] =
|
||||
if rm == nil:
|
||||
lastError = ReliabilityError.reInvalidArgument
|
||||
return @[]
|
||||
|
||||
let res = rm.wrapOutgoingMessage(message, messageId)
|
||||
if res.isOk:
|
||||
return res.get
|
||||
else:
|
||||
lastError = res.error
|
||||
return @[]
|
||||
|
||||
# Wrapper for unwrapping received messages
|
||||
proc safeUnwrapReceivedMessage(rm: ReliabilityManager, message: seq[byte]): tuple[message: seq[byte], missingDeps: seq[MessageID]] =
|
||||
if rm == nil:
|
||||
lastError = ReliabilityError.reInvalidArgument
|
||||
return (@[], @[])
|
||||
|
||||
let res = rm.unwrapReceivedMessage(message)
|
||||
if res.isOk:
|
||||
return res.get
|
||||
else:
|
||||
lastError = res.error
|
||||
return (@[], @[])
|
||||
|
||||
# Wrapper for marking dependencies as met
|
||||
proc safeMarkDependenciesMet(rm: ReliabilityManager, messageIds: seq[MessageID]): bool =
|
||||
if rm == nil:
|
||||
lastError = ReliabilityError.reInvalidArgument
|
||||
return false
|
||||
|
||||
let res = rm.markDependenciesMet(messageIds)
|
||||
if res.isOk:
|
||||
return true
|
||||
else:
|
||||
lastError = res.error
|
||||
return false
|
||||
|
||||
# Helper to create a Duration from milliseconds
|
||||
proc durationFromMs(ms: int64): Duration =
|
||||
initDuration(milliseconds = ms)
|
||||
|
||||
# Wrapper for creating a ReliabilityConfig with Duration values in milliseconds
|
||||
proc configFromMs(
|
||||
bloomFilterCapacity: int = DefaultBloomFilterCapacity,
|
||||
bloomFilterErrorRate: float = DefaultBloomFilterErrorRate,
|
||||
bloomFilterWindowMs: int64 = 3600000, # 1 hour default
|
||||
maxMessageHistory: int = DefaultMaxMessageHistory,
|
||||
maxCausalHistory: int = DefaultMaxCausalHistory,
|
||||
resendIntervalMs: int64 = 60000, # 1 minute default
|
||||
maxResendAttempts: int = DefaultMaxResendAttempts,
|
||||
syncMessageIntervalMs: int64 = 30000, # 30 seconds default
|
||||
bufferSweepIntervalMs: int64 = 60000 # 1 minute default
|
||||
): ReliabilityConfig =
|
||||
var config = ReliabilityConfig(
|
||||
bloomFilterCapacity: bloomFilterCapacity,
|
||||
bloomFilterErrorRate: bloomFilterErrorRate,
|
||||
bloomFilterWindow: durationFromMs(bloomFilterWindowMs),
|
||||
maxMessageHistory: maxMessageHistory,
|
||||
maxCausalHistory: maxCausalHistory,
|
||||
resendInterval: durationFromMs(resendIntervalMs),
|
||||
maxResendAttempts: maxResendAttempts,
|
||||
syncMessageInterval: durationFromMs(syncMessageIntervalMs),
|
||||
bufferSweepInterval: durationFromMs(bufferSweepIntervalMs)
|
||||
)
|
||||
return config
|
||||
|
||||
# Helper to parse comma-separated string into seq[MessageID]
|
||||
proc parseMessageIDs*(commaSeparated: string): seq[MessageID] =
|
||||
if commaSeparated.len == 0:
|
||||
return @[]
|
||||
return commaSeparated.split(',')
|
||||
|
||||
# Constants
|
||||
exportConsts:
|
||||
DefaultBloomFilterCapacity
|
||||
DefaultBloomFilterErrorRate
|
||||
DefaultMaxMessageHistory
|
||||
DefaultMaxCausalHistory
|
||||
DefaultMaxResendAttempts
|
||||
MaxMessageSize
|
||||
|
||||
# Enums
|
||||
exportEnums:
|
||||
ReliabilityError
|
||||
|
||||
# Helper procs
|
||||
exportProcs:
|
||||
checkError
|
||||
takeError
|
||||
configFromMs
|
||||
durationFromMs
|
||||
parseMessageIDs
|
||||
registerMessageReadyCallback
|
||||
registerMessageSentCallback
|
||||
registerMissingDepsCallback
|
||||
registerPeriodicSyncCallback
|
||||
applyCallbacks
|
||||
|
||||
# Core objects
|
||||
exportObject ReliabilityConfig:
|
||||
constructor:
|
||||
configFromMs(int, float, int64, int, int, int64, int, int64, int64)
|
||||
|
||||
# Main ref object
|
||||
exportRefObject ReliabilityManager:
|
||||
constructor:
|
||||
safeNewReliabilityManager(string, ReliabilityConfig)
|
||||
procs:
|
||||
safeWrapOutgoingMessage(ReliabilityManager, seq[byte], MessageID)
|
||||
safeUnwrapReceivedMessage(ReliabilityManager, seq[byte])
|
||||
safeMarkDependenciesMet(ReliabilityManager, seq[MessageID])
|
||||
checkUnacknowledgedMessages(ReliabilityManager)
|
||||
startPeriodicTasks(ReliabilityManager)
|
||||
cleanup(ReliabilityManager)
|
||||
getMessageHistory(ReliabilityManager)
|
||||
getOutgoingBuffer(ReliabilityManager)
|
||||
getIncomingBuffer(ReliabilityManager)
|
||||
|
||||
# Sequences
|
||||
exportSeq seq[byte]:
|
||||
discard
|
||||
|
||||
exportSeq seq[MessageID]:
|
||||
discard
|
||||
|
||||
# Finally generate the files
|
||||
writeFiles("bindings/generated", "sds_bindings")
|
||||
@ -9,8 +9,25 @@ srcDir = "src"
|
||||
requires "nim >= 2.0.8"
|
||||
requires "chronicles"
|
||||
requires "libp2p"
|
||||
requires "genny >= 0.1.0"
|
||||
|
||||
# Tasks
|
||||
task test, "Run the test suite":
|
||||
exec "nim c -r tests/test_bloom.nim"
|
||||
exec "nim c -r tests/test_reliability.nim"
|
||||
exec "nim c -r tests/test_reliability.nim"
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
else:
|
||||
compile "libsds.so"
|
||||
Loading…
x
Reference in New Issue
Block a user