Files
dstalk/examples/example_plugin/example_plugin.cpp
XiuChengWu f2da0f2ed4 Add metadata validation script and module documentation
- Introduced a new Python script `check_agents_metadata.py` for validating agent metadata, including YAML parsing, rating ranges, and cross-references.
- Added usage instructions and exit codes for the script.
- Created a new markdown file `模块目录和功能说明.md` to outline the directory structure and functionality of the modules.
- Added a text file `说明此文件不可AI修改.txt` to specify that certain files should not be modified by AI, including important information about the `dstalk` framework and its modules.
2026-05-31 00:00:58 +08:00

164 lines
6.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* @file example_plugin.cpp
* @brief Example plugin demonstrating the dstalk plugin API contract.
* 示例插件:演示 dstalk 插件 API 契约。
* Copyright (c) 2026 dstalk contributors. GPLv3.
*
* Build instructions (conceptual) / 构建说明(概念性):
*
* Linux / macOS:
* g++ -std=c++20 -shared -fPIC -fvisibility=hidden \
* -I<dstalk-include-dir> \
* -o example_plugin.so example_plugin.cpp
*
* Windows (MSVC):
* cl /std:c++20 /LD /EHsc \
* /I<dstalk-include-dir> \
* /Fe:example_plugin.dll example_plugin.cpp
*
* The resulting `.so` / `.dylib` / `.dll` can be loaded with:
* 生成的 .so / .dylib / .dll 可通过以下方式加载:
*
* int id = dstalk_plugin_load("./example_plugin.so");
*/
#include "dstalk/dstalk_host.h"
#include <cstdio> /* fprintf */
#include <cstdlib> /* malloc, free */
#include <cstring> /* strlen, strcmp */
/* ------------------------------------------------------------------
* 私有状态(每个插件加载实例一份) / Private state (one instance per plugin load)
* ------------------------------------------------------------------
*
* In a more complex plugin this struct would hold open database
* connections, configuration, etc.
* 在更复杂的插件中,此结构体可包含打开的数据库连接、配置等。
*/
struct ExampleState {
int call_count;
};
/* ------------------------------------------------------------------
* 保存主机 API 表,以便回调函数使用主机服务 / Stored host API table so callbacks can use host services.
* ------------------------------------------------------------------ */
static const dstalk_host_api_t* g_host = nullptr;
static ExampleState g_state; /* 非堆分配:在库映射期间持续有效 / not heap-allocated: stays valid
while the library is mapped */
/* ------------------------------------------------------------------
* on_init原 on_load / on_init (was on_load)
* ------------------------------------------------------------------ */
// 插件初始化:保存主机指针,重置调用计数,记录加载消息 / Plugin init: store host pointer, reset call count, log loaded message.
static int my_on_init(const dstalk_host_api_t* host)
{
g_host = host;
g_state.call_count = 0;
/* TODO: 真实插件应在此处初始化资源 / real plugins would initialise resources here:
* - 通过 host->config_get 解析插件专属配置文件 / parse a plugin-specific config file via host->config_get
* - 打开日志文件 / open a log file
* - 连接到本地服务 / connect to a local service
* - 通过 host->register_service 注册服务 / register services via host->register_service
*
* Return non-zero to signal a fatal initialisation error to the
* host, which will then unload the plugin immediately.
* 返回非零值以向主机报告致命初始化错误,主机将立即卸载该插件。
*/
if (host) {
host->log(DSTALK_LOG_INFO, "[example-plugin] loaded (v1.0.0)");
} else {
std::fprintf(stderr, "[example-plugin] loaded (v1.0.0)\n");
}
return 0;
}
/* ------------------------------------------------------------------
* on_shutdown原 on_unload / on_shutdown (was on_unload)
* ------------------------------------------------------------------ */
// 插件关闭:记录调用次数,释放资源 / Plugin shutdown: log call count, release any resources.
static void my_on_shutdown(void)
{
/* TODO: 释放 on_init 中分配的所有资源。此函数返回后主机将卸载共享库。 / release any resources allocated in on_init. After this
* function returns the host will unmap the shared library. */
if (g_host) {
g_host->log(DSTALK_LOG_INFO, "[example-plugin] unloaded (%d events processed)",
g_state.call_count);
} else {
std::fprintf(stderr,
"[example-plugin] unloaded (%d callbacks processed)\n",
g_state.call_count);
}
}
/* ------------------------------------------------------------------
* on_event原 on_message / on_event (was on_message)
* ------------------------------------------------------------------ */
// 插件事件处理:记录消息事件,忽略其他事件类型 / Plugin event handler: log message events, ignore other event types.
static void my_on_event(int event_type, const void* data)
{
if (event_type == DSTALK_EVENT_MESSAGE && data) {
const auto* msg = static_cast<const dstalk_message_t*>(data);
g_state.call_count++;
/* 真实插件可能: / A real plugin might:
* - 将对话记录到文件 / log the conversation to a file
* - 实施内容审核 / apply content moderation
* - 实时翻译消息 / translate messages on the fly
* - 用外部数据丰富消息 / enrich messages with external data
*/
if (g_host) {
g_host->log(DSTALK_LOG_DEBUG, "[example-plugin] message | role=%-9s len=%zu",
msg->role, std::strlen(msg->content));
} else {
std::fprintf(stderr,
"[example-plugin] message | role=%-9s len=%zu\n",
msg->role, std::strlen(msg->content));
}
}
/* 其他事件类型 / Other event types (DSTALK_EVENT_SESSION_CLEAR, DSTALK_EVENT_CONFIG_CHANGED,
DSTALK_EVENT_PLUGIN_LOADED, DSTALK_EVENT_PLUGIN_UNLOADED, DSTALK_EVENT_CUSTOM+)
此最小化插件静默忽略 / are silently ignored by this minimal plugin. */
}
/* ------------------------------------------------------------------
* 插件描述符(静态 —— 在 .so 的生命周期内有效) / Plugin descriptor (static -- lives for the lifetime of the .so)
* ------------------------------------------------------------------ */
static dstalk_plugin_info_t g_info = {
/* .name = */ "example-plugin",
/* .version = */ "1.0.0",
/* .description = */ "An example plugin for dstalk / dstalk 示例插件",
/* .api_version = */ DSTALK_API_VERSION,
/* .dependencies = */ {nullptr},
/* .on_init = */ my_on_init,
/* .on_shutdown = */ my_on_shutdown,
/* .on_event = */ my_on_event,
};
/* ------------------------------------------------------------------
* 必须入口点 / Mandatory entry point
* ------------------------------------------------------------------
*
* The host looks for this symbol via dlsym / GetProcAddress.
* 主机通过 dlsym / GetProcAddress 查找此符号。
* It MUST be declared extern "C" so the name is not mangled.
* 必须声明为 extern "C" 以避免名称修饰。
*/
// 返回插件描述符给主机加载器 / Returns the plugin descriptor to the host loader.
extern "C" DSTALK_PLUGIN_EXPORT dstalk_plugin_info_t* dstalk_plugin_init(void)
{
return &g_info;
}