From d9c3bccc31d08db8c676c468ac3b5cf05ebde806 Mon Sep 17 00:00:00 2001 From: Gabriel mermelstein Date: Wed, 16 Apr 2025 17:54:48 +0300 Subject: [PATCH] removing old go wrappers --- sds_wrapper.go | 281 -------------------------------------------- sds_wrapper_test.go | 259 ---------------------------------------- 2 files changed, 540 deletions(-) delete mode 100644 sds_wrapper.go delete mode 100644 sds_wrapper_test.go diff --git a/sds_wrapper.go b/sds_wrapper.go deleted file mode 100644 index 1150a46..0000000 --- a/sds_wrapper.go +++ /dev/null @@ -1,281 +0,0 @@ -package main - -/* -#cgo CFLAGS: -I${SRCDIR}/library -#cgo LDFLAGS: -L${SRCDIR}/build -llibsds -#cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/build - -#include // For C.free -#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); - -// Helper function to call the C memory freeing functions -static void callFreeCResultError(CResult res) { FreeCResultError(res); } -static void callFreeCWrapResult(CWrapResult res) { FreeCWrapResult(res); } -static void callFreeCUnwrapResult(CUnwrapResult res) { FreeCUnwrapResult(res); } - -*/ -import "C" -import ( - "errors" - "fmt" - "sync" - "unsafe" -) - -// --- Go Types --- - -// ReliabilityManagerHandle represents the opaque handle to the Nim object -type ReliabilityManagerHandle unsafe.Pointer - -// MessageID is a type alias for string for clarity -type MessageID string - -// Callbacks holds the Go functions to be called by the Nim library -type Callbacks struct { - OnMessageReady func(messageId MessageID) - OnMessageSent func(messageId MessageID) - OnMissingDependencies func(messageId MessageID, missingDeps []MessageID) - OnPeriodicSync func() -} - -// Global map to store callbacks associated with handles -var ( - callbackRegistry = make(map[ReliabilityManagerHandle]*Callbacks) - registryMutex sync.RWMutex -) - -// --- Go Wrapper Functions --- - -// NewReliabilityManager creates a new instance of the Nim ReliabilityManager -func NewReliabilityManager(channelId string) (ReliabilityManagerHandle, error) { - cChannelId := C.CString(channelId) - defer C.free(unsafe.Pointer(cChannelId)) - - handle := C.NewReliabilityManager(cChannelId) - if handle == nil { - // Note: Nim side currently just prints to stdout on creation failure - return nil, errors.New("failed to create ReliabilityManager (check Nim logs/stdout)") - } - return ReliabilityManagerHandle(handle), nil -} - -// CleanupReliabilityManager frees the resources associated with the handle -func CleanupReliabilityManager(handle ReliabilityManagerHandle) { - if handle == nil { - return - } - registryMutex.Lock() - delete(callbackRegistry, handle) - registryMutex.Unlock() - C.CleanupReliabilityManager(unsafe.Pointer(handle)) -} - -// ResetReliabilityManager resets the state of the manager -func ResetReliabilityManager(handle ReliabilityManagerHandle) error { - if handle == nil { - return errors.New("handle is nil") - } - cResult := C.ResetReliabilityManager(unsafe.Pointer(handle)) - if !cResult.is_ok { - errMsg := C.GoString(cResult.error_message) - C.callFreeCResultError(cResult) // Free the error message - return errors.New(errMsg) - } - return nil -} - -// WrapOutgoingMessage wraps a message with reliability metadata -func WrapOutgoingMessage(handle ReliabilityManagerHandle, message []byte, messageId MessageID) ([]byte, error) { - if handle == nil { - return nil, errors.New("handle is nil") - } - cMessageId := C.CString(string(messageId)) - defer C.free(unsafe.Pointer(cMessageId)) - - var cMessagePtr unsafe.Pointer - if len(message) > 0 { - cMessagePtr = C.CBytes(message) // C.CBytes allocates memory that needs to be freed - defer C.free(cMessagePtr) - } else { - cMessagePtr = nil - } - cMessageLen := C.size_t(len(message)) - - cWrapResult := C.WrapOutgoingMessage(unsafe.Pointer(handle), cMessagePtr, cMessageLen, cMessageId) - - if !cWrapResult.base_result.is_ok { - errMsg := C.GoString(cWrapResult.base_result.error_message) - C.callFreeCWrapResult(cWrapResult) // Free error and potentially allocated message - return nil, errors.New(errMsg) - } - - // Copy the wrapped message from C memory to Go slice - // Explicitly cast the message pointer to unsafe.Pointer - wrappedMessage := C.GoBytes(unsafe.Pointer(cWrapResult.message), C.int(cWrapResult.message_len)) - C.callFreeCWrapResult(cWrapResult) // Free the C-allocated message buffer - - return wrappedMessage, nil -} - -// UnwrapReceivedMessage unwraps a received message -func UnwrapReceivedMessage(handle ReliabilityManagerHandle, message []byte) ([]byte, []MessageID, error) { - if handle == nil { - return nil, nil, errors.New("handle is nil") - } - - var cMessagePtr unsafe.Pointer - if len(message) > 0 { - cMessagePtr = C.CBytes(message) - defer C.free(cMessagePtr) - } else { - cMessagePtr = nil - } - cMessageLen := C.size_t(len(message)) - - cUnwrapResult := C.UnwrapReceivedMessage(unsafe.Pointer(handle), cMessagePtr, cMessageLen) - - if !cUnwrapResult.base_result.is_ok { - errMsg := C.GoString(cUnwrapResult.base_result.error_message) - C.callFreeCUnwrapResult(cUnwrapResult) // Free error and potentially allocated fields - return nil, nil, errors.New(errMsg) - } - - // Copy unwrapped message content - unwrappedContent := C.GoBytes(unsafe.Pointer(cUnwrapResult.message), C.int(cUnwrapResult.message_len)) - - // Copy missing dependencies - missingDeps := make([]MessageID, cUnwrapResult.missing_deps_count) - if cUnwrapResult.missing_deps_count > 0 { - // Convert C array of C strings to Go slice of strings - cDepsArray := (*[1 << 30]*C.char)(unsafe.Pointer(cUnwrapResult.missing_deps))[:cUnwrapResult.missing_deps_count:cUnwrapResult.missing_deps_count] - for i, s := range cDepsArray { - missingDeps[i] = MessageID(C.GoString(s)) - } - } - - C.callFreeCUnwrapResult(cUnwrapResult) // Free C-allocated message, deps array, and strings - - return unwrappedContent, missingDeps, nil -} - -// MarkDependenciesMet informs the library that dependencies are met -func MarkDependenciesMet(handle ReliabilityManagerHandle, messageIDs []MessageID) error { - if handle == nil { - return errors.New("handle is nil") - } - if len(messageIDs) == 0 { - return nil // Nothing to do - } - - // Convert Go string slice to C array of C strings (char**) - cMessageIDs := make([]*C.char, len(messageIDs)) - for i, id := range messageIDs { - cMessageIDs[i] = C.CString(string(id)) - defer C.free(unsafe.Pointer(cMessageIDs[i])) // Ensure each CString is freed - } - - // Create a pointer (**C.char) to the first element of the slice - var cMessageIDsPtr **C.char - if len(cMessageIDs) > 0 { - cMessageIDsPtr = &cMessageIDs[0] - } else { - cMessageIDsPtr = nil // Handle empty slice case - } - - // Pass the pointer variable (cMessageIDsPtr) directly, which is of type **C.char - cResult := C.MarkDependenciesMet(unsafe.Pointer(handle), cMessageIDsPtr, C.size_t(len(messageIDs))) - - if !cResult.is_ok { - errMsg := C.GoString(cResult.error_message) - C.callFreeCResultError(cResult) - return errors.New(errMsg) - } - return nil -} - -// RegisterCallback sets the single Go callback relay function -func RegisterCallback(handle ReliabilityManagerHandle, callbacks Callbacks) error { - if handle == nil { - return errors.New("handle is nil") - } - - // Store the Go callbacks associated with this handle - registryMutex.Lock() - callbackRegistry[handle] = &callbacks - registryMutex.Unlock() - - // Register the single global Go relay function with the Nim library - // Nim will call globalCallbackRelay, passing the handle as the first argument. - C.RegisterCallback( - unsafe.Pointer(handle), - (C.CEventCallback)(C.globalCallbackRelay), // Pass the Go relay function pointer - nil, // user_data is not used here, handle is passed directly by Nim wrapper - ) - return nil -} - -// StartPeriodicTasks starts the background tasks in the Nim library -func StartPeriodicTasks(handle ReliabilityManagerHandle) error { - if handle == nil { - return errors.New("handle is nil") - } - C.StartPeriodicTasks(unsafe.Pointer(handle)) - // Assuming StartPeriodicTasks doesn't return an error status in C API - return nil -} - -// 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) - - registryMutex.RLock() - callbacks, ok := callbackRegistry[goHandle] - registryMutex.RUnlock() - - if !ok || callbacks == nil { - fmt.Printf("Go: globalCallbackRelay: No callbacks registered for handle %v\n", goHandle) // Uncommented - return - } - - // Use a goroutine to avoid blocking the Nim thread - go func() { - switch eventType { - case C.EVENT_MESSAGE_READY: - if callbacks.OnMessageReady != nil { - msgIdStr := C.GoString((*C.char)(data1)) - callbacks.OnMessageReady(MessageID(msgIdStr)) - } - case C.EVENT_MESSAGE_SENT: - if callbacks.OnMessageSent != nil { - msgIdStr := C.GoString((*C.char)(data1)) - callbacks.OnMessageSent(MessageID(msgIdStr)) - } - case C.EVENT_MISSING_DEPENDENCIES: - if callbacks.OnMissingDependencies != nil { - msgIdStr := C.GoString((*C.char)(data1)) - depsCount := int(data3) - deps := make([]MessageID, depsCount) - if depsCount > 0 { - // Convert C array of C strings (**char) to Go slice - cDepsArray := (*[1 << 30]*C.char)(data2)[:depsCount:depsCount] - for i, s := range cDepsArray { - deps[i] = MessageID(C.GoString(s)) - } - } - callbacks.OnMissingDependencies(MessageID(msgIdStr), deps) - } - case C.EVENT_PERIODIC_SYNC: - if callbacks.OnPeriodicSync != nil { - callbacks.OnPeriodicSync() - } - default: - fmt.Printf("Go: globalCallbackRelay: Received unknown event type %d for handle %v\n", eventType, goHandle) - } - }() -} diff --git a/sds_wrapper_test.go b/sds_wrapper_test.go deleted file mode 100644 index ee1185a..0000000 --- a/sds_wrapper_test.go +++ /dev/null @@ -1,259 +0,0 @@ -package main -import ( - "fmt" - "sync" - "testing" - "time" -) - -// Test basic creation, cleanup, and reset -func TestLifecycle(t *testing.T) { - channelID := "test-lifecycle" - handle, err := NewReliabilityManager(channelID) - if err != nil { - t.Fatalf("NewReliabilityManager failed: %v", err) - } - if handle == nil { - t.Fatal("NewReliabilityManager returned a nil handle") - } - defer CleanupReliabilityManager(handle) // Ensure cleanup even on test failure - - err = ResetReliabilityManager(handle) - if err != nil { - t.Errorf("ResetReliabilityManager failed: %v", err) - } -} - -// Test wrapping and unwrapping a simple message -func TestWrapUnwrap(t *testing.T) { - channelID := "test-wrap-unwrap" - handle, err := NewReliabilityManager(channelID) - if err != nil { - t.Fatalf("NewReliabilityManager failed: %v", err) - } - defer CleanupReliabilityManager(handle) - - originalPayload := []byte("hello reliability") - messageID := MessageID("msg-wrap-1") - - wrappedMsg, err := WrapOutgoingMessage(handle, originalPayload, messageID) - if err != nil { - t.Fatalf("WrapOutgoingMessage failed: %v", err) - } - if len(wrappedMsg) == 0 { - t.Fatal("WrapOutgoingMessage returned empty bytes") - } - - // Simulate receiving the wrapped message - unwrappedPayload, missingDeps, err := UnwrapReceivedMessage(handle, wrappedMsg) - if err != nil { - t.Fatalf("UnwrapReceivedMessage failed: %v", err) - } - - if string(unwrappedPayload) != string(originalPayload) { - t.Errorf("Unwrapped payload mismatch: got %q, want %q", unwrappedPayload, originalPayload) - } - if len(missingDeps) != 0 { - t.Errorf("Expected 0 missing dependencies, got %d: %v", len(missingDeps), missingDeps) - } -} - -// Test dependency handling -func TestDependencies(t *testing.T) { - channelID := "test-deps" - handle, err := NewReliabilityManager(channelID) - if err != nil { - t.Fatalf("NewReliabilityManager failed: %v", err) - } - defer CleanupReliabilityManager(handle) - - // 1. Send message 1 (will become a dependency) - payload1 := []byte("message one") - msgID1 := MessageID("msg-dep-1") - wrappedMsg1, err := WrapOutgoingMessage(handle, payload1, msgID1) - if err != nil { - t.Fatalf("WrapOutgoingMessage (1) failed: %v", err) - } - // Simulate receiving msg1 to add it to history (implicitly acknowledges it) - _, _, err = UnwrapReceivedMessage(handle, wrappedMsg1) - if err != nil { - t.Fatalf("UnwrapReceivedMessage (1) failed: %v", err) - } - - // 2. Send message 2 (depends on message 1 implicitly via causal history) - payload2 := []byte("message two") - msgID2 := MessageID("msg-dep-2") - wrappedMsg2, err := WrapOutgoingMessage(handle, payload2, msgID2) - if err != nil { - t.Fatalf("WrapOutgoingMessage (2) failed: %v", err) - } - - // 3. Create a new manager to simulate a different peer receiving msg2 without msg1 - handle2, err := NewReliabilityManager(channelID) // Same channel ID - if err != nil { - t.Fatalf("NewReliabilityManager (2) failed: %v", err) - } - defer CleanupReliabilityManager(handle2) - - // 4. Unwrap message 2 on the second manager - should report msg1 as missing - _, missingDeps, err := UnwrapReceivedMessage(handle2, wrappedMsg2) - if err != nil { - t.Fatalf("UnwrapReceivedMessage (2) on handle2 failed: %v", err) - } - - if len(missingDeps) == 0 { - t.Fatalf("Expected missing dependencies, got none") - } - foundDep1 := false - for _, dep := range missingDeps { - if dep == msgID1 { - foundDep1 = true - break - } - } - if !foundDep1 { - t.Errorf("Expected missing dependency %q, got %v", msgID1, missingDeps) - } - - // 5. Mark the dependency as met - err = MarkDependenciesMet(handle2, []MessageID{msgID1}) - if err != nil { - t.Fatalf("MarkDependenciesMet failed: %v", err) - } -} - -// Test callbacks -func TestCallbacks(t *testing.T) { - channelID := "test-callbacks" - handle, err := NewReliabilityManager(channelID) - if err != nil { - t.Fatalf("NewReliabilityManager failed: %v", err) - } - defer CleanupReliabilityManager(handle) - - var wg sync.WaitGroup - receivedReady := make(map[MessageID]bool) - receivedSent := make(map[MessageID]bool) - receivedMissing := make(map[MessageID][]MessageID) - syncRequested := false - var cbMutex sync.Mutex // Protect access to callback tracking maps/vars - - callbacks := Callbacks{ - OnMessageReady: func(messageId MessageID) { - fmt.Printf("Test: OnMessageReady received: %s\n", messageId) - cbMutex.Lock() - receivedReady[messageId] = true - cbMutex.Unlock() - wg.Done() - }, - OnMessageSent: func(messageId MessageID) { - fmt.Printf("Test: OnMessageSent received: %s\n", messageId) - cbMutex.Lock() - receivedSent[messageId] = true - cbMutex.Unlock() - wg.Done() - }, - OnMissingDependencies: func(messageId MessageID, missingDeps []MessageID) { - fmt.Printf("Test: OnMissingDependencies received for %s: %v\n", messageId, missingDeps) - cbMutex.Lock() - receivedMissing[messageId] = missingDeps - cbMutex.Unlock() - wg.Done() - }, - OnPeriodicSync: func() { - fmt.Println("Test: OnPeriodicSync received") - cbMutex.Lock() - syncRequested = true - cbMutex.Unlock() - // Don't wg.Done() here, it might be called multiple times - }, - } - - err = RegisterCallback(handle, callbacks) - if err != nil { - t.Fatalf("RegisterCallback failed: %v", err) - } - - // Start tasks AFTER registering callbacks - err = StartPeriodicTasks(handle) - if err != nil { - t.Fatalf("StartPeriodicTasks failed: %v", err) - } - - // --- Test Scenario --- - - // 1. Send msg1 - wg.Add(1) // Expect OnMessageSent for msg1 eventually - payload1 := []byte("callback test 1") - msgID1 := MessageID("cb-msg-1") - wrappedMsg1, err := WrapOutgoingMessage(handle, payload1, msgID1) - if err != nil { - t.Fatalf("WrapOutgoingMessage (1) failed: %v", err) - } - - // 2. Receive msg1 (triggers OnMessageReady for msg1, OnMessageSent for msg1 via causal history) - wg.Add(1) // Expect OnMessageReady for msg1 - _, _, err = UnwrapReceivedMessage(handle, wrappedMsg1) - if err != nil { - t.Fatalf("UnwrapReceivedMessage (1) failed: %v", err) - } - - // 3. Send msg2 (depends on msg1) - wg.Add(1) // Expect OnMessageSent for msg2 eventually - payload2 := []byte("callback test 2") - msgID2 := MessageID("cb-msg-2") - wrappedMsg2, err := WrapOutgoingMessage(handle, payload2, msgID2) - if err != nil { - t.Fatalf("WrapOutgoingMessage (2) failed: %v", err) - } - - // 4. Receive msg2 (triggers OnMessageReady for msg2, OnMessageSent for msg2) - wg.Add(1) // Expect OnMessageReady for msg2 - _, _, err = UnwrapReceivedMessage(handle, wrappedMsg2) - if err != nil { - t.Fatalf("UnwrapReceivedMessage (2) failed: %v", err) - } - - // --- Verification --- - // Wait for expected callbacks with a timeout - waitTimeout(&wg, 5*time.Second, t) - - cbMutex.Lock() - defer cbMutex.Unlock() - - if !receivedReady[msgID1] { - t.Errorf("OnMessageReady not called for %s", msgID1) - } - if !receivedReady[msgID2] { - t.Errorf("OnMessageReady not called for %s", msgID2) - } - if !receivedSent[msgID1] { - t.Errorf("OnMessageSent not called for %s", msgID1) - } - if !receivedSent[msgID2] { - t.Errorf("OnMessageSent not called for %s", msgID2) - } - // We didn't explicitly test missing deps in this path - if len(receivedMissing) > 0 { - t.Errorf("Unexpected OnMissingDependencies calls: %v", receivedMissing) - } - // Periodic sync is harder to guarantee in a short test, just check if it was ever true - if !syncRequested { - t.Logf("Warning: OnPeriodicSync might not have been called within the test timeout") - } -} - -// Helper function to wait for WaitGroup with a timeout -func waitTimeout(wg *sync.WaitGroup, timeout time.Duration, t *testing.T) { - c := make(chan struct{}) - go func() { - defer close(c) - wg.Wait() - }() - select { - case <-c: - // Completed normally - case <-time.After(timeout): - t.Fatalf("Timed out waiting for callbacks") - } -}