From 7efca9440a7b06c8d50162d5a350b10791ce9037 Mon Sep 17 00:00:00 2001 From: Odboy Date: Wed, 22 Apr 2026 21:08:02 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4=20C=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E5=92=8C=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除 kenaito-conf-c-client 和 kenaito-conf-c-client-demo 模块。 --- kenaito-conf-c-client-demo/main.c | 137 --------- kenaito-conf-c-client/README.md | 307 -------------------- kenaito-conf-c-client/main.c | 447 ------------------------------ 3 files changed, 891 deletions(-) delete mode 100644 kenaito-conf-c-client-demo/main.c delete mode 100644 kenaito-conf-c-client/README.md delete mode 100644 kenaito-conf-c-client/main.c diff --git a/kenaito-conf-c-client-demo/main.c b/kenaito-conf-c-client-demo/main.c deleted file mode 100644 index 3effc9a..0000000 --- a/kenaito-conf-c-client-demo/main.c +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Kenaito Config Center C Client Demo - * - * 演示如何使用 C 客户端 SDK - * - * 编译: - * gcc -o demo main.c ../kenaito-conf-c-client/main.c -I/usr/local/opt/cjson/include -L/usr/local/opt/cjson/lib -lcurl -lcjson -lpthread - * - * 运行: - * ./demo - */ - -#include -#include -#include -#include -#include -#include - -/* 声明 SDK 类型和函数 */ -typedef struct { - char baseUrl[512]; - char appName[128]; - char env[32]; - char version[32]; - char token[256]; - int syncInterval; - int ignoreGlobal; - char cacheDir[256]; -} Config; - -typedef struct { - Config config; - void *configs; - long lastTime; - void (*onChange)(const char *key, const char *value); - void *curl; - int running; - void *syncThread; -} ConfigClient; - -extern void config_client_init(ConfigClient *client, Config *config); -extern const char *config_client_get(ConfigClient *client, const char *key); -extern void config_client_start(ConfigClient *client); -extern void config_client_stop(ConfigClient *client); - -/* 全局客户端实例,用于信号处理 */ -static ConfigClient *g_demo_client = NULL; -static int g_running = 1; - -/** - * 配置变更回调示例 - */ -void on_config_change(const char *key, const char *value) { - printf("\n[Callback] Config changed: %s = %s\n", key, value); - - if (strcmp(key, "log.level") == 0) { - printf(" -> Log level changed to: %s\n", value); - } else if (strcmp(key, "database.host") == 0) { - printf(" -> Database host changed to: %s\n", value); - } else if (strcmp(key, "database.port") == 0) { - printf(" -> Database port changed to: %s\n", value); - } else if (strcmp(key, "feature.enabled") == 0) { - printf(" -> Feature flag changed: %s\n", value); - } -} - -/** - * 信号处理 - 优雅退出 - */ -static void signal_handler(int sig) { - printf("\n[Signal] Received signal %d, shutting down...\n", sig); - g_running = 0; - if (g_demo_client) { - g_demo_client->running = 0; - } -} - -int main() { - printf("========================================\n"); - printf(" Kenaito Config Center C Client Demo\n"); - printf("========================================\n\n"); - - /* 注册信号处理 */ - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - - /* 配置客户端 */ - Config config = { - .baseUrl = "http://localhost:8080", - .appName = "kenaito-springboot-demo", - .env = "daily", - .version = "latest", - .token = "", - .syncInterval = 10, - .ignoreGlobal = 0, - .cacheDir = "." - }; - - ConfigClient client; - config_client_init(&client, &config); - client.onChange = on_config_change; - - g_demo_client = &client; - - /* 启动客户端 */ - config_client_start(&client); - - /* 主循环:演示配置读取 */ - printf("\n[Demo] Running... Press Ctrl+C to stop\n\n"); - - int iterations = 0; - while (g_running && iterations < 10) { - sleep(5); - - /* 演示:定期读取并打印配置 */ - const char *dbHost = config_client_get(&client, "database.host"); - const char *dbPort = config_client_get(&client, "database.port"); - const char *logLevel = config_client_get(&client, "log.level"); - const char *featureEnabled = config_client_get(&client, "feature.enabled"); - - printf("\n[Current Configs @ %ld]\n", time(NULL)); - printf(" database.host = %s\n", dbHost ? dbHost : "(not set)"); - printf(" database.port = %s\n", dbPort ? dbPort : "(not set)"); - printf(" log.level = %s\n", logLevel ? logLevel : "(not set)"); - printf(" feature.enabled = %s\n", featureEnabled ? featureEnabled : "(not set)"); - printf("\n"); - - iterations++; - } - - /* 停止客户端 */ - config_client_stop(&client); - - printf("\n[Demo] Finished\n"); - return 0; -} diff --git a/kenaito-conf-c-client/README.md b/kenaito-conf-c-client/README.md deleted file mode 100644 index cad9d0e..0000000 --- a/kenaito-conf-c-client/README.md +++ /dev/null @@ -1,307 +0,0 @@ -# Kenaito Config Center C Client - -C 语言的配置中心客户端 SDK,适用于嵌入式设备或高性能场景,依赖 libcurl。 - -## 依赖 - -- libcurl - -### Ubuntu/Debian - -```bash -apt-get install libcurl4-openssl-dev -``` - -### CentOS/RHEL - -```bash -yum install libcurl-devel -``` - -> **macOS**:系统自带 libcurl,无需额外安装。 - -## 快速开始 - -### 1. 安装依赖 - -#### Ubuntu/Debian - -```bash -apt-get install libcurl4-openssl-dev libcjson-dev -``` - -#### CentOS/RHEL - -```bash -yum install libcurl-devel libcjson-devel -``` - -#### macOS - -```bash -brew install cJSON -``` - -> **macOS**:系统自带 libcurl,无需额外安装。 - -### 2. 编译 SDK - -**macOS:** - -```bash -cd kenaito-conf-c-client -gcc -c main.c -o kenaito_conf.o -I/usr/local/opt/cjson/include -lcurl -ar rcs libkenaito_conf.a kenaito_conf.o -``` - -**Ubuntu/Debian:** - -```bash -cd kenaito-conf-c-client -gcc -c main.c -o kenaito_conf.o $(pkg-config --cflags libcjson) -lcurl -ar rcs libkenaito_conf.a kenaito_conf.o -``` - -### 3. 编译 Demo - -**macOS:** - -```bash -cd kenaito-conf-c-client-demo -gcc -o demo main.c ../kenaito-conf-c-client/main.c -I/usr/local/opt/cjson/include -lcurl -lpthread -./demo -``` - -**Ubuntu/Debian:** - -```bash -cd kenaito-conf-c-client-demo -gcc -o demo main.c ../kenaito-conf-c-client/main.c $(pkg-config --cflags libcjson) -lcurl -lpthread -./demo -``` - -### 4. 使用 SDK - -在你的项目中: - -```c -#include "kenaito-conf-c-client/main.c" - -// 或者链接静态库 -// gcc -o myapp myapp.c -lkenaito_conf -lcurl -lcjson -lpthread -``` - -### 5. 完整示例 - -```c -#include -#include "../kenaito-conf-c-client/main.c" - -void on_change(const char *key, const char *value) { - printf("config changed: %s = %s\n", key, value); -} - -int main() { - Config config = { - .baseUrl = "http://localhost:8080", - .appName = "my-app", - .env = "daily", - .version = "latest", - .token = "", - .syncInterval = 10, - .ignoreGlobal = 0, - .cacheDir = "." - }; - - ConfigClient client; - config_client_init(&client, &config); - client.onChange = on_change; - - // 启动客户端(拉取全量配置 + 开启定时同步) - config_client_start(&client); - - // 获取配置 - const char *dbHost = config_client_get(&client, "database.host"); - const char *dbPort = config_client_get(&client, "database.port"); - - printf("database.host = %s\n", dbHost ? dbHost : "not found"); - printf("database.port = %s\n", dbPort ? dbPort : "not found"); - - // 等待配置变更 - sleep(30); - - // 停止客户端 - config_client_stop(&client); - return 0; -} -``` - -### 3. 配置变更监听 - -```c -void on_config_change(const char *key, const char *value) { - printf("[ConfigChange] %s = %s\n", key, value); - // 在此处处理配置更新逻辑 - // 例如:重新初始化数据库连接、更新日志级别等 -} - -// 注册回调 -client.onChange = on_config_change; -``` - -## 配置参数 - -| 参数 | 说明 | 默认值 | 必填 | -|------|------|--------|------| -| `baseUrl` | 配置中心地址 | - | 是 | -| `appName` | 应用名称 | - | 是 | -| `env` | 环境(dev/daily/prod) | `dev` | 否 | -| `version` | 配置版本 | `latest` | 否 | -| `token` | 认证令牌 | 空 | 否 | -| `syncInterval` | 同步间隔(秒) | `10` | 否 | -| `ignoreGlobal` | 是否忽略全局配置 | `0` | 否 | -| `cacheDir` | 本地缓存目录 | `.` | 否 | - -## API 参考 - -### 初始化客户端 - -```c -void config_client_init(ConfigClient *client, Config *config); -``` - -### 获取配置值 - -```c -const char *config_client_get(ConfigClient *client, const char *key); -``` - -**参数:** -- `client`:客户端实例 -- `key`:配置键名 - -**返回值:** -- 成功:配置值字符串 -- 失败:`NULL` - -### 停止客户端 - -```c -void config_client_stop(ConfigClient *client); -``` - -**说明:** 释放 libcurl 资源,停止定时同步。 - -### 注册变更回调 - -```c -client.onChange = on_config_change; -``` - -**回调签名:** -```c -void on_config_change(const char *key, const char *value); -``` - -## 完整示例代码 - -```c -#include -#include -#include -#include -#include - -// 此处引入 kenaito-conf-c-client/main.c 的完整实现 -// 或使用编译好的库文件 - -void on_change(const char *key, const char *value) { - printf("[ConfigChange] %s = %s\n", key, value); -} - -int main() { - printf("=== Kenaito Config Center C Client Demo ===\n"); - - Config config = { - .baseUrl = "http://localhost:8080", - .appName = "kenaito-springboot-demo", - .env = "daily", - .version = "latest", - .token = "", - .syncInterval = 10, - .ignoreGlobal = 0, - .cacheDir = "." - }; - - ConfigClient client; - config_client_init(&client, &config); - client.onChange = on_change; - - // 获取配置 - const char *value = config_client_get(&client, "database.host"); - if (value) { - printf("database.host = %s\n", value); - } else { - printf("database.host not found\n"); - } - - // 等待配置变更(实际应用中应在此处运行业务逻辑) - printf("Listening for config changes...\n"); - sleep(30); - - config_client_stop(&client); - printf("Client stopped.\n"); - return 0; -} -``` - -## Demo - -运行示例项目: - -```bash -cd kenaito-conf-c-client-demo -gcc -o demo ../kenaito-conf-c-client/main.c -lcurl -./demo -``` - -Demo 默认配置: -- 应用名称:`kenaito-springboot-demo` -- 环境:`daily` -- 配置中心地址:`http://localhost:8080` -- 同步间隔:10 秒 - -## 注意事项 - -1. **JSON 解析**:当前示例代码仅演示 HTTP 请求,实际使用需集成 JSON 解析库(如 cJSON) -2. **配置缓存**:建议实现本地文件缓存,避免频繁请求配置中心 -3. **线程安全**:多线程环境下需自行添加锁机制保护配置读取 -4. **错误处理**:生产环境应完善网络异常、超时、重试等错误处理逻辑 -5. **内存管理**:使用 `config_client_stop()` 释放资源前不要访问配置 - -## 与其他客户端对比 - -| 特性 | C 客户端 | Go 客户端 | Java 客户端 | -|------|---------|----------|------------| -| 编译方式 | 手动 gcc | go build | Maven | -| 依赖管理 | 手动链接 | go mod | Maven | -| JSON 解析 | 需自行集成 | 标准库 | FastJSON2 | -| 定时同步 | 需自行实现 | ✅ | ✅ | -| 配置缓存 | 需自行实现 | ✅ | ✅ | -| 变更回调 | ✅ | ✅ | ✅ | -| 线程安全 | 需自行实现 | ✅ | ✅ | - -## 版本历史 - -- **1.0.0** - 初始版本 - - 基础 HTTP 拉取配置功能 - - 配置变更回调接口 - - 简化示例代码 - -## 后续开发计划 - -- [ ] 集成 cJSON 实现 JSON 解析 -- [ ] 实现定时轮询同步机制 -- [ ] 添加本地文件缓存支持 -- [ ] 完善错误处理和重试机制 -- [ ] 添加线程安全保护 diff --git a/kenaito-conf-c-client/main.c b/kenaito-conf-c-client/main.c deleted file mode 100644 index 568371d..0000000 --- a/kenaito-conf-c-client/main.c +++ /dev/null @@ -1,447 +0,0 @@ -/** - * Kenaito Config Center C Client SDK - * - * 完整的配置中心客户端,支持: - * - JSON 解析(cJSON) - * - 配置缓存到本地文件 - * - 定时同步配置变更 - * - 配置变更回调 - * - 全量/增量拉取 - * - * 依赖: - * - libcurl - * - cJSON - * - pthread - * - * 编译: - * gcc -c main.c -o kenaito_conf.o -I/usr/local/opt/cjson/include -lcurl - * - * @author odboy - * @version 1.0.0 - * @date 2026-10-16 - */ - -#ifndef KENAITO_CONF_CLIENT_IMPL -#define KENAITO_CONF_CLIENT_IMPL - -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_CONFIGS 256 -#define MAX_KEY_LEN 256 -#define MAX_VAL_LEN 4096 -#define CACHE_FILE ".kenaito-config-cache.json" - -/* ============ 配置结构 ============ */ -typedef struct { - char baseUrl[512]; - char appName[128]; - char env[32]; - char version[32]; - char token[256]; - int syncInterval; - int ignoreGlobal; - char cacheDir[256]; -} Config; - -/* ============ 配置条目 ============ */ -typedef struct { - char key[MAX_KEY_LEN]; - char value[MAX_VAL_LEN]; -} ConfigEntry; - -/* ============ 配置映射表 ============ */ -typedef struct { - ConfigEntry entries[MAX_CONFIGS]; - int count; -} ConfigMap; - -/* ============ 客户端实例 ============ */ -typedef struct { - Config config; - ConfigMap configs; - long lastTime; - void (*onChange)(const char *key, const char *value); - CURL *curl; - int running; - pthread_t syncThread; -} ConfigClient; - -/* ============ HTTP 响应缓冲区 ============ */ -typedef struct { - char *data; - size_t size; -} ResponseBuffer; - -/* 全局客户端实例 */ -static ConfigClient *g_client = NULL; - -/* ============ 工具函数 ============ */ - -/* HTTP 响应回调 */ -static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { - size_t totalSize = size * nmemb; - ResponseBuffer *buf = (ResponseBuffer *)userp; - char *ptr = realloc(buf->data, buf->size + totalSize + 1); - if (!ptr) return 0; - buf->data = ptr; - memcpy(&(buf->data[buf->size]), contents, totalSize); - buf->size += totalSize; - buf->data[buf->size] = 0; - return totalSize; -} - -/* HTTP POST 请求 */ -static char *http_post(ConfigClient *client, const char *url, const char *jsonBody) { - ResponseBuffer buf = {0}; - struct curl_slist *headers = NULL; - - headers = curl_slist_append(headers, "Content-Type: application/json"); - headers = curl_slist_append(headers, "Expect:"); - - curl_easy_setopt(client->curl, CURLOPT_URL, url); - curl_easy_setopt(client->curl, CURLOPT_POSTFIELDS, jsonBody); - curl_easy_setopt(client->curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(client->curl, CURLOPT_WRITEFUNCTION, write_callback); - curl_easy_setopt(client->curl, CURLOPT_WRITEDATA, &buf); - curl_easy_setopt(client->curl, CURLOPT_TIMEOUT, 10L); - curl_easy_setopt(client->curl, CURLOPT_FOLLOWLOCATION, 1L); - - CURLcode res = curl_easy_perform(client->curl); - curl_slist_free_all(headers); - - if (res != CURLE_OK) { - fprintf(stderr, "HTTP request failed: %s\n", curl_easy_strerror(res)); - free(buf.data); - return NULL; - } - - long httpCode = 0; - curl_easy_getinfo(client->curl, CURLINFO_RESPONSE_CODE, &httpCode); - if (httpCode != 200) { - fprintf(stderr, "HTTP %ld: %s\n", httpCode, buf.data ? buf.data : "empty response"); - free(buf.data); - return NULL; - } - - return buf.data; -} - -/* 从缓存加载配置 */ -static int load_from_cache(ConfigClient *client) { - FILE *f = fopen(CACHE_FILE, "r"); - if (!f) return 0; - - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - - char *jsonStr = malloc(fsize + 1); - fread(jsonStr, 1, fsize, f); - fclose(f); - jsonStr[fsize] = 0; - - cJSON *root = cJSON_Parse(jsonStr); - free(jsonStr); - - if (!root) return 0; - - cJSON *lastTimeObj = cJSON_GetObjectItem(root, "lastTime"); - if (lastTimeObj) { - client->lastTime = lastTimeObj->valueint; - } - - cJSON *configsObj = cJSON_GetObjectItem(root, "configs"); - if (configsObj && cJSON_IsArray(configsObj)) { - client->configs.count = 0; - int arrSize = cJSON_GetArraySize(configsObj); - for (int i = 0; i < arrSize && client->configs.count < MAX_CONFIGS; i++) { - cJSON *item = cJSON_GetArrayItem(configsObj, i); - cJSON *keyObj = cJSON_GetObjectItem(item, "key"); - cJSON *valObj = cJSON_GetObjectItem(item, "value"); - - if (keyObj && valObj && cJSON_IsString(keyObj) && cJSON_IsString(valObj)) { - strncpy(client->configs.entries[client->configs.count].key, - keyObj->valuestring, MAX_KEY_LEN - 1); - strncpy(client->configs.entries[client->configs.count].value, - valObj->valuestring, MAX_VAL_LEN - 1); - client->configs.count++; - } - } - } - - cJSON_Delete(root); - printf("[Cache] Loaded %d configs from %s\n", client->configs.count, CACHE_FILE); - return 1; -} - -/* 保存配置到缓存 */ -static void save_to_cache(ConfigClient *client) { - cJSON *root = cJSON_CreateObject(); - cJSON_AddNumberToObject(root, "lastTime", client->lastTime); - - cJSON *configsArr = cJSON_CreateArray(); - for (int i = 0; i < client->configs.count; i++) { - cJSON *item = cJSON_CreateObject(); - cJSON_AddStringToObject(item, "key", client->configs.entries[i].key); - cJSON_AddStringToObject(item, "value", client->configs.entries[i].value); - cJSON_AddItemToArray(configsArr, item); - } - cJSON_AddItemToObject(root, "configs", configsArr); - - char *jsonStr = cJSON_PrintUnformatted(root); - FILE *f = fopen(CACHE_FILE, "w"); - if (f) { - fprintf(f, "%s", jsonStr); - fclose(f); - printf("[Cache] Saved %d configs to %s\n", client->configs.count, CACHE_FILE); - } - - free(jsonStr); - cJSON_Delete(root); -} - -/* 获取配置值 */ -const char *config_client_get(ConfigClient *client, const char *key) { - for (int i = 0; i < client->configs.count; i++) { - if (strcmp(client->configs.entries[i].key, key) == 0) - return client->configs.entries[i].value; - } - return NULL; -} - -/* 解析 JSON 响应 */ -static int parse_json_response(const char *jsonStr, ConfigClient *client) { - cJSON *root = cJSON_Parse(jsonStr); - if (!root) { - fprintf(stderr, "Failed to parse JSON: %s\n", cJSON_GetErrorPtr()); - return -1; - } - - cJSON *successObj = cJSON_GetObjectItem(root, "success"); - if (successObj && cJSON_IsBool(successObj) && !successObj->valueint) { - cJSON *msgObj = cJSON_GetObjectItem(root, "message"); - fprintf(stderr, "Server error: %s\n", msgObj ? msgObj->valuestring : "unknown"); - cJSON_Delete(root); - return -1; - } - - cJSON *dataObj = cJSON_GetObjectItem(root, "data"); - if (!dataObj) { - fprintf(stderr, "No data in response\n"); - cJSON_Delete(root); - return -1; - } - - /* 全量配置 */ - cJSON *configsObj = cJSON_GetObjectItem(dataObj, "configs"); - if (configsObj && cJSON_IsArray(configsObj)) { - client->configs.count = 0; - int arrSize = cJSON_GetArraySize(configsObj); - for (int i = 0; i < arrSize && client->configs.count < MAX_CONFIGS; i++) { - cJSON *item = cJSON_GetArrayItem(configsObj, i); - cJSON *keyObj = cJSON_GetObjectItem(item, "key"); - cJSON *valObj = cJSON_GetObjectItem(item, "value"); - - if (keyObj && valObj && cJSON_IsString(keyObj) && cJSON_IsString(valObj)) { - strncpy(client->configs.entries[client->configs.count].key, - keyObj->valuestring, MAX_KEY_LEN - 1); - - const char *oldVal = config_client_get(client, keyObj->valuestring); - - strncpy(client->configs.entries[client->configs.count].value, - valObj->valuestring, MAX_VAL_LEN - 1); - - /* 检测变更并触发回调 */ - if (client->onChange && oldVal && strcmp(oldVal, valObj->valuestring) != 0) { - printf("[Change] %s = %s -> %s\n", - keyObj->valuestring, oldVal, valObj->valuestring); - client->onChange(keyObj->valuestring, valObj->valuestring); - } - - client->configs.count++; - } - } - } - - /* 增量变更 */ - cJSON *changesObj = cJSON_GetObjectItem(dataObj, "changes"); - if (changesObj && cJSON_IsArray(changesObj)) { - int arrSize = cJSON_GetArraySize(changesObj); - for (int i = 0; i < arrSize; i++) { - cJSON *item = cJSON_GetArrayItem(changesObj, i); - cJSON *keyObj = cJSON_GetObjectItem(item, "key"); - cJSON *valObj = cJSON_GetObjectItem(item, "value"); - - if (keyObj && valObj && cJSON_IsString(keyObj) && cJSON_IsString(valObj)) { - /* 更新或添加配置 */ - int found = 0; - for (int j = 0; j < client->configs.count; j++) { - if (strcmp(client->configs.entries[j].key, keyObj->valuestring) == 0) { - const char *oldVal = client->configs.entries[j].value; - strncpy(client->configs.entries[j].value, - valObj->valuestring, MAX_VAL_LEN - 1); - - if (client->onChange && strcmp(oldVal, valObj->valuestring) != 0) { - printf("[Change] %s = %s -> %s\n", - keyObj->valuestring, oldVal, valObj->valuestring); - client->onChange(keyObj->valuestring, valObj->valuestring); - } - found = 1; - break; - } - } - - if (!found && client->configs.count < MAX_CONFIGS) { - strncpy(client->configs.entries[client->configs.count].key, - keyObj->valuestring, MAX_KEY_LEN - 1); - strncpy(client->configs.entries[client->configs.count].value, - valObj->valuestring, MAX_VAL_LEN - 1); - client->configs.count++; - - if (client->onChange) { - printf("[New] %s = %s\n", keyObj->valuestring, valObj->valuestring); - client->onChange(keyObj->valuestring, valObj->valuestring); - } - } - } - } - } - - /* 更新 lastTime */ - cJSON *lastTimeObj = cJSON_GetObjectItem(dataObj, "lastTime"); - if (lastTimeObj && cJSON_IsNumber(lastTimeObj)) { - client->lastTime = lastTimeObj->valueint; - } - - cJSON_Delete(root); - return 0; -} - -/* ============ 客户端 API ============ */ - -/** - * 初始化客户端 - * @param client 客户端实例 - * @param config 配置参数 - */ -void config_client_init(ConfigClient *client, Config *config) { - client->config = *config; - client->configs.count = 0; - client->lastTime = 0; - client->onChange = NULL; - client->running = 0; - client->curl = curl_easy_init(); - - g_client = client; - - /* 尝试从缓存加载 */ - if (!load_from_cache(client)) { - printf("[Cache] No cache found, will fetch from server\n"); - } -} - -/** - * 拉取配置(全量或增量) - * @param client 客户端实例 - * @param incremental 是否增量拉取 - * @return 0 成功,-1 失败 - */ -static int fetch_configs(ConfigClient *client, int incremental) { - char url[1024]; - char payload[1024]; - - if (incremental && client->lastTime > 0) { - snprintf(url, sizeof(url), "%s/api/fetchChangedConfigs", client->config.baseUrl); - snprintf(payload, sizeof(payload), - "{\"appName\":\"%s\",\"env\":\"%s\",\"version\":\"%s\"," - "\"ignoreGlobal\":%s,\"token\":\"%s\",\"lastTime\":%ld}", - client->config.appName, client->config.env, client->config.version, - client->config.ignoreGlobal ? "true" : "false", - client->config.token, client->lastTime); - } else { - snprintf(url, sizeof(url), "%s/api/fetchAllConfigs", client->config.baseUrl); - snprintf(payload, sizeof(payload), - "{\"appName\":\"%s\",\"env\":\"%s\",\"version\":\"%s\"," - "\"ignoreGlobal\":%s,\"token\":\"%s\"}", - client->config.appName, client->config.env, client->config.version, - client->config.ignoreGlobal ? "true" : "false", - client->config.token); - } - - printf("[%s] Fetching from %s...\n", incremental ? "Incremental" : "Full", url); - char *response = http_post(client, url, payload); - - if (!response) { - fprintf(stderr, "Failed to fetch configs\n"); - return -1; - } - - int ret = parse_json_response(response, client); - free(response); - - if (ret == 0) { - save_to_cache(client); - } - - return ret; -} - -/* 定时同步线程 */ -static void *sync_thread_func(void *arg) { - ConfigClient *client = (ConfigClient *)arg; - - while (client->running) { - sleep(client->config.syncInterval); - - if (!client->running) break; - - fetch_configs(client, 1); - } - - return NULL; -} - -/** - * 启动客户端 - * @param client 客户端实例 - */ -void config_client_start(ConfigClient *client) { - /* 首次全量拉取 */ - fetch_configs(client, 0); - - /* 启动定时同步线程 */ - client->running = 1; - pthread_create(&client->syncThread, NULL, sync_thread_func, client); - printf("[Sync] Started background sync thread (interval: %ds)\n", - client->config.syncInterval); -} - -/** - * 停止客户端 - * @param client 客户端实例 - */ -void config_client_stop(ConfigClient *client) { - client->running = 0; - - if (client->syncThread) { - pthread_join(client->syncThread, NULL); - } - - save_to_cache(client); - - if (client->curl) { - curl_easy_cleanup(client->curl); - } - - curl_global_cleanup(); - printf("[Client] Stopped\n"); -} - -#endif /* KENAITO_CONF_CLIENT_IMPL */