// 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 #include #include 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 }