diff --git a/go.mod b/go.mod index bec7095..6cf698c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/waku-org/sds-go-bindings -go 1.23 +go 1.24.0 require ( github.com/stretchr/testify v1.8.1 diff --git a/go.sum b/go.sum index ea719a5..d99d513 100644 --- a/go.sum +++ b/go.sum @@ -10,10 +10,13 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/sds/Makefile b/sds/Makefile index b51a569..49194f6 100644 --- a/sds/Makefile +++ b/sds/Makefile @@ -1,43 +1,53 @@ # Makefile for SDS Go Bindings -# Directories -THIRD_PARTY_DIR := ../third_party -NIM_SDS_REPO := https://github.com/waku-org/nim-sds -NIM_SDS_DIR := $(THIRD_PARTY_DIR)/nim-sds +# The NIM_SDS_LIB_PATH and NIM_SDS_HEADER_PATH env vars should be defined beforehand +# Therefore, we assume the libsds library and headers are located in the specified paths +export CGO_CFLAGS="-I${NIM_SDS_HEADER_PATH}/" +export CGO_LDFLAGS="-L${NIM_SDS_LIB_PATH}/ -lsds -Wl,-rpath,${NIM_SDS_LIB_PATH}/" + +# Expected files +HEADER_FILE := $(NIM_SDS_HEADER_PATH)/libsds.h +LIB_FILES := $(wildcard $(NIM_SDS_LIB_PATH)/libsds.*) .PHONY: all clean prepare build-libsds build # Default target all: build -# Prepare third_party directory and clone nim-sds -prepare: - @echo "Creating third_party directory..." - @mkdir -p $(THIRD_PARTY_DIR) - - @echo "Cloning nim-sds repository..." - @if [ ! -d "$(NIM_SDS_DIR)" ]; then \ - cd $(THIRD_PARTY_DIR) && \ - git clone $(NIM_SDS_REPO) && \ - cd $(NIM_SDS_DIR) && \ - git checkout master; \ - make update; \ - else \ - echo "nim-sds repository already exists."; \ +# Validate necessary folders and files +check-folders: + @echo Checking header directory ... + @if [ -z "$(NIM_SDS_HEADER_PATH)" ]; then \ + echo "ERROR: NIM_SDS_HEADER_PATH not set"; exit 1; \ + fi + @if [ ! -d "$(NIM_SDS_HEADER_PATH)" ]; then \ + echo "ERROR: Header path does not exist: $(NIM_SDS_HEADER_PATH)"; exit 1; \ fi -# Build libsds -build-libsds: prepare - @echo "Building libsds..." - @cd $(NIM_SDS_DIR) && make libsds + @echo Checking lib directory ... + @if [ -z "$(NIM_SDS_LIB_PATH)" ]; then \ + echo "ERROR: NIM_SDS_LIB_PATH not set"; exit 1; \ + fi + @if [ ! -d "$(NIM_SDS_LIB_PATH)" ]; then \ + echo "ERROR: Library path does not exist: $(NIM_SDS_LIB_PATH)"; exit 1; \ + fi + + @echo Checking for libsds.h ... + @if [ ! -f "$(HEADER_FILE)" ]; then \ + echo "ERROR: libsds.h not found at: $(HEADER_FILE)"; exit 1; \ + fi + + @echo Checking for libsds library file ... + @if [ -z "$(LIB_FILES)" ]; then \ + echo "ERROR: No libsds library file found in: $(NIM_SDS_LIB_PATH)"; exit 1; \ + fi # Build SDS Go Bindings -build: build-libsds +build: check-folders @echo "Building SDS Go Bindings..." go build ./... # Clean up generated files clean: @echo "Cleaning up..." - @rm -rf $(THIRD_PARTY_DIR) - @rm -f sds-go-bindings \ No newline at end of file + @rm -f sds-go-bindings diff --git a/sds/generate.go b/sds/generate.go deleted file mode 100644 index 93c4505..0000000 --- a/sds/generate.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build ignore -// +build ignore - -package sds - -// This file contains the go:generate directive for building SDS native code. - -//go:generate sh -c "cd sds && make build" diff --git a/sds/sds.go b/sds/sds.go index cd8168e..386d79b 100644 --- a/sds/sds.go +++ b/sds/sds.go @@ -1,10 +1,9 @@ +//go:build !lint + package sds /* - #cgo LDFLAGS: -L../third_party/nim-sds/build/ -lsds - #cgo LDFLAGS: -L../third_party/nim-sds -Wl,-rpath,../third_party/nim-sds/build/ - - #include "../third_party/nim-sds/library/libsds.h" + #include #include #include @@ -136,13 +135,9 @@ import ( "strconv" "strings" "sync" - "time" "unsafe" ) -const requestTimeout = 30 * time.Second -const EventChanBufferSize = 1024 - //export SdsGoCallback func SdsGoCallback(ret C.int, msg *C.char, len C.size_t, resp unsafe.Pointer) { if resp != nil { @@ -155,19 +150,6 @@ func SdsGoCallback(ret C.int, msg *C.char, len C.size_t, resp unsafe.Pointer) { } } -type EventCallbacks struct { - OnMessageReady func(messageId MessageID, channelId string) - OnMessageSent func(messageId MessageID, channelId string) - OnMissingDependencies func(messageId MessageID, missingDeps []MessageID, channelId string) - OnPeriodicSync func() -} - -// ReliabilityManager represents an instance of a nim-sds ReliabilityManager -type ReliabilityManager struct { - rmCtx unsafe.Pointer - callbacks EventCallbacks -} - func NewReliabilityManager() (*ReliabilityManager, error) { Debug("Creating new Reliability Manager") rm := &ReliabilityManager{} @@ -194,29 +176,6 @@ func NewReliabilityManager() (*ReliabilityManager, error) { return rm, nil } -// The event callback sends back the rm ctx to know to which -// rm is the event being emited for. Since we only have a global -// callback in the go side, We register all the rm's that we create -// so we can later obtain which instance of `ReliabilityManager` it should -// be invoked depending on the ctx received - -var rmRegistry map[unsafe.Pointer]*ReliabilityManager - -func init() { - rmRegistry = make(map[unsafe.Pointer]*ReliabilityManager) -} - -func registerReliabilityManager(rm *ReliabilityManager) { - _, ok := rmRegistry[rm.rmCtx] - if !ok { - rmRegistry[rm.rmCtx] = rm - } -} - -func unregisterReliabilityManager(rm *ReliabilityManager) { - delete(rmRegistry, rm.rmCtx) -} - //export sdsGlobalEventCallback func sdsGlobalEventCallback(callerRet C.int, msg *C.char, len C.size_t, userData unsafe.Pointer) { if callerRet == C.RET_OK { @@ -235,89 +194,6 @@ func sdsGlobalEventCallback(callerRet C.int, msg *C.char, len C.size_t, userData } } -type jsonEvent struct { - EventType string `json:"eventType"` -} - -type msgEvent struct { - MessageId MessageID `json:"messageId"` - ChannelId string `json:"channelId"` -} - -type missingDepsEvent struct { - MessageId MessageID `json:"messageId"` - MissingDeps []MessageID `json:"missingDeps"` - ChannelId string `json:"channelId"` -} - -func (rm *ReliabilityManager) RegisterCallbacks(callbacks EventCallbacks) { - rm.callbacks = callbacks -} - -func (rm *ReliabilityManager) OnEvent(eventStr string) { - - jsonEvent := jsonEvent{} - err := json.Unmarshal([]byte(eventStr), &jsonEvent) - if err != nil { - Error("could not unmarshal sds event string: %v", err) - - return - } - - switch jsonEvent.EventType { - case "message_ready": - rm.parseMessageReadyEvent(eventStr) - case "message_sent": - rm.parseMessageSentEvent(eventStr) - case "missing_dependencies": - rm.parseMissingDepsEvent(eventStr) - case "periodic_sync": - if rm.callbacks.OnPeriodicSync != nil { - rm.callbacks.OnPeriodicSync() - } - } - -} - -func (rm *ReliabilityManager) parseMessageReadyEvent(eventStr string) { - - msgEvent := msgEvent{} - err := json.Unmarshal([]byte(eventStr), &msgEvent) - if err != nil { - Error("could not parse message ready event %v", err) - } - - if rm.callbacks.OnMessageReady != nil { - rm.callbacks.OnMessageReady(msgEvent.MessageId, msgEvent.ChannelId) - } -} - -func (rm *ReliabilityManager) parseMessageSentEvent(eventStr string) { - - msgEvent := msgEvent{} - err := json.Unmarshal([]byte(eventStr), &msgEvent) - if err != nil { - Error("could not parse message sent event %v", err) - } - - if rm.callbacks.OnMessageSent != nil { - rm.callbacks.OnMessageSent(msgEvent.MessageId, msgEvent.ChannelId) - } -} - -func (rm *ReliabilityManager) parseMissingDepsEvent(eventStr string) { - - missingDepsEvent := missingDepsEvent{} - err := json.Unmarshal([]byte(eventStr), &missingDepsEvent) - if err != nil { - Error("could not parse missing dependencies event %v", err) - } - - if rm.callbacks.OnMissingDependencies != nil { - rm.callbacks.OnMissingDependencies(missingDepsEvent.MessageId, missingDepsEvent.MissingDeps, missingDepsEvent.ChannelId) - } -} - func (rm *ReliabilityManager) Cleanup() error { if rm == nil { err := errors.New("reliability manager is nil in Cleanup") diff --git a/sds/sds_common.go b/sds/sds_common.go new file mode 100644 index 0000000..32b9f05 --- /dev/null +++ b/sds/sds_common.go @@ -0,0 +1,122 @@ +package sds + +import ( + "encoding/json" + "time" + "unsafe" +) + +const requestTimeout = 30 * time.Second +const EventChanBufferSize = 1024 + +type EventCallbacks struct { + OnMessageReady func(messageId MessageID, channelId string) + OnMessageSent func(messageId MessageID, channelId string) + OnMissingDependencies func(messageId MessageID, missingDeps []MessageID, channelId string) + OnPeriodicSync func() +} + +// ReliabilityManager represents an instance of a nim-sds ReliabilityManager +type ReliabilityManager struct { + rmCtx unsafe.Pointer + callbacks EventCallbacks +} + +// The event callback sends back the rm ctx to know to which +// rm is the event being emited for. Since we only have a global +// callback in the go side, We register all the rm's that we create +// so we can later obtain which instance of `ReliabilityManager` it should +// be invoked depending on the ctx received +var rmRegistry map[unsafe.Pointer]*ReliabilityManager + +func init() { + rmRegistry = make(map[unsafe.Pointer]*ReliabilityManager) +} + +func registerReliabilityManager(rm *ReliabilityManager) { + _, ok := rmRegistry[rm.rmCtx] + if !ok { + rmRegistry[rm.rmCtx] = rm + } +} + +func unregisterReliabilityManager(rm *ReliabilityManager) { + delete(rmRegistry, rm.rmCtx) +} + +type jsonEvent struct { + EventType string `json:"eventType"` +} + +type msgEvent struct { + MessageId MessageID `json:"messageId"` + ChannelId string `json:"channelId"` +} + +type missingDepsEvent struct { + MessageId MessageID `json:"messageId"` + MissingDeps []MessageID `json:"missingDeps"` + ChannelId string `json:"channelId"` +} + +func (rm *ReliabilityManager) RegisterCallbacks(callbacks EventCallbacks) { + rm.callbacks = callbacks +} + +func (rm *ReliabilityManager) OnEvent(eventStr string) { + jsonEvent := jsonEvent{} + err := json.Unmarshal([]byte(eventStr), &jsonEvent) + if err != nil { + Error("could not unmarshal sds event string: %v", err) + return + } + + switch jsonEvent.EventType { + case "message_ready": + rm.parseMessageReadyEvent(eventStr) + case "message_sent": + rm.parseMessageSentEvent(eventStr) + case "missing_dependencies": + rm.parseMissingDepsEvent(eventStr) + case "periodic_sync": + if rm.callbacks.OnPeriodicSync != nil { + rm.callbacks.OnPeriodicSync() + } + } +} + +func (rm *ReliabilityManager) parseMessageReadyEvent(eventStr string) { + msgEvent := msgEvent{} + err := json.Unmarshal([]byte(eventStr), &msgEvent) + if err != nil { + Error("could not parse message ready event %v", err) + } + + if rm.callbacks.OnMessageReady != nil { + rm.callbacks.OnMessageReady(msgEvent.MessageId, msgEvent.ChannelId) + } +} + +func (rm *ReliabilityManager) parseMessageSentEvent(eventStr string) { + msgEvent := msgEvent{} + err := json.Unmarshal([]byte(eventStr), &msgEvent) + if err != nil { + Error("could not parse message sent event %v", err) + } + + if rm.callbacks.OnMessageSent != nil { + rm.callbacks.OnMessageSent(msgEvent.MessageId, msgEvent.ChannelId) + } +} + +func (rm *ReliabilityManager) parseMissingDepsEvent(eventStr string) { + missingDepsEvent := missingDepsEvent{} + err := json.Unmarshal([]byte(eventStr), &missingDepsEvent) + if err != nil { + Error("could not parse missing dependencies event %v", err) + } + + if rm.callbacks.OnMissingDependencies != nil { + rm.callbacks.OnMissingDependencies(missingDepsEvent.MessageId, missingDepsEvent.MissingDeps, missingDepsEvent.ChannelId) + } +} diff --git a/sds/sds_lint.go b/sds/sds_lint.go new file mode 100644 index 0000000..ec9317a --- /dev/null +++ b/sds/sds_lint.go @@ -0,0 +1,38 @@ +//go:build lint + +package sds + +import "errors" + +// This file provides lint-only stubs that avoid requiring libsds.h/cgo +// so linters can analyze this package without native dependencies. + +// ErrLintBuild indicates a stubbed, lint-only build without native libsds. +var ErrLintBuild = errors.New("sds: lint-only build stub: native libsds not linked") + +// NewReliabilityManager returns an error in lint builds. +func NewReliabilityManager() (*ReliabilityManager, error) { + return nil, ErrLintBuild +} + +// Cleanup returns an error in lint builds. +func (rm *ReliabilityManager) Cleanup() error { return ErrLintBuild } + +// Reset returns an error in lint builds. +func (rm *ReliabilityManager) Reset() error { return ErrLintBuild } + +// WrapOutgoingMessage returns an error in lint builds. +func (rm *ReliabilityManager) WrapOutgoingMessage(message []byte, messageId MessageID, channelId string) ([]byte, error) { + return nil, ErrLintBuild +} + +// UnwrapReceivedMessage returns an error in lint builds. +func (rm *ReliabilityManager) UnwrapReceivedMessage(message []byte) (*UnwrappedMessage, error) { + return nil, ErrLintBuild +} + +// MarkDependenciesMet returns an error in lint builds. +func (rm *ReliabilityManager) MarkDependenciesMet(messageIDs []MessageID, channelId string) error { return ErrLintBuild } + +// StartPeriodicTasks returns an error in lint builds. +func (rm *ReliabilityManager) StartPeriodicTasks() error { return ErrLintBuild }