// HandlerFunc is the signature for Go handler functions.
// They receive JSON-serialized request and return JSON response.
type HandlerFunc func([]byte) ([]byte, error)
// handlerRegistry maps opaque context indices to Go handlers.
var (
handlerRegistryMu sync.Mutex
handlerRegistry = make(map[uintptr]HandlerFunc)
handlerNextID uintptr = 1
)
// registerHandler stores a Go handler in the registry and returns its opaque context ID.
func registerHandler(fn HandlerFunc) uintptr {
handlerRegistryMu.Lock()
defer handlerRegistryMu.Unlock()
id := handlerNextID
handlerNextID++
handlerRegistry[id] = fn
return id
}
// unregisterHandler removes a handler from the registry.
func unregisterHandler(id uintptr) {
handlerRegistryMu.Lock()
defer handlerRegistryMu.Unlock()
delete(handlerRegistry, id)
}
// invokeHandler looks up a handler by ID and invokes it with the request JSON.
// Returns the response JSON or an error.
func invokeHandler(ctx uintptr, reqJSON []byte) ([]byte, error) {
handlerRegistryMu.Lock()
handler, ok := handlerRegistry[ctx]
handlerRegistryMu.Unlock()
if !ok {
return nil, errors.New("handler not found")
}
return handler(reqJSON)
}
// cgo trampoline matching the C callback typedef:
// char* (*)(void* context, const char* request_json)
//
// This function is exported with //export so cgo can call it from C.
// It looks up the handler in the registry and invokes it.
//
//export service_handler_callback
func service_handler_callback(ctx unsafe.Pointer, reqCStr *C.char) *C.char {
ctxID := uintptr(ctx)
reqJSON := C.GoBytes(unsafe.Pointer(reqCStr), C.int(C.strlen(reqCStr)))
respJSON, err := invokeHandler(ctxID, reqJSON)
if err != nil {
errJSON, _ := json.Marshal(map[string]string{"error": err.Error()})
respJSON = errJSON
}
// Allocate C string from Go heap (caller responsible for freeing).
cResp := C.CString(string(respJSON))
return cResp
}