package backend import ( "fmt" "sync" "unsafe" ) /* ATCHUNG! what follow are not silly comments. Well, *this one* is, but the lines after this are not. Those are inline C functions, that are invoked by CGO later on. it's also crucial that you don't any extra space between the function block and the 'import "C"' line. */ // typedef void (*cb)(); // inline void _do_callback(cb f) { // f(); // } import "C" /* callbacks into C-land. We keep a registry, and protect its updates with a mutex. */ var callbacks = make(map[string](*[0]byte)) var callbackMutex sync.Mutex var initOnce sync.Once // Events are just a enumeration of all the posible events that C functions can // be interested in subscribing to. You cannot subscribe to an event that is // not listed here. type Events struct { OnStatusChanged string } const OnStatusChanged string = "OnStatusChanged" // subscribe registers a callback from C-land. // This callback needs to be passed as a void* C function pointer. func subscribe(event string, fp unsafe.Pointer) { callbackMutex.Lock() defer callbackMutex.Unlock() /* I'm commenting this check because it imposes 1.14, which is only in buster-backports. We can re-add it after buster is oldstable e := &Events{} v := reflect.Indirect(reflect.ValueOf(&e)) hf := v.Elem().FieldByName(event) if reflect.ValueOf(hf).IsZero() { fmt.Println("ERROR: not a valid event:", event) } else { callbacks[event] = (*[0]byte)(fp) } */ callbacks[event] = (*[0]byte)(fp) } // trigger fires a callback from C-land. func trigger(event string) { callbackMutex.Lock() defer callbackMutex.Unlock() cb := callbacks[event] if cb != nil { C._do_callback(cb) } else { fmt.Println("ERROR: this event does not have subscribers:", event) } }