Files
overlord/plugins/sample-c/native/plugin.c
T

161 lines
5.2 KiB
C
Raw Normal View History

/*
* Sample C Plugin — fully unloadable, no runtime baggage.
*
* Exports the standard Overlord plugin ABI:
* PluginOnLoad, PluginOnEvent, PluginOnUnload, PluginSetCallback,
* PluginGetRuntime (returns "c" — tells the host this DLL can be freed)
*
* Build (Windows):
* cl /LD /O2 plugin.c /Fe:sample-c-windows-amd64.dll
* — or with MinGW —
* x86_64-w64-mingw32-gcc -shared -O2 -o sample-c-windows-amd64.dll plugin.c
*
* Build (Linux):
* gcc -shared -fPIC -O2 -o sample-c-linux-amd64.so plugin.c
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* ------------------------------------------------------------------ */
/* Platform helpers */
/* ------------------------------------------------------------------ */
#ifdef _WIN32
# define EXPORT __declspec(dllexport)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hDll, DWORD reason, LPVOID reserved) {
(void)hDll; (void)reserved;
switch (reason) {
case DLL_PROCESS_ATTACH: break;
case DLL_PROCESS_DETACH: break;
}
return TRUE;
}
#else
# define EXPORT __attribute__((visibility("default")))
#endif
/* ------------------------------------------------------------------ */
/* Host callback */
/* ------------------------------------------------------------------ */
#ifdef _WIN32
/* Windows: callback is void(__stdcall*)(ptr,len,ptr,len) */
typedef void (__stdcall *host_callback_t)(
const char *event, uintptr_t eventLen,
const char *payload, uintptr_t payloadLen);
#else
/* Unix: callback is void(*)(ctx, event, eventLen, payload, payloadLen) */
typedef void (*host_callback_t)(
uintptr_t ctx,
const char *event, int eventLen,
const char *payload, int payloadLen);
#endif
static host_callback_t g_callback = NULL;
#ifndef _WIN32
static uintptr_t g_callback_ctx = 0;
#endif
static void send_event(const char *event, const char *payload) {
if (!g_callback) return;
int elen = event ? (int)strlen(event) : 0;
int plen = payload ? (int)strlen(payload) : 0;
#ifdef _WIN32
g_callback(event, (uintptr_t)elen, payload, (uintptr_t)plen);
#else
g_callback(g_callback_ctx, event, elen, payload, plen);
#endif
}
/* ------------------------------------------------------------------ */
/* Plugin state (trivial example) */
/* ------------------------------------------------------------------ */
static char g_client_id[256];
/* ------------------------------------------------------------------ */
/* Exported ABI */
/* ------------------------------------------------------------------ */
EXPORT const char *PluginGetRuntime(void) {
return "c";
}
#ifdef _WIN32
EXPORT void PluginSetCallback(uint64_t cb) {
g_callback = (host_callback_t)(uintptr_t)cb;
}
EXPORT int PluginOnLoad(const char *hostInfo, int hostInfoLen, uint64_t cb) {
g_callback = (host_callback_t)(uintptr_t)cb;
#else
EXPORT int PluginOnLoad(const char *hostInfo, int hostInfoLen,
uintptr_t cb, uintptr_t ctx) {
g_callback = (host_callback_t)cb;
g_callback_ctx = ctx;
#endif
/* Minimal JSON-ish parse to grab clientId — keeps the example dependency-free */
g_client_id[0] = '\0';
if (hostInfo && hostInfoLen > 0) {
const char *key = "\"clientId\":\"";
const char *p = strstr(hostInfo, key); /* safe: hostInfo is nul-terminated by the Go caller copying it */
if (!p) {
key = "\"clientId\": \"";
p = strstr(hostInfo, key);
}
if (p) {
p += strlen(key);
const char *end = strchr(p, '"');
if (end) {
size_t n = (size_t)(end - p);
if (n >= sizeof(g_client_id)) n = sizeof(g_client_id) - 1;
memcpy(g_client_id, p, n);
g_client_id[n] = '\0';
}
}
}
fprintf(stderr, "[sample-c] loaded, clientId=%s\n", g_client_id);
send_event("ready", "{\"message\":\"sample-c plugin ready\"}");
return 0;
}
EXPORT int PluginOnEvent(const char *event, int eventLen,
const char *payload, int payloadLen) {
(void)payloadLen;
/* Simple echo for "ping" */
if (eventLen == 4 && memcmp(event, "ping", 4) == 0) {
send_event("pong", NULL);
return 0;
}
/* Echo back ui_message */
if (eventLen == 10 && memcmp(event, "ui_message", 10) == 0) {
fprintf(stderr, "[sample-c] got ui_message: %.*s\n", payloadLen, payload ? payload : "");
/* Build a tiny JSON response — payload is already JSON from the host */
char buf[512];
snprintf(buf, sizeof(buf), "{\"message\":\"echo from C: %.*s\"}",
payloadLen < 400 ? payloadLen : 400, payload ? payload : "");
send_event("echo", buf);
return 0;
}
fprintf(stderr, "[sample-c] unhandled event: %.*s\n", eventLen, event);
return 0;
}
EXPORT void PluginOnUnload(void) {
fprintf(stderr, "[sample-c] unloading\n");
g_callback = NULL;
#ifndef _WIN32
g_callback_ctx = 0;
#endif
g_client_id[0] = '\0';
}