feat: 新增 C++ 和 Rust 客户端 SDK 及 Docker 构建支持
- 新增 kenaito-conf-cpp-client / kenaito-conf-rust-client 及对应 demo - 新增 Dockerfile.cpp / Dockerfile.rust - README 目录结构补充 C++/Rust 客户端 - README_DOCKERFILE 补充 Windows docker run 命令,新增 C++/Rust 段落
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(kenaito-conf-cpp-client VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(CURL REQUIRED)
|
||||
|
||||
# 自动下载 nlohmann/json(单头文件)
|
||||
set(JSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/nlohmann)
|
||||
if(NOT EXISTS ${JSON_INCLUDE_DIR}/json.hpp)
|
||||
message(STATUS "Downloading nlohmann/json.hpp...")
|
||||
file(MAKE_DIRECTORY ${JSON_INCLUDE_DIR})
|
||||
file(DOWNLOAD
|
||||
https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp
|
||||
${JSON_INCLUDE_DIR}/json.hpp
|
||||
SHOW_PROGRESS
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(kenaito_conf_client STATIC
|
||||
src/client.cpp
|
||||
)
|
||||
|
||||
target_include_directories(kenaito_conf_client
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party
|
||||
PRIVATE
|
||||
${CURL_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(kenaito_conf_client
|
||||
PRIVATE
|
||||
${CURL_LIBRARIES}
|
||||
)
|
||||
|
||||
# Install
|
||||
install(TARGETS kenaito_conf_client
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
install(DIRECTORY include/kenaito_conf
|
||||
DESTINATION include
|
||||
)
|
||||
@@ -0,0 +1,112 @@
|
||||
# Kenaito Config Center C++ Client
|
||||
|
||||
C++ 客户端 SDK,适用于 C++11 及以上项目。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 从配置中心拉取应用配置
|
||||
- 定时同步配置变更
|
||||
- 支持配置变更回调监听
|
||||
- 本地文件缓存(配置中心不可用时降级)
|
||||
|
||||
## 依赖
|
||||
|
||||
- C++11 或更高版本
|
||||
- libcurl
|
||||
- nlohmann/json(已包含在 third_party 目录)
|
||||
|
||||
## 编译
|
||||
|
||||
```bash
|
||||
cd kenaito-conf-cpp-client
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
```cpp
|
||||
#include <kenaito_conf/client.h>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
kenaito::Config config;
|
||||
config.base_url = "http://localhost:8080";
|
||||
config.app_name = "my-app";
|
||||
config.env = "daily";
|
||||
config.sync_interval = 10;
|
||||
config.cache_dir = ".";
|
||||
|
||||
kenaito::Client client(config);
|
||||
|
||||
// 监听配置变更
|
||||
client.on_change([](const std::map<std::string, std::string>& changed) {
|
||||
std::cout << "Config changed:" << std::endl;
|
||||
for (const auto& [k, v] : changed) {
|
||||
std::cout << " " << k << " = " << v << std::endl;
|
||||
}
|
||||
});
|
||||
|
||||
// 启动客户端
|
||||
if (!client.start()) {
|
||||
std::cerr << "Failed to start config client" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
std::string db_host = client.get("database.host");
|
||||
std::cout << "database.host = " << db_host << std::endl;
|
||||
|
||||
// 获取所有配置
|
||||
auto all = client.get_all();
|
||||
for (const auto& [k, v] : all) {
|
||||
std::cout << k << " = " << v << std::endl;
|
||||
}
|
||||
|
||||
// 手动同步
|
||||
client.sync_once();
|
||||
|
||||
// 停止
|
||||
client.stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 配置项
|
||||
|
||||
| 参数 | 类型 | 说明 | 默认值 |
|
||||
|------|------|------|--------|
|
||||
| `base_url` | string | 配置中心地址 | `http://localhost:8080` |
|
||||
| `app_name` | string | 应用名称 | (必填) |
|
||||
| `env` | string | 环境标识 | `dev` |
|
||||
| `version` | string | 配置版本 | `latest` |
|
||||
| `token` | string | 应用 Token | 空 |
|
||||
| `sync_interval` | int | 同步间隔(秒) | `60` |
|
||||
| `ignore_global` | bool | 忽略全局配置 | `false` |
|
||||
| `cache_dir` | string | 缓存目录 | `.` |
|
||||
|
||||
## Demo
|
||||
|
||||
```bash
|
||||
cd kenaito-conf-cpp-client-demo
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
./demo
|
||||
```
|
||||
|
||||
## 环境变量
|
||||
|
||||
Demo 支持以下环境变量:
|
||||
|
||||
| 变量名 | 说明 | 默认值 |
|
||||
|--------|------|--------|
|
||||
| `KENAITO_BASE_URL` | 配置中心地址 | `http://localhost:8080` |
|
||||
| `KENAITO_APP_NAME` | 应用名称 | `kenaito-springboot-demo` |
|
||||
| `KENAITO_ENV` | 环境标识 | `daily` |
|
||||
| `KENAITO_VERSION` | 配置版本 | `latest` |
|
||||
| `KENAITO_TOKEN` | 应用 Token | 空 |
|
||||
| `KENAITO_SYNC_INTERVAL` | 同步间隔(秒) | `10` |
|
||||
| `KENAITO_CACHE_DIR` | 缓存目录 | `.` |
|
||||
@@ -0,0 +1,112 @@
|
||||
# Kenaito Config Center C++ Client
|
||||
|
||||
C++ client SDK for the Kenaito Config Center, suitable for C++11 and above.
|
||||
|
||||
## Features
|
||||
|
||||
- Fetch application configs from the config center
|
||||
- Periodic config sync
|
||||
- Config change callback listener
|
||||
- Local file cache (fallback when config center is unavailable)
|
||||
|
||||
## Dependencies
|
||||
|
||||
- C++11 or higher
|
||||
- libcurl
|
||||
- nlohmann/json (included in third_party directory)
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
cd kenaito-conf-cpp-client
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```cpp
|
||||
#include <kenaito_conf/client.h>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
kenaito::Config config;
|
||||
config.base_url = "http://localhost:8080";
|
||||
config.app_name = "my-app";
|
||||
config.env = "daily";
|
||||
config.sync_interval = 10;
|
||||
config.cache_dir = ".";
|
||||
|
||||
kenaito::Client client(config);
|
||||
|
||||
// Listen for config changes
|
||||
client.on_change([](const std::map<std::string, std::string>& changed) {
|
||||
std::cout << "Config changed:" << std::endl;
|
||||
for (const auto& [k, v] : changed) {
|
||||
std::cout << " " << k << " = " << v << std::endl;
|
||||
}
|
||||
});
|
||||
|
||||
// Start client
|
||||
if (!client.start()) {
|
||||
std::cerr << "Failed to start config client" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get config
|
||||
std::string db_host = client.get("database.host");
|
||||
std::cout << "database.host = " << db_host << std::endl;
|
||||
|
||||
// Get all configs
|
||||
auto all = client.get_all();
|
||||
for (const auto& [k, v] : all) {
|
||||
std::cout << k << " = " << v << std::endl;
|
||||
}
|
||||
|
||||
// Manual sync
|
||||
client.sync_once();
|
||||
|
||||
// Stop
|
||||
client.stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
| Parameter | Type | Description | Default |
|
||||
|-----------|------|-------------|---------|
|
||||
| `base_url` | string | Config center URL | `http://localhost:8080` |
|
||||
| `app_name` | string | Application name | (Required) |
|
||||
| `env` | string | Environment | `dev` |
|
||||
| `version` | string | Config version | `latest` |
|
||||
| `token` | string | App token | Empty |
|
||||
| `sync_interval` | int | Sync interval (seconds) | `60` |
|
||||
| `ignore_global` | bool | Whether to ignore global configs | `false` |
|
||||
| `cache_dir` | string | Cache directory | `.` |
|
||||
|
||||
## Demo
|
||||
|
||||
```bash
|
||||
cd kenaito-conf-cpp-client-demo
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
./demo
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
The demo supports the following environment variables:
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `KENAITO_BASE_URL` | Config center URL | `http://localhost:8080` |
|
||||
| `KENAITO_APP_NAME` | Application name | `kenaito-springboot-demo` |
|
||||
| `KENAITO_ENV` | Environment | `daily` |
|
||||
| `KENAITO_VERSION` | Config version | `latest` |
|
||||
| `KENAITO_TOKEN` | App token | Empty |
|
||||
| `KENAITO_SYNC_INTERVAL` | Sync interval (seconds) | `10` |
|
||||
| `KENAITO_CACHE_DIR` | Cache directory | `.` |
|
||||
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
namespace kenaito {
|
||||
|
||||
struct Config {
|
||||
std::string base_url = "http://localhost:8080";
|
||||
std::string app_name;
|
||||
std::string env = "dev";
|
||||
std::string version = "latest";
|
||||
std::string token;
|
||||
int sync_interval = 60;
|
||||
bool ignore_global = false;
|
||||
std::string cache_dir = ".";
|
||||
};
|
||||
|
||||
using ChangeHandler = std::function<void(const std::map<std::string, std::string>&)>;
|
||||
|
||||
class Cache {
|
||||
public:
|
||||
explicit Cache(const std::string& dir);
|
||||
bool write(const std::string& json_str);
|
||||
std::string read();
|
||||
|
||||
private:
|
||||
std::string dir_;
|
||||
static const std::string CACHE_FILE;
|
||||
};
|
||||
|
||||
class Listener {
|
||||
public:
|
||||
void on_change(ChangeHandler handler);
|
||||
void notify(const std::map<std::string, std::string>& changed);
|
||||
|
||||
private:
|
||||
std::mutex mu_;
|
||||
std::vector<ChangeHandler> handlers_;
|
||||
};
|
||||
|
||||
class Client {
|
||||
public:
|
||||
explicit Client(const Config& config);
|
||||
~Client();
|
||||
|
||||
void on_change(ChangeHandler handler);
|
||||
std::string get(const std::string& key);
|
||||
std::map<std::string, std::string> get_all();
|
||||
bool start();
|
||||
void stop();
|
||||
void sync_once();
|
||||
|
||||
private:
|
||||
bool fetch_all();
|
||||
bool fetch_changed();
|
||||
void apply_configs(const std::map<std::string, std::string>& data);
|
||||
std::string http_post(const std::string& url, const std::string& body);
|
||||
|
||||
Config config_;
|
||||
Cache cache_;
|
||||
Listener listener_;
|
||||
std::map<std::string, std::string> configs_;
|
||||
int64_t last_time_ = 0;
|
||||
std::mutex mu_;
|
||||
std::atomic<bool> started_{false};
|
||||
std::atomic<bool> stop_flag_{false};
|
||||
std::thread sync_thread_;
|
||||
};
|
||||
|
||||
} // namespace kenaito
|
||||
@@ -0,0 +1,293 @@
|
||||
#include "kenaito_conf/client.h"
|
||||
#include <curl/curl.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
// nlohmann/json single header is bundled
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace kenaito {
|
||||
|
||||
// ---- Cache ----
|
||||
|
||||
const std::string Cache::CACHE_FILE = "config-cache.json";
|
||||
|
||||
Cache::Cache(const std::string& dir) : dir_(dir) {}
|
||||
|
||||
bool Cache::write(const std::string& json_str) {
|
||||
std::string path = dir_ + "/" + CACHE_FILE;
|
||||
std::ofstream ofs(path);
|
||||
if (!ofs.is_open()) return false;
|
||||
ofs << json_str;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Cache::read() {
|
||||
std::string path = dir_ + "/" + CACHE_FILE;
|
||||
std::ifstream ifs(path);
|
||||
if (!ifs.is_open()) return "";
|
||||
std::stringstream ss;
|
||||
ss << ifs.rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// ---- Listener ----
|
||||
|
||||
void Listener::on_change(ChangeHandler handler) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
handlers_.push_back(std::move(handler));
|
||||
}
|
||||
|
||||
void Listener::notify(const std::map<std::string, std::string>& changed) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
for (auto& h : handlers_) {
|
||||
h(changed);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Client ----
|
||||
|
||||
static size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) {
|
||||
auto* str = static_cast<std::string*>(userp);
|
||||
str->append(static_cast<char*>(contents), size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
Client::Client(const Config& config)
|
||||
: config_(config), cache_(config.cache_dir) {
|
||||
if (config_.version.empty()) config_.version = "latest";
|
||||
if (config_.sync_interval <= 0) config_.sync_interval = 60;
|
||||
if (config_.cache_dir.empty()) config_.cache_dir = ".";
|
||||
}
|
||||
|
||||
Client::~Client() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void Client::on_change(ChangeHandler handler) {
|
||||
listener_.on_change(std::move(handler));
|
||||
}
|
||||
|
||||
std::string Client::get(const std::string& key) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
auto it = configs_.find(key);
|
||||
return it != configs_.end() ? it->second : "";
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> Client::get_all() {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
return configs_;
|
||||
}
|
||||
|
||||
bool Client::start() {
|
||||
if (started_.exchange(true)) return true;
|
||||
|
||||
if (!fetch_all()) {
|
||||
std::cerr << "[ConfigClient] fetch all configs error, trying cache" << std::endl;
|
||||
std::string cached = cache_.read();
|
||||
if (!cached.empty()) {
|
||||
try {
|
||||
auto j = json::parse(cached);
|
||||
std::map<std::string, std::string> data;
|
||||
for (auto& [k, v] : j.items()) {
|
||||
if (v.is_string()) data[k] = v.get<std::string>();
|
||||
}
|
||||
apply_configs(data);
|
||||
std::cerr << "[ConfigClient] loaded " << configs_.size() << " configs from cache" << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[ConfigClient] cache parse error: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "[ConfigClient] fetch configs failed and no cache" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::stop() {
|
||||
stop_flag_ = true;
|
||||
if (sync_thread_.joinable()) {
|
||||
sync_thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::sync_once() {
|
||||
if (!fetch_changed()) {
|
||||
std::cerr << "[ConfigClient] sync error" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Client::http_post(const std::string& url, const std::string& body) {
|
||||
CURL* curl = curl_easy_init();
|
||||
if (!curl) return "";
|
||||
|
||||
std::string response;
|
||||
struct curl_slist* headers = nullptr;
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if (res != CURLE_OK) return "";
|
||||
return response;
|
||||
}
|
||||
|
||||
bool Client::fetch_all() {
|
||||
std::string url = config_.base_url + "/api/fetchAllConfigs";
|
||||
|
||||
json payload;
|
||||
payload["appName"] = config_.app_name;
|
||||
payload["env"] = config_.env;
|
||||
payload["version"] = config_.version;
|
||||
payload["ignoreGlobal"] = config_.ignore_global;
|
||||
payload["token"] = config_.token;
|
||||
|
||||
std::string resp = http_post(url, payload.dump());
|
||||
if (resp.empty()) return false;
|
||||
|
||||
try {
|
||||
auto j = json::parse(resp);
|
||||
|
||||
if (j.contains("code") && j["code"].get<int>() != 0) {
|
||||
std::string msg = j.value("msg", "unknown");
|
||||
std::cerr << "[ConfigClient] server error: " << msg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (j.contains("latest.fetch.timestamp")) {
|
||||
last_time_ = std::stoll(j["latest.fetch.timestamp"].get<std::string>());
|
||||
}
|
||||
|
||||
// cache raw response
|
||||
cache_.write(resp);
|
||||
|
||||
// apply configs
|
||||
std::map<std::string, std::string> data;
|
||||
for (auto& [k, v] : j.items()) {
|
||||
if (v.is_string()) data[k] = v.get<std::string>();
|
||||
}
|
||||
apply_configs(data);
|
||||
|
||||
std::cerr << "[ConfigClient] fetched " << configs_.size() << " configs" << std::endl;
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[ConfigClient] parse error: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::fetch_changed() {
|
||||
std::string url = config_.base_url + "/api/fetchChangedConfigs";
|
||||
|
||||
json payload;
|
||||
payload["appName"] = config_.app_name;
|
||||
payload["env"] = config_.env;
|
||||
payload["version"] = config_.version;
|
||||
payload["lastTime"] = last_time_;
|
||||
payload["ignoreGlobal"] = config_.ignore_global;
|
||||
|
||||
std::string resp = http_post(url, payload.dump());
|
||||
if (resp.empty()) {
|
||||
std::cerr << "[ConfigClient] fetch_changed: empty response (network error or timeout)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
auto j = json::parse(resp);
|
||||
|
||||
if (j.contains("code") && j["code"].get<int>() != 0) {
|
||||
std::string msg = j.value("msg", "unknown");
|
||||
std::cerr << "[ConfigClient] fetch_changed: server error code=" << j["code"] << " msg=" << msg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!j.contains("data")) {
|
||||
std::cerr << "[ConfigClient] fetch_changed: missing 'data' field in response" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto data = j["data"];
|
||||
|
||||
if (data.contains("latest.fetch.timestamp")) {
|
||||
last_time_ = std::stoll(data["latest.fetch.timestamp"].get<std::string>());
|
||||
data.erase("latest.fetch.timestamp");
|
||||
}
|
||||
|
||||
// handle deleted keys
|
||||
if (data.contains("deletedKeys") && !data["deletedKeys"].get<std::string>().empty()) {
|
||||
std::string deleted_str = data["deletedKeys"].get<std::string>();
|
||||
std::istringstream iss(deleted_str);
|
||||
std::string key;
|
||||
std::vector<std::string> deleted_keys;
|
||||
while (std::getline(iss, key, ',')) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
configs_.erase(key);
|
||||
deleted_keys.push_back(key);
|
||||
}
|
||||
|
||||
std::string keys;
|
||||
for (const auto& k : deleted_keys) {
|
||||
if (!keys.empty()) keys += ", ";
|
||||
keys += k;
|
||||
}
|
||||
std::cerr << "[ConfigClient] " << deleted_keys.size() << " configs deleted: " << keys << std::endl;
|
||||
data.erase("deletedKeys");
|
||||
}
|
||||
|
||||
// handle changed configs
|
||||
std::map<std::string, std::string> changed;
|
||||
for (auto& [k, v] : data.items()) {
|
||||
if (v.is_string()) {
|
||||
changed[k] = v.get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed.empty()) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
for (auto& [k, v] : changed) {
|
||||
configs_[k] = v;
|
||||
}
|
||||
}
|
||||
listener_.notify(changed);
|
||||
|
||||
std::string keys;
|
||||
for (auto& [k, v] : changed) {
|
||||
if (!keys.empty()) keys += ", ";
|
||||
keys += k;
|
||||
}
|
||||
std::cerr << "[ConfigClient] " << changed.size() << " configs changed: " << keys << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[ConfigClient] fetch_changed: parse error: " << e.what() << std::endl;
|
||||
std::cerr << "[ConfigClient] response was: " << resp.substr(0, 200) << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::apply_configs(const std::map<std::string, std::string>& data) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
for (auto& [k, v] : data) {
|
||||
if (k.substr(0, 8) == "kenaito." || k == "latest.fetch.timestamp") continue;
|
||||
configs_[k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kenaito
|
||||
+24765
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user