* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* MindIE is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "config_dynamic_handler.h"
#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <nlohmann/json.hpp>
#include <string>
#include <thread>
#include "common_util.h"
#include "param_checker.h"
namespace mindie_llm {
DynamicConfigHandler::~DynamicConfigHandler() { Stop(); }
DynamicConfigHandler& DynamicConfigHandler::GetInstance() {
static DynamicConfigHandler instance;
return instance;
}
void DynamicConfigHandler::Start() const {
std::thread t([]() {
while (GetInstance().isRunning) {
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
std::lock_guard<std::mutex> locker(GetInstance().vectorMutex);
for (auto& configTuple : GetInstance().callBackFunctions) {
if (GetInstance().isTriggered(configTuple.first)) {
configTuple.second();
}
}
}
});
t.detach();
}
void DynamicConfigHandler::Stop() const { GetInstance().isRunning = false; }
std::vector<std::string> DynamicConfigHandler::splitString(const std::string& s, const char delimiter) const {
std::vector<std::string> ans;
if (s.empty()) {
return ans;
}
for (std::size_t i = 0; i < s.length();) {
std::size_t pos = s.find(delimiter, i);
if (pos != std::string::npos) {
if (pos == i) {
i = pos + 1;
continue;
} else {
std::string strTemp = s.substr(i, pos - i);
ans.push_back(strTemp);
i = pos + 1;
}
} else {
std::string strTemp = s.substr(i, s.length() - i);
ans.push_back(strTemp);
break;
}
}
return ans;
}
std::string DynamicConfigHandler::getConfigFilePath() const {
auto miesInstallPath = GetMindieLlmHomePath();
if (!miesInstallPath.empty()) {
return miesInstallPath + "/conf/config.json";
}
return "../conf/config.json";
}
bool DynamicConfigHandler::CheckSystemConfig(const std::string& jsonPath, nlohmann::json& inputJsonData,
std::string paramType) const {
std::string homePath;
if (!GetHomePath(homePath).IsOk()) {
std::cout << "Failed to get home path." << std::endl;
return false;
}
std::string systemConfigPath = homePath + "/conf/config.json";
std::string baseDir = "/";
if (systemConfigPath.compare(jsonPath) == 0) {
baseDir = homePath;
}
return ParamChecker::ReadJsonFile(jsonPath, baseDir, inputJsonData, paramType);
}
bool DynamicConfigHandler::isTriggered(const std::string pathExpression) const {
try {
std::string configFilePath = getConfigFilePath();
nlohmann::json configJson;
CheckSystemConfig(configFilePath, configJson, "");
std::vector<std::string> pathVec = splitString(pathExpression);
for (std::string& path : pathVec) {
if (path == "EnableDynamicAdjustTimeoutConfig" && !configJson.contains(path)) {
return false;
} else {
configJson = configJson.at(path);
}
}
return static_cast<bool>(configJson);
} catch (nlohmann::json::parse_error& e) {
std::cout << "DynamicConfigHandler parse_error: " << e.what() << std::endl;
return false;
} catch (std::exception& e) {
std::cout << "DynamicConfigHandler exception: " << e.what() << std::endl;
return false;
}
return true;
}
}