mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-20 16:29:31 +00:00
Struct-returning methods now hand back a typed Go struct instead of the raw
CBOR/bytes. Since the native return POD is freed right after the callback, the
POD->Go conversion must happen in-callback: the generator emits a `fromC()`
reader per {.ffi.} type and, per struct-returning proc, an exported Go result
callback. The method calls the native entry point directly with that callback
and a `runtime/cgo.Handle` (boxed in a small C allocation so it travels through
the void* userData checkptr-safe), then blocks until the callback delivers the
typed value or error on the result slot.
String/raw-returning procs keep the existing C-bridge + condvar path. Validated
end-to-end (Echo/Complex/Schedule) including under `go run -race`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
625 lines
18 KiB
Go
625 lines
18 KiB
Go
// Code generated by nim-ffi Go codegen. DO NOT EDIT.
|
|
package my_timer
|
|
|
|
/*
|
|
#cgo CFLAGS: -I${SRCDIR}
|
|
#cgo LDFLAGS: -L${SRCDIR} -lmy_timer -Wl,-rpath,${SRCDIR}
|
|
#include "my_timer.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
|
|
extern void my_timerGoEvent(int ret, char* msg, size_t len, void* userData);
|
|
extern void my_timerResultEcho(int ret, char* msg, size_t len, void* ud);
|
|
extern void my_timerResultComplex(int ret, char* msg, size_t len, void* ud);
|
|
extern void my_timerResultSchedule(int ret, char* msg, size_t len, void* ud);
|
|
|
|
typedef struct {
|
|
int ret; char* msg; size_t len; int done;
|
|
pthread_mutex_t mu; pthread_cond_t cv;
|
|
} My_timerResp;
|
|
|
|
static My_timerResp* my_timerRespNew() {
|
|
My_timerResp* r = (My_timerResp*)calloc(1, sizeof(My_timerResp));
|
|
pthread_mutex_init(&r->mu, NULL); pthread_cond_init(&r->cv, NULL);
|
|
return r;
|
|
}
|
|
static void my_timerRespFree(My_timerResp* r) {
|
|
if (!r) return;
|
|
if (r->msg) free(r->msg);
|
|
pthread_mutex_destroy(&r->mu); pthread_cond_destroy(&r->cv); free(r);
|
|
}
|
|
static int my_timerRespRet(My_timerResp* r) { return r->ret; }
|
|
static char* my_timerRespMsg(My_timerResp* r) { return r->msg; }
|
|
static size_t my_timerRespLen(My_timerResp* r) { return r->len; }
|
|
|
|
static void my_timerRespCb(int ret, const char* msg, size_t len, void* ud) {
|
|
My_timerResp* r = (My_timerResp*)ud;
|
|
pthread_mutex_lock(&r->mu);
|
|
r->ret = ret;
|
|
// Native ABI: (msg, len) is the raw result (RET_OK) or error (RET_ERR).
|
|
// Copy it so it survives past the callback.
|
|
char* e = (char*)malloc(len + 1); if (e) { memcpy(e, msg, len); e[len] = 0; }
|
|
r->msg = e; r->len = len;
|
|
r->done = 1; pthread_cond_signal(&r->cv); pthread_mutex_unlock(&r->mu);
|
|
}
|
|
static void my_timerRespWait(My_timerResp* r) {
|
|
pthread_mutex_lock(&r->mu);
|
|
while (!r->done) pthread_cond_wait(&r->cv, &r->mu);
|
|
pthread_mutex_unlock(&r->mu);
|
|
}
|
|
|
|
static void* my_timerCall_my_timer_create(TimerConfig config, My_timerResp* r) {
|
|
void* ctx = my_timer_create(config, my_timerRespCb, r);
|
|
my_timerRespWait(r);
|
|
return ctx;
|
|
}
|
|
static int my_timerCall_my_timer_version(void* ctx, My_timerResp* r) {
|
|
int rc = my_timer_version(ctx, my_timerRespCb, r);
|
|
if (rc == RET_OK) my_timerRespWait(r);
|
|
return rc;
|
|
}
|
|
static int my_timerCall_my_timer_destroy(void* ctx) { return my_timer_destroy(ctx); }
|
|
static uint64_t my_timerRegisterEvents(void* ctx) { return my_timer_add_event_listener(ctx, "", (FFICallBack)my_timerGoEvent, ctx); }
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"errors"
|
|
"runtime/cgo"
|
|
"sync"
|
|
"unsafe"
|
|
)
|
|
|
|
type resultSlot struct {
|
|
val any
|
|
err error
|
|
done chan struct{}
|
|
}
|
|
|
|
// TimerConfig mirrors the {.ffi.} type of the same name.
|
|
type TimerConfig struct {
|
|
Name string
|
|
}
|
|
|
|
// toC marshals TimerConfig into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v TimerConfig) toC() (C.TimerConfig, []func()) {
|
|
var c C.TimerConfig
|
|
var frees []func()
|
|
cs_name := C.CString(v.Name)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_name)) })
|
|
c.name = cs_name
|
|
return c, frees
|
|
}
|
|
|
|
// TimerConfigFromC copies a C-POD TimerConfig (e.g. a typed return) into a Go value.
|
|
func TimerConfigFromC(c *C.TimerConfig) TimerConfig {
|
|
var v TimerConfig
|
|
v.Name = C.GoString(c.name)
|
|
return v
|
|
}
|
|
|
|
// EchoRequest mirrors the {.ffi.} type of the same name.
|
|
type EchoRequest struct {
|
|
Message string
|
|
DelayMs int64
|
|
}
|
|
|
|
// toC marshals EchoRequest into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v EchoRequest) toC() (C.EchoRequest, []func()) {
|
|
var c C.EchoRequest
|
|
var frees []func()
|
|
cs_message := C.CString(v.Message)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_message)) })
|
|
c.message = cs_message
|
|
c.delayMs = C.int64_t(v.DelayMs)
|
|
return c, frees
|
|
}
|
|
|
|
// EchoRequestFromC copies a C-POD EchoRequest (e.g. a typed return) into a Go value.
|
|
func EchoRequestFromC(c *C.EchoRequest) EchoRequest {
|
|
var v EchoRequest
|
|
v.Message = C.GoString(c.message)
|
|
v.DelayMs = int64(c.delayMs)
|
|
return v
|
|
}
|
|
|
|
// EchoResponse mirrors the {.ffi.} type of the same name.
|
|
type EchoResponse struct {
|
|
Echoed string
|
|
TimerName string
|
|
}
|
|
|
|
// toC marshals EchoResponse into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v EchoResponse) toC() (C.EchoResponse, []func()) {
|
|
var c C.EchoResponse
|
|
var frees []func()
|
|
cs_echoed := C.CString(v.Echoed)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_echoed)) })
|
|
c.echoed = cs_echoed
|
|
cs_timerName := C.CString(v.TimerName)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_timerName)) })
|
|
c.timerName = cs_timerName
|
|
return c, frees
|
|
}
|
|
|
|
// EchoResponseFromC copies a C-POD EchoResponse (e.g. a typed return) into a Go value.
|
|
func EchoResponseFromC(c *C.EchoResponse) EchoResponse {
|
|
var v EchoResponse
|
|
v.Echoed = C.GoString(c.echoed)
|
|
v.TimerName = C.GoString(c.timerName)
|
|
return v
|
|
}
|
|
|
|
// ComplexRequest mirrors the {.ffi.} type of the same name.
|
|
type ComplexRequest struct {
|
|
Messages []EchoRequest
|
|
Tags []string
|
|
Note *string
|
|
Retries *int64
|
|
}
|
|
|
|
// toC marshals ComplexRequest into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v ComplexRequest) toC() (C.ComplexRequest, []func()) {
|
|
var c C.ComplexRequest
|
|
var frees []func()
|
|
if n_messages := len(v.Messages); n_messages > 0 {
|
|
arr_messages := C.malloc(C.size_t(n_messages) * C.size_t(unsafe.Sizeof(C.EchoRequest{})))
|
|
sl_messages := unsafe.Slice((*C.EchoRequest)(arr_messages), n_messages)
|
|
for i := 0; i < n_messages; i++ {
|
|
cf_messages_e, ff_messages_e := (v.Messages[i]).toC()
|
|
frees = append(frees, ff_messages_e...)
|
|
sl_messages[i] = cf_messages_e
|
|
}
|
|
c.messages = (*C.EchoRequest)(arr_messages)
|
|
c.messages_len = C.size_t(n_messages)
|
|
a_messages := arr_messages
|
|
frees = append(frees, func() { C.free(a_messages) })
|
|
}
|
|
if n_tags := len(v.Tags); n_tags > 0 {
|
|
arr_tags := C.malloc(C.size_t(n_tags) * C.size_t(unsafe.Sizeof((*C.char)(nil))))
|
|
sl_tags := unsafe.Slice((**C.char)(arr_tags), n_tags)
|
|
for i := 0; i < n_tags; i++ {
|
|
cs_tags_e := C.CString(v.Tags[i])
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_tags_e)) })
|
|
sl_tags[i] = cs_tags_e
|
|
}
|
|
c.tags = (**C.char)(arr_tags)
|
|
c.tags_len = C.size_t(n_tags)
|
|
a_tags := arr_tags
|
|
frees = append(frees, func() { C.free(a_tags) })
|
|
}
|
|
if v.Note != nil {
|
|
c.note_present = 1
|
|
cs_note_o := C.CString(*v.Note)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_note_o)) })
|
|
c.note = cs_note_o
|
|
}
|
|
if v.Retries != nil {
|
|
c.retries_present = 1
|
|
c.retries = C.int64_t(*v.Retries)
|
|
}
|
|
return c, frees
|
|
}
|
|
|
|
// ComplexRequestFromC copies a C-POD ComplexRequest (e.g. a typed return) into a Go value.
|
|
func ComplexRequestFromC(c *C.ComplexRequest) ComplexRequest {
|
|
var v ComplexRequest
|
|
if c.messages_len > 0 {
|
|
src_messages := unsafe.Slice(c.messages, int(c.messages_len))
|
|
v.Messages = make([]EchoRequest, int(c.messages_len))
|
|
for i := range src_messages {
|
|
v.Messages[i] = EchoRequestFromC(&src_messages[i])
|
|
}
|
|
}
|
|
if c.tags_len > 0 {
|
|
src_tags := unsafe.Slice(c.tags, int(c.tags_len))
|
|
v.Tags = make([]string, int(c.tags_len))
|
|
for i := range src_tags {
|
|
v.Tags[i] = C.GoString(src_tags[i])
|
|
}
|
|
}
|
|
if c.note_present != 0 {
|
|
tmp_note := C.GoString(c.note)
|
|
v.Note = &tmp_note
|
|
}
|
|
if c.retries_present != 0 {
|
|
tmp_retries := int64(c.retries)
|
|
v.Retries = &tmp_retries
|
|
}
|
|
return v
|
|
}
|
|
|
|
// ComplexResponse mirrors the {.ffi.} type of the same name.
|
|
type ComplexResponse struct {
|
|
Summary string
|
|
ItemCount int64
|
|
HasNote bool
|
|
}
|
|
|
|
// toC marshals ComplexResponse into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v ComplexResponse) toC() (C.ComplexResponse, []func()) {
|
|
var c C.ComplexResponse
|
|
var frees []func()
|
|
cs_summary := C.CString(v.Summary)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_summary)) })
|
|
c.summary = cs_summary
|
|
c.itemCount = C.int64_t(v.ItemCount)
|
|
if v.HasNote {
|
|
c.hasNote = 1
|
|
} else {
|
|
c.hasNote = 0
|
|
}
|
|
return c, frees
|
|
}
|
|
|
|
// ComplexResponseFromC copies a C-POD ComplexResponse (e.g. a typed return) into a Go value.
|
|
func ComplexResponseFromC(c *C.ComplexResponse) ComplexResponse {
|
|
var v ComplexResponse
|
|
v.Summary = C.GoString(c.summary)
|
|
v.ItemCount = int64(c.itemCount)
|
|
v.HasNote = (c.hasNote != 0)
|
|
return v
|
|
}
|
|
|
|
// EchoEvent mirrors the {.ffi.} type of the same name.
|
|
type EchoEvent struct {
|
|
Message string
|
|
EchoCount int64
|
|
}
|
|
|
|
// toC marshals EchoEvent into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v EchoEvent) toC() (C.EchoEvent, []func()) {
|
|
var c C.EchoEvent
|
|
var frees []func()
|
|
cs_message := C.CString(v.Message)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_message)) })
|
|
c.message = cs_message
|
|
c.echoCount = C.int64_t(v.EchoCount)
|
|
return c, frees
|
|
}
|
|
|
|
// EchoEventFromC copies a C-POD EchoEvent (e.g. a typed return) into a Go value.
|
|
func EchoEventFromC(c *C.EchoEvent) EchoEvent {
|
|
var v EchoEvent
|
|
v.Message = C.GoString(c.message)
|
|
v.EchoCount = int64(c.echoCount)
|
|
return v
|
|
}
|
|
|
|
// JobSpec mirrors the {.ffi.} type of the same name.
|
|
type JobSpec struct {
|
|
Name string
|
|
Payload []string
|
|
Priority int64
|
|
}
|
|
|
|
// toC marshals JobSpec into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v JobSpec) toC() (C.JobSpec, []func()) {
|
|
var c C.JobSpec
|
|
var frees []func()
|
|
cs_name := C.CString(v.Name)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_name)) })
|
|
c.name = cs_name
|
|
if n_payload := len(v.Payload); n_payload > 0 {
|
|
arr_payload := C.malloc(C.size_t(n_payload) * C.size_t(unsafe.Sizeof((*C.char)(nil))))
|
|
sl_payload := unsafe.Slice((**C.char)(arr_payload), n_payload)
|
|
for i := 0; i < n_payload; i++ {
|
|
cs_payload_e := C.CString(v.Payload[i])
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_payload_e)) })
|
|
sl_payload[i] = cs_payload_e
|
|
}
|
|
c.payload = (**C.char)(arr_payload)
|
|
c.payload_len = C.size_t(n_payload)
|
|
a_payload := arr_payload
|
|
frees = append(frees, func() { C.free(a_payload) })
|
|
}
|
|
c.priority = C.int64_t(v.Priority)
|
|
return c, frees
|
|
}
|
|
|
|
// JobSpecFromC copies a C-POD JobSpec (e.g. a typed return) into a Go value.
|
|
func JobSpecFromC(c *C.JobSpec) JobSpec {
|
|
var v JobSpec
|
|
v.Name = C.GoString(c.name)
|
|
if c.payload_len > 0 {
|
|
src_payload := unsafe.Slice(c.payload, int(c.payload_len))
|
|
v.Payload = make([]string, int(c.payload_len))
|
|
for i := range src_payload {
|
|
v.Payload[i] = C.GoString(src_payload[i])
|
|
}
|
|
}
|
|
v.Priority = int64(c.priority)
|
|
return v
|
|
}
|
|
|
|
// RetryPolicy mirrors the {.ffi.} type of the same name.
|
|
type RetryPolicy struct {
|
|
MaxAttempts int64
|
|
BackoffMs int64
|
|
RetryOn []string
|
|
}
|
|
|
|
// toC marshals RetryPolicy into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v RetryPolicy) toC() (C.RetryPolicy, []func()) {
|
|
var c C.RetryPolicy
|
|
var frees []func()
|
|
c.maxAttempts = C.int64_t(v.MaxAttempts)
|
|
c.backoffMs = C.int64_t(v.BackoffMs)
|
|
if n_retryOn := len(v.RetryOn); n_retryOn > 0 {
|
|
arr_retryOn := C.malloc(C.size_t(n_retryOn) * C.size_t(unsafe.Sizeof((*C.char)(nil))))
|
|
sl_retryOn := unsafe.Slice((**C.char)(arr_retryOn), n_retryOn)
|
|
for i := 0; i < n_retryOn; i++ {
|
|
cs_retryOn_e := C.CString(v.RetryOn[i])
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_retryOn_e)) })
|
|
sl_retryOn[i] = cs_retryOn_e
|
|
}
|
|
c.retryOn = (**C.char)(arr_retryOn)
|
|
c.retryOn_len = C.size_t(n_retryOn)
|
|
a_retryOn := arr_retryOn
|
|
frees = append(frees, func() { C.free(a_retryOn) })
|
|
}
|
|
return c, frees
|
|
}
|
|
|
|
// RetryPolicyFromC copies a C-POD RetryPolicy (e.g. a typed return) into a Go value.
|
|
func RetryPolicyFromC(c *C.RetryPolicy) RetryPolicy {
|
|
var v RetryPolicy
|
|
v.MaxAttempts = int64(c.maxAttempts)
|
|
v.BackoffMs = int64(c.backoffMs)
|
|
if c.retryOn_len > 0 {
|
|
src_retryOn := unsafe.Slice(c.retryOn, int(c.retryOn_len))
|
|
v.RetryOn = make([]string, int(c.retryOn_len))
|
|
for i := range src_retryOn {
|
|
v.RetryOn[i] = C.GoString(src_retryOn[i])
|
|
}
|
|
}
|
|
return v
|
|
}
|
|
|
|
// ScheduleConfig mirrors the {.ffi.} type of the same name.
|
|
type ScheduleConfig struct {
|
|
StartAtMs int64
|
|
IntervalMs int64
|
|
Jitter *int64
|
|
}
|
|
|
|
// toC marshals ScheduleConfig into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v ScheduleConfig) toC() (C.ScheduleConfig, []func()) {
|
|
var c C.ScheduleConfig
|
|
var frees []func()
|
|
c.startAtMs = C.int64_t(v.StartAtMs)
|
|
c.intervalMs = C.int64_t(v.IntervalMs)
|
|
if v.Jitter != nil {
|
|
c.jitter_present = 1
|
|
c.jitter = C.int64_t(*v.Jitter)
|
|
}
|
|
return c, frees
|
|
}
|
|
|
|
// ScheduleConfigFromC copies a C-POD ScheduleConfig (e.g. a typed return) into a Go value.
|
|
func ScheduleConfigFromC(c *C.ScheduleConfig) ScheduleConfig {
|
|
var v ScheduleConfig
|
|
v.StartAtMs = int64(c.startAtMs)
|
|
v.IntervalMs = int64(c.intervalMs)
|
|
if c.jitter_present != 0 {
|
|
tmp_jitter := int64(c.jitter)
|
|
v.Jitter = &tmp_jitter
|
|
}
|
|
return v
|
|
}
|
|
|
|
// ScheduleResult mirrors the {.ffi.} type of the same name.
|
|
type ScheduleResult struct {
|
|
JobId string
|
|
WillRunCount int64
|
|
FirstRunAtMs int64
|
|
EffectiveBackoffMs int64
|
|
}
|
|
|
|
// toC marshals ScheduleResult into its C-POD form, returning cleanup funcs to run after the call.
|
|
func (v ScheduleResult) toC() (C.ScheduleResult, []func()) {
|
|
var c C.ScheduleResult
|
|
var frees []func()
|
|
cs_jobId := C.CString(v.JobId)
|
|
frees = append(frees, func() { C.free(unsafe.Pointer(cs_jobId)) })
|
|
c.jobId = cs_jobId
|
|
c.willRunCount = C.int64_t(v.WillRunCount)
|
|
c.firstRunAtMs = C.int64_t(v.FirstRunAtMs)
|
|
c.effectiveBackoffMs = C.int64_t(v.EffectiveBackoffMs)
|
|
return c, frees
|
|
}
|
|
|
|
// ScheduleResultFromC copies a C-POD ScheduleResult (e.g. a typed return) into a Go value.
|
|
func ScheduleResultFromC(c *C.ScheduleResult) ScheduleResult {
|
|
var v ScheduleResult
|
|
v.JobId = C.GoString(c.jobId)
|
|
v.WillRunCount = int64(c.willRunCount)
|
|
v.FirstRunAtMs = int64(c.firstRunAtMs)
|
|
v.EffectiveBackoffMs = int64(c.effectiveBackoffMs)
|
|
return v
|
|
}
|
|
|
|
type My_timerNode struct {
|
|
ctx unsafe.Pointer
|
|
}
|
|
|
|
// goStr extracts and frees the captured response string.
|
|
func respStr(r *C.My_timerResp) string {
|
|
return C.GoStringN(C.my_timerRespMsg(r), C.int(C.my_timerRespLen(r)))
|
|
}
|
|
|
|
var (
|
|
eventMu sync.Mutex
|
|
eventHandler func(string)
|
|
)
|
|
|
|
// SetEventHandler installs the catch-all handler for library-initiated
|
|
// events (delivered as raw JSON strings).
|
|
func (n *My_timerNode) SetEventHandler(h func(string)) {
|
|
eventMu.Lock()
|
|
eventHandler = h
|
|
eventMu.Unlock()
|
|
C.my_timerRegisterEvents(n.ctx)
|
|
}
|
|
|
|
//export my_timerGoEvent
|
|
func my_timerGoEvent(ret C.int, msg *C.char, length C.size_t, userData unsafe.Pointer) {
|
|
eventMu.Lock()
|
|
h := eventHandler
|
|
eventMu.Unlock()
|
|
if h != nil && ret == C.RET_OK {
|
|
h(C.GoStringN(msg, C.int(length)))
|
|
}
|
|
}
|
|
|
|
func NewMy_timer(config TimerConfig) (*My_timerNode, error) {
|
|
c_config, free_config := config.toC()
|
|
defer func() {
|
|
for _, f := range free_config {
|
|
f()
|
|
}
|
|
}()
|
|
r := C.my_timerRespNew()
|
|
defer C.my_timerRespFree(r)
|
|
ctx := C.my_timerCall_my_timer_create(c_config, r)
|
|
if C.my_timerRespRet(r) != C.RET_OK {
|
|
return nil, errors.New(respStr(r))
|
|
}
|
|
return &My_timerNode{ctx: ctx}, nil
|
|
}
|
|
|
|
//export my_timerResultEcho
|
|
func my_timerResultEcho(ret C.int, msg *C.char, length C.size_t, ud unsafe.Pointer) {
|
|
slot := cgo.Handle(*(*C.uintptr_t)(ud)).Value().(*resultSlot)
|
|
if ret == C.RET_OK {
|
|
slot.val = EchoResponseFromC((*C.EchoResponse)(unsafe.Pointer(msg)))
|
|
} else {
|
|
slot.err = errors.New(C.GoStringN(msg, C.int(length)))
|
|
}
|
|
close(slot.done)
|
|
}
|
|
|
|
func (n *My_timerNode) Echo(req EchoRequest) (EchoResponse, error) {
|
|
c_req, free_req := req.toC()
|
|
defer func() {
|
|
for _, f := range free_req {
|
|
f()
|
|
}
|
|
}()
|
|
slot := &resultSlot{done: make(chan struct{})}
|
|
h := cgo.NewHandle(slot)
|
|
defer h.Delete()
|
|
hbox := (*C.uintptr_t)(C.malloc(C.size_t(unsafe.Sizeof(C.uintptr_t(0)))))
|
|
*hbox = C.uintptr_t(h)
|
|
defer C.free(unsafe.Pointer(hbox))
|
|
rc := C.my_timer_echo(n.ctx, C.FFICallBack(C.my_timerResultEcho), unsafe.Pointer(hbox), c_req)
|
|
if rc != C.RET_OK {
|
|
return EchoResponse{}, errors.New("my_timer_echo: dispatch failed")
|
|
}
|
|
<-slot.done
|
|
if slot.err != nil {
|
|
return EchoResponse{}, slot.err
|
|
}
|
|
return slot.val.(EchoResponse), nil
|
|
}
|
|
|
|
func (n *My_timerNode) Version() (string, error) {
|
|
r := C.my_timerRespNew()
|
|
defer C.my_timerRespFree(r)
|
|
C.my_timerCall_my_timer_version(n.ctx, r)
|
|
if C.my_timerRespRet(r) != C.RET_OK {
|
|
return "", errors.New(respStr(r))
|
|
}
|
|
return respStr(r), nil
|
|
}
|
|
|
|
//export my_timerResultComplex
|
|
func my_timerResultComplex(ret C.int, msg *C.char, length C.size_t, ud unsafe.Pointer) {
|
|
slot := cgo.Handle(*(*C.uintptr_t)(ud)).Value().(*resultSlot)
|
|
if ret == C.RET_OK {
|
|
slot.val = ComplexResponseFromC((*C.ComplexResponse)(unsafe.Pointer(msg)))
|
|
} else {
|
|
slot.err = errors.New(C.GoStringN(msg, C.int(length)))
|
|
}
|
|
close(slot.done)
|
|
}
|
|
|
|
func (n *My_timerNode) Complex(req ComplexRequest) (ComplexResponse, error) {
|
|
c_req, free_req := req.toC()
|
|
defer func() {
|
|
for _, f := range free_req {
|
|
f()
|
|
}
|
|
}()
|
|
slot := &resultSlot{done: make(chan struct{})}
|
|
h := cgo.NewHandle(slot)
|
|
defer h.Delete()
|
|
hbox := (*C.uintptr_t)(C.malloc(C.size_t(unsafe.Sizeof(C.uintptr_t(0)))))
|
|
*hbox = C.uintptr_t(h)
|
|
defer C.free(unsafe.Pointer(hbox))
|
|
rc := C.my_timer_complex(n.ctx, C.FFICallBack(C.my_timerResultComplex), unsafe.Pointer(hbox), c_req)
|
|
if rc != C.RET_OK {
|
|
return ComplexResponse{}, errors.New("my_timer_complex: dispatch failed")
|
|
}
|
|
<-slot.done
|
|
if slot.err != nil {
|
|
return ComplexResponse{}, slot.err
|
|
}
|
|
return slot.val.(ComplexResponse), nil
|
|
}
|
|
|
|
//export my_timerResultSchedule
|
|
func my_timerResultSchedule(ret C.int, msg *C.char, length C.size_t, ud unsafe.Pointer) {
|
|
slot := cgo.Handle(*(*C.uintptr_t)(ud)).Value().(*resultSlot)
|
|
if ret == C.RET_OK {
|
|
slot.val = ScheduleResultFromC((*C.ScheduleResult)(unsafe.Pointer(msg)))
|
|
} else {
|
|
slot.err = errors.New(C.GoStringN(msg, C.int(length)))
|
|
}
|
|
close(slot.done)
|
|
}
|
|
|
|
func (n *My_timerNode) Schedule(job JobSpec, retry RetryPolicy, schedule ScheduleConfig) (ScheduleResult, error) {
|
|
c_job, free_job := job.toC()
|
|
defer func() {
|
|
for _, f := range free_job {
|
|
f()
|
|
}
|
|
}()
|
|
c_retry, free_retry := retry.toC()
|
|
defer func() {
|
|
for _, f := range free_retry {
|
|
f()
|
|
}
|
|
}()
|
|
c_schedule, free_schedule := schedule.toC()
|
|
defer func() {
|
|
for _, f := range free_schedule {
|
|
f()
|
|
}
|
|
}()
|
|
slot := &resultSlot{done: make(chan struct{})}
|
|
h := cgo.NewHandle(slot)
|
|
defer h.Delete()
|
|
hbox := (*C.uintptr_t)(C.malloc(C.size_t(unsafe.Sizeof(C.uintptr_t(0)))))
|
|
*hbox = C.uintptr_t(h)
|
|
defer C.free(unsafe.Pointer(hbox))
|
|
rc := C.my_timer_schedule(n.ctx, C.FFICallBack(C.my_timerResultSchedule), unsafe.Pointer(hbox), c_job, c_retry, c_schedule)
|
|
if rc != C.RET_OK {
|
|
return ScheduleResult{}, errors.New("my_timer_schedule: dispatch failed")
|
|
}
|
|
<-slot.done
|
|
if slot.err != nil {
|
|
return ScheduleResult{}, slot.err
|
|
}
|
|
return slot.val.(ScheduleResult), nil
|
|
}
|
|
|
|
func (n *My_timerNode) Destroy() error {
|
|
if C.my_timerCall_my_timer_destroy(n.ctx) != C.RET_OK {
|
|
return errors.New("my_timer destroy failed")
|
|
}
|
|
return nil
|
|
}
|