vcpe/srcs/libs/configure/config.c

547 lines
20 KiB
C
Raw Normal View History

2022-05-10 06:43:27 +00:00
//
// Created by xajhu on 2021/7/30 0030.
//
#include <libconfig.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>
#include <zlog.h>
#include <sds.h>
#include "uthash/uthash.h"
#include "config.h"
#include "misc.h"
#include "user_errno.h"
#include "crypto.h"
#include "hardware.h"
#define CFG_INT_VALUE(p) (p->value.longValue)
#define CFG_BOOL_VALUE(p) (p->value.longValue == FALSE ? FALSE : TRUE)
#define CFG_FLOAT_VALUE(p) (p->value.floatValue)
#define CFG_STRING_VALUE(p) (p->value.strValue)
#define ADD_CFG_ITEM(id, key, type, defVal, desc) add_new_cfg_item(id, key, type, defVal, #id, desc)
typedef union {
long long longValue;
char *strValue;
long double floatValue;
} CFG_VALUE, *PCFG_VALUE;
typedef struct {
CONFIG_ITEM_ID cfgId;
const char *pcfgKey;
CONFIG_VALUE_TYPE valType;
const char *defaultValue;
int isChanged;
const char *pMessage;
const char *pStrId;
CFG_VALUE value;
UT_hash_handle hh;
} CONFIG_ITEM, *PCONFIG_ITEM;
static config_t g_cfgContent;
static const char *g_cfgFilePath;
static const char *g_pCfgKey = NULL;
PCONFIG_ITEM g_pConfigItem = NULL;
static int cfg_is_upgrade(PCONFIG_ITEM pItem) {
if (pItem->isChanged) {
pItem->isChanged = FALSE;
return TRUE;
}
return FALSE;
}
#define ENC_HEAD ("AES@")
static const char *load_string_value(const char *pKeyName) {
const char *pCfgVal;
if (config_lookup_string(&g_cfgContent, pKeyName, &pCfgVal) != CONFIG_TRUE) {
dzlog_error("No {%s} setting in configuration file.\n", pKeyName);
return NULL;
}
if (strncmp(ENC_HEAD, pCfgVal, strlen(ENC_HEAD)) == 0) {
if (g_pCfgKey == NULL || strlen(g_pCfgKey) == 0) {
return NULL;
} else {
const char *pKey = get_config_key(g_pCfgKey);
int bufSize, outSize;
unsigned char *buf;
unsigned char *pBuf = base64_decode(&pCfgVal[strlen(ENC_HEAD)], (unsigned int *)&bufSize);
if (pBuf == NULL || bufSize <= 0) {
dzlog_error("{%s} setting [%s] maybe a encryption message, base64 decode error.\n", pKeyName, pCfgVal);
return NULL;
}
if (symmetric_decrypto(AES128_ECB_PKCS7PADDING_SHA1PRNG, pBuf, bufSize, &buf, &outSize, pKey) != ERR_OK) {
free((void *)pKey);
free(pBuf);
return NULL;
}
free(pBuf);
free((void *)pKey);
buf[outSize] = 0;
return (const char *)buf;
}
} else {
return strdup(pCfgVal);
}
}
static int load_boolean_value(const char *pKeyName, int defValue) {
int val;
if (config_lookup_bool(&g_cfgContent, pKeyName, &val) != CONFIG_TRUE) {
dzlog_error("No {%s} setting in configuration file.\n", pKeyName);
return defValue;
}
return val;
}
static long long load_integral_value(const char *pKeyName, long long defValue) {
long long val;
if (config_lookup_int64(&g_cfgContent, pKeyName, &val) != CONFIG_TRUE) {
dzlog_error("No {%s} setting in configuration file.\n", pKeyName);
return defValue;
}
return val;
}
static double load_float_value(const char *pKeyName, double defValue) {
double val;
if (config_lookup_float(&g_cfgContent, pKeyName, &val) != CONFIG_TRUE) {
dzlog_error("No {%s} setting in configuration file.\n", pKeyName);
return defValue;
}
return val;
}
static int setConfigItemValue(PCONFIG_ITEM pItem, const char *pValue) {
errno = 0;
if (pItem->valType == VALUE_TYPE_STRING) {
if (pItem->value.strValue != NULL) {
free(pItem->value.strValue);
}
pItem->value.strValue = strdup(pValue);
} else if (pItem->valType == VALUE_TYPE_INTEGRAL || pItem->valType == VALUE_TYPE_BOOL) {
char *pOver;
long long val = strtoll(pValue, &pOver, 10);
if ((pOver != NULL && strlen(pOver)) || errno != 0) {
return -ERR_STRING_TO_NUMBER;
}
pItem->value.longValue = val;
} else if (pItem->valType == VALUE_TYPE_FLOAT) {
char *pOver;
long double val = strtold(pValue, &pOver);
if ((pOver != NULL && strlen(pOver)) || errno != 0) {
return -ERR_STRING_TO_NUMBER;
}
pItem->value.floatValue = val;
} else {
return -ERR_UN_SUPPORT;
}
return ERR_OK;
}
static int add_new_cfg_item(CONFIG_ITEM_ID id, const char *pKey, CONFIG_VALUE_TYPE valType, const char *pDefVal,
const char *pStrId, const char *pDesc) {
PCONFIG_ITEM pItem;
int ret;
HASH_FIND_INT(g_pConfigItem, &id, pItem);
if (pItem != NULL) {
return -ERR_ITEM_EXISTS;
}
pItem = (PCONFIG_ITEM)malloc(sizeof(CONFIG_ITEM));
if (pItem == NULL) {
return -ERR_MALLOC_MEMORY;
}
memset(pItem, 0, sizeof(CONFIG_ITEM));
pItem->cfgId = id;
pItem->pcfgKey = pKey;
pItem->valType = valType;
pItem->defaultValue = pDefVal;
pItem->pMessage = pDesc;
pItem->pStrId = pStrId;
ret = setConfigItemValue(pItem, pItem->defaultValue);
if (ret != ERR_OK) {
free(pItem);
return ret;
}
HASH_ADD_INT(g_pConfigItem, cfgId, pItem);
return ERR_OK;
}
static PCFG_VALUE cfg_get_value(CONFIG_ITEM_ID id) {
PCONFIG_ITEM pItem;
HASH_FIND_INT(g_pConfigItem, &id, pItem);
if (pItem != NULL) {
return &pItem->value;
}
return NULL;
}
static void refreshCfgFileCb() {
PCONFIG_ITEM pItem, pTmp;
int cfgUpgrade = FALSE;
if (!config_read_file(&g_cfgContent, g_cfgFilePath)) {
dzlog_error("%s:%d - %s\n",
config_error_file(&g_cfgContent),
config_error_line(&g_cfgContent),
config_error_text(&g_cfgContent));
return;
}
HASH_ITER(hh, g_pConfigItem, pItem, pTmp) {
char *pStr;
long long iVal;
double fVal;
switch (pItem->valType) {
case VALUE_TYPE_STRING:
pStr = (char *)load_string_value(pItem->pcfgKey);
if (pStr) {
if (strcmp(pItem->value.strValue, pStr) != 0) {
if (pItem->value.strValue != NULL) {
free(pItem->value.strValue);
}
pItem->value.strValue = strdup(pStr);
pItem->isChanged = TRUE;
}
free(pStr);
}
break;
case VALUE_TYPE_BOOL:
iVal = load_boolean_value(pItem->pcfgKey, DEFAULT_INTEGRAL_ERR_VALUE);
if (iVal != DEFAULT_INTEGRAL_ERR_VALUE) {
if (pItem->value.longValue != iVal) {
pItem->value.longValue = iVal;
pItem->isChanged = TRUE;
}
}
break;
case VALUE_TYPE_INTEGRAL:
iVal = load_integral_value(pItem->pcfgKey, DEFAULT_INTEGRAL_ERR_VALUE);
if (iVal != DEFAULT_INTEGRAL_ERR_VALUE) {
if (pItem->value.longValue != iVal) {
pItem->value.longValue = iVal;
pItem->isChanged = TRUE;
}
}
break;
case VALUE_TYPE_FLOAT:
fVal = load_float_value(pItem->pcfgKey, DEFAULT_INTEGRAL_ERR_VALUE);
if (fVal != DEFAULT_INTEGRAL_ERR_VALUE) {
if (pItem->value.floatValue != fVal) {
pItem->value.floatValue = fVal;
pItem->isChanged = TRUE;
}
}
break;
default:
break;
}
if (pItem->isChanged) {
cfgUpgrade = TRUE;
}
}
if (cfgUpgrade) {
config_item_dump("Configuration upgrade");
}
}
const char *config_item_dump_fmt(const char *titleMessage) {
const char *pResp;
PCONFIG_ITEM pItem, pTmp;
sds tmp, tmp2;
sds s = sdsempty();
if (titleMessage && strlen(titleMessage) > 0) {
s = sdscatprintf(s, "%s:\n", titleMessage);
}
s = sdscat(s,
"--------------------------------------------------------------------------------"
"---------------------------------------------------\n");
s = sdscat(s,
"| id | Key Name | Configuration file key |"
" value |\n");
s = sdscat(s,
"--------------------------------------------------------------------------------"
"---------------------------------------------------\n");
HASH_ITER(hh, g_pConfigItem, pItem, pTmp) {
tmp2 = sdsempty();
tmp2 = sdscatprintf(tmp2, "%s%s", cfg_is_upgrade(pItem) ? "*" : " ", pItem->pStrId);
switch (pItem->valType) {
case VALUE_TYPE_BOOL:
s = sdscatprintf(s,
"|%4d | %-25s | %-45s | %-44s |\n",
pItem->cfgId,
tmp2,
pItem->pcfgKey,
CFG_BOOL_VALUE(pItem) ? "True" : "False");
break;
case VALUE_TYPE_INTEGRAL:
s = sdscatprintf(s,
"|%4d | %-25s | %-45s | %-44lld |\n",
pItem->cfgId,
tmp2,
pItem->pcfgKey,
CFG_INT_VALUE(pItem));
break;
case VALUE_TYPE_FLOAT:
s = sdscatprintf(s,
"|%4d | %-25s | %-45s | %-44Lf |\n",
pItem->cfgId,
tmp2,
pItem->pcfgKey,
CFG_FLOAT_VALUE(pItem));
break;
case VALUE_TYPE_STRING:
tmp = sdsempty();
tmp = sdscatprintf(tmp, "\"%s\"", CFG_STRING_VALUE(pItem));
s = sdscatprintf(s, "|%4d | %-25s | %-45s | %-44s |\n", pItem->cfgId, tmp2, pItem->pcfgKey, tmp);
sdsfree(tmp);
break;
default:
break;
}
sdsfree(tmp2);
}
s = sdscat(s,
"--------------------------------------------------------------------------------"
"---------------------------------------------------\n");
pResp = strdup(s);
sdsfree(s);
return pResp;
}
void config_item_dump(const char *titleMessage) {
const char *pMsg = config_item_dump_fmt(titleMessage);
dzlog_info("%s", pMsg);
free((char *)pMsg);
#if 0
PCONFIG_ITEM pItem, pTmp;
//int i, k = ARRAY_SIZE(g_sysConfigMap);
dzlog_info("================== %s ===================\n", titleMessage == NULL ? "" : titleMessage);
HASH_ITER(hh, g_pConfigItem, pItem, pTmp) {
switch (pItem->valType) {
case VALUE_TYPE_BOOL:
dzlog_info("%s%-25s: [%-45s] = %s\n",
cfg_is_upgrade(pItem) ? "*" : " ",
pItem->pStrId,
pItem->pcfgKey,
CFG_BOOL_VALUE(pItem) ? "True" : "False");
break;
case VALUE_TYPE_INTEGRAL:
dzlog_info("%s%-25s: [%-45s] = %lld\n",
cfg_is_upgrade(pItem) ? "*" : " ",
pItem->pStrId,
pItem->pcfgKey,
CFG_INT_VALUE(pItem));
break;
case VALUE_TYPE_FLOAT:
dzlog_info("%s%-25s: [%-45s] = %Lf\n",
cfg_is_upgrade(pItem) ? "*" : " ",
pItem->pStrId,
pItem->pcfgKey,
CFG_FLOAT_VALUE(pItem));
break;
case VALUE_TYPE_STRING:
dzlog_info("%s%-25s: [%-45s] = \"%s\"\n",
cfg_is_upgrade(pItem) ? "*" : " ",
pItem->pStrId,
pItem->pcfgKey,
CFG_STRING_VALUE(pItem));
break;
default:
break;
}
}
#endif
}
long double cfg_get_float_value(CONFIG_ITEM_ID id) {
PCFG_VALUE pVal = cfg_get_value(id);
if (pVal) {
return pVal->floatValue;
} else {
return DEFAULT_INTEGRAL_ERR_VALUE;
}
}
long long cfg_get_integral_value(CONFIG_ITEM_ID id) {
PCFG_VALUE pVal = cfg_get_value(id);
if (pVal) {
return pVal->longValue;
} else {
return DEFAULT_INTEGRAL_ERR_VALUE;
}
}
int cfg_get_bool_value(CONFIG_ITEM_ID id) {
PCFG_VALUE pVal = cfg_get_value(id);
if (pVal) {
return pVal->longValue == FALSE ? FALSE : TRUE;
} else {
return DEFAULT_INTEGRAL_ERR_VALUE;
}
}
const char *cfg_get_string_value(CONFIG_ITEM_ID id) {
PCFG_VALUE pVal = cfg_get_value(id);
if (pVal) {
return pVal->strValue;
} else {
return NULL;
}
}
// clang-format off
#define ADD_DEFAULT_CONFIGURATION_ITEMS() \
do { \
ADD_CFG_ITEM(CFG_DIRECTORY, "application.system.config_file_path", VALUE_TYPE_STRING, ".", "Configuration files location path"); \
ADD_CFG_ITEM(CFG_CURL_CA_PATH, "application.system.ssl_ca_file_path", VALUE_TYPE_STRING, "~/.ssh/ca.crt", "Libcurl access HTTPS CA File"); \
ADD_CFG_ITEM(CFG_BANNER_SHOW, "application.system.show_banner", VALUE_TYPE_BOOL, "1", "Enable/Disable show banner"); \
ADD_CFG_ITEM(CFG_HARDWARE_WATCH, "application.system.system_info_watch", VALUE_TYPE_BOOL, "1", "Monitor cpu, memory, disk, fan, temperature ..."); \
ADD_CFG_ITEM(CFG_HARDWARE_REFRESH, "application.system.system_info_refresh", VALUE_TYPE_INTEGRAL, "10", "Monitor hardware information upgrade frequency"); \
/* 系统监控设备相配置 */ \
ADD_CFG_ITEM(CFG_WATCH_CPU, "application.watch_params.cpu", VALUE_TYPE_BOOL, "1", "Monitor cpu information"); \
ADD_CFG_ITEM(CFG_WATCH_MEMORY, "application.watch_params.memory", VALUE_TYPE_BOOL, "1", "Monitor memory information"); \
ADD_CFG_ITEM(CFG_WATCH_DISK, "application.watch_params.disk", VALUE_TYPE_BOOL, "1", "Monitor disk partition information"); \
ADD_CFG_ITEM(CFG_WATCH_SENSOR, "application.watch_params.sensor", VALUE_TYPE_BOOL, "1", "Sensor information refresh frequency"); \
/* 系统监控设备刷频率 */ \
ADD_CFG_ITEM(CFG_CPU_REFRESH, "application.watch_params.cpu_refresh", VALUE_TYPE_INTEGRAL, "10", "CPU information refresh frequency"); \
ADD_CFG_ITEM(CFG_MEM_REFRESH, "application.watch_params.mem_refresh", VALUE_TYPE_INTEGRAL, "10", "Memory information refresh frequency"); \
ADD_CFG_ITEM(CFG_DISK_REFRESH, "application.watch_params.disk_refresh", VALUE_TYPE_INTEGRAL, "10", "Disk information refresh frequency"); \
ADD_CFG_ITEM(CFG_SENSOR_REFRESH, "application.watch_params.sensor_refresh", VALUE_TYPE_INTEGRAL, "10", "Sensor information refresh frequency"); \
/* 数据库相配置 */ \
/* Redis配置 */ \
ADD_CFG_ITEM(CFG_DB_REDIS_SERVER, "application.database.redis_server", VALUE_TYPE_STRING, "127.0.0.1", "Redis database server ip address"); \
ADD_CFG_ITEM(CFG_DB_REDIS_PORT, "application.database.redis_port", VALUE_TYPE_INTEGRAL, "6379", "Redis database server port"); \
ADD_CFG_ITEM(CFG_DB_REDIS_PASSWD, "application.database.redis_passwd", VALUE_TYPE_STRING, "", "Redis database server password"); \
/* MySQL配置 */ \
ADD_CFG_ITEM(CFG_DB_MYSQL_SERVER, "application.database.mysql_server", VALUE_TYPE_STRING, "127.0.0.1", "MySQL database server ip address"); \
ADD_CFG_ITEM(CFG_DB_MYSQL_PORT, "application.database.mysql_port", VALUE_TYPE_INTEGRAL, "3306", "MySQL database server port"); \
ADD_CFG_ITEM(CFG_DB_MYSQL_USER, "application.database.mysql_user", VALUE_TYPE_STRING, "", "MySQL database user name"); \
ADD_CFG_ITEM(CFG_DB_MYSQL_PASSWD, "application.database.mysql_passwd", VALUE_TYPE_STRING, "", "MySQL database server password"); \
ADD_CFG_ITEM(CFG_DB_MYSQL_DB_NAME, "application.database.mysql_database", VALUE_TYPE_STRING, ".main", "MySQL database used"); \
/* 消息队列相配置 */ \
/* ZeroMq配置 */ \
ADD_CFG_ITEM(CFG_MQ_SVR_PORT, "application.zero_mq.svr_port", VALUE_TYPE_INTEGRAL, "6378", "ZeroMQ server port"); \
} while (0)// clang-format on
int init_config_system(const char *pCfgFile, const char *pKey) {
if (!file_exists(pCfgFile)) {
dzlog_error("Configuration file [%s] not exists\n", pCfgFile);
return -ERR_FILE_NOT_EXISTS;
}
g_pCfgKey = strdup(pKey == NULL ? "" : pKey);
g_cfgFilePath = strdup(pCfgFile);
config_init(&g_cfgContent);
ADD_DEFAULT_CONFIGURATION_ITEMS();
// clang-format on
refreshCfgFileCb();
return ERR_OK;
}
const char *get_config_keygen() {
char buf[MAX_PATH];
CPU_INFO cpuInfo;
get_cpu_info(&cpuInfo);
memset(buf, 0, MAX_PATH);
sprintf(buf, "%d#%s", cpuInfo.nLogicCores, cpuInfo.cpuCoreDesc.cpuName);
return strdup(buf);
}
const char *get_config_key(const char *pKeygen) {
int outSize;
unsigned char *buf = NULL;
const char *strRet;
const char *pKey = get_config_keygen();
unsigned char *pBase64 = (unsigned char *)base64_decode(pKeygen, (unsigned int *)&outSize);
if (pBase64 == NULL) {
printf("Base64 decode error: %s\n", pKeygen);
return NULL;
}
if (symmetric_decrypto(DES3_CBC_PKCS7PADDING, pBase64, outSize, &buf, &outSize, pKey) != ERR_OK) {
free((void *)pKey);
free((void *)pBase64);
if (buf) {
free(buf);
}
return NULL;
} else {
buf[outSize] = 0;
strRet = strdup((const char *)buf);
}
free(buf);
free((void *)pKey);
free((void *)pBase64);
return strRet;
}