initial commit
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
SpaceAfterCStyleCast: true
|
||||
PointerBindsToType: false
|
||||
DerivePointerBinding: false
|
||||
IncludeBlocks: Preserve
|
||||
@@ -0,0 +1,48 @@
|
||||
name: Prepare Build and Testing executable binary
|
||||
run-name: ${{ gitea.actor }}
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
Prepare-Build-Testing-With-Make:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- name: Building binary with make
|
||||
run: make -j$(nproc)
|
||||
# - name: Testing binary
|
||||
# run: make test
|
||||
|
||||
Prepare-Build-Testing-With-CMake:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: prepare-container
|
||||
run: |
|
||||
apt install -y cmake
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- name: Building binary with CMake
|
||||
run: |
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake .. && \
|
||||
make -j$(nproc)
|
||||
# - name: Testing binary
|
||||
# run: |
|
||||
# cp -v build/auth_service . && ./tests.sh
|
||||
|
||||
Prepare-Build-Testing-With-Meson:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: prepare-container
|
||||
run: |
|
||||
apt install -y meson
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- name: Building binary with meson
|
||||
run: |
|
||||
meson setup build && \
|
||||
ninja -C build
|
||||
# - name: Testing binary
|
||||
# run: |
|
||||
# cp -v build/auth_service . && ./tests.sh
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
*.o
|
||||
.vscode
|
||||
.cache
|
||||
.idea
|
||||
build
|
||||
builddir
|
||||
auth_service
|
||||
*.swp
|
||||
*.log
|
||||
.proxy.sh
|
||||
.no-proxy.sh
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required (VERSION 3.6)
|
||||
project(dns_service LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
include_directories(./src/lib/ ${SQLite3_INCLUDE_DIRS})
|
||||
|
||||
FILE(GLOB_RECURSE SOURCES src/*.c)
|
||||
|
||||
add_executable(
|
||||
dns_service
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(dns_service ssl crypto pthread)
|
||||
@@ -0,0 +1,24 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -g -std=gnu2x -DMG_TLS=MG_TLS_OPENSSL
|
||||
LDFLAGS =
|
||||
LIBS = -lpthread -lcrypto -lssl
|
||||
INCLUDES = -I./src/lib -I./src
|
||||
SRCS = $(wildcard src/*.c src/lib/*.c)
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
TARGET = dns_service
|
||||
BUILD_DIR=./build
|
||||
CROSS_COMPILE =
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CROSS_COMPILE)$(CC) $(LDFLAGS) $^ -o $@ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(TARGET) $(shell find . -type f -name '*.log')
|
||||
|
||||
test: $(TARGET)
|
||||
bash ./tests.sh
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"address": "0.0.0.0:8321",
|
||||
"tls_address": "0.0.0.0:8322",
|
||||
"web": "./web",
|
||||
"tls_enabled": true,
|
||||
"tls_cert": "/home/tola/certs/localhost/localhost.crt",
|
||||
"tls_key": "/home/tola/certs/localhost/localhost.key",
|
||||
"system_initialization": "rc",
|
||||
"dnsmasq_config": "/etc/dnsmasq.conf"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
project('dns_service', 'c', default_options: ['c_std=gnu2x'])
|
||||
include_dirs = include_directories('src', 'src/lib')
|
||||
deps = [dependency('openssl')]
|
||||
executable(
|
||||
'dns_service',
|
||||
'src/main.c',
|
||||
'src/lib/mongoose.c',
|
||||
'src/lib/cJSON.c',
|
||||
'src/lib/file.c',
|
||||
'src/lib/ConfigManager.c',
|
||||
'src/config.c',
|
||||
'src/get_settings.c',
|
||||
'src/decode_hosts.c',
|
||||
'src/decode_resolvs.c',
|
||||
'src/decode_dnsmasq_settings.c',
|
||||
'src/set_settings.c',
|
||||
'src/set_settings_file.c',
|
||||
'src/get_settings_file.c',
|
||||
'src/static.c',
|
||||
include_directories: include_dirs,
|
||||
dependencies: deps,
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
ConfigManager *config = nullptr;
|
||||
|
||||
void init_config(const char *filename) {
|
||||
config = cm_new_config_from_file(filename);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ConfigManager.h>
|
||||
|
||||
extern ConfigManager *config;
|
||||
|
||||
void init_config(const char *filename);
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "settings.h"
|
||||
|
||||
cJSON *decode_dnsmasq_settings(char *input, char *pair_delim, char *kv_delim) {
|
||||
if (!input || !pair_delim || !kv_delim) return NULL;
|
||||
|
||||
cJSON *result = cJSON_CreateObject();
|
||||
if (!result) return NULL;
|
||||
|
||||
char *input_copy = strdup(input);
|
||||
if (!input_copy) {
|
||||
cJSON_Delete(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *save_ptr;
|
||||
char *pair = strtok_r(input_copy, pair_delim, &save_ptr);
|
||||
|
||||
while (pair) {
|
||||
// Пропускаем пробелы в начале
|
||||
char *trimmed_pair = pair;
|
||||
while (isspace(*trimmed_pair)) trimmed_pair++;
|
||||
|
||||
// Обрезаем пробелы в конце
|
||||
char *end = trimmed_pair + strlen(trimmed_pair) - 1;
|
||||
while (end > trimmed_pair && isspace(*end)) {
|
||||
*end = '\0';
|
||||
end--;
|
||||
}
|
||||
|
||||
if (strlen(trimmed_pair) > 0) {
|
||||
char *delim_pos = strstr(trimmed_pair, kv_delim);
|
||||
if (delim_pos) {
|
||||
*delim_pos = '\0';
|
||||
char *key = trimmed_pair;
|
||||
char *value = delim_pos + strlen(kv_delim);
|
||||
|
||||
// Обрезаем пробелы вокруг ключа
|
||||
while (isspace(*key)) key++;
|
||||
end = key + strlen(key) - 1;
|
||||
while (end > key && isspace(*end)) {
|
||||
*end = '\0';
|
||||
end--;
|
||||
}
|
||||
|
||||
// Обрезаем пробелы вокруг значения
|
||||
while (isspace(*value)) value++;
|
||||
end = value + strlen(value) - 1;
|
||||
while (end > value && isspace(*end)) {
|
||||
*end = '\0';
|
||||
end--;
|
||||
}
|
||||
|
||||
if (strlen(key) > 0) {
|
||||
cJSON_AddStringToObject(result, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
pair = strtok_r(NULL, pair_delim, &save_ptr);
|
||||
}
|
||||
|
||||
free(input_copy);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "settings.h"
|
||||
|
||||
cJSON *decode_hosts(const char *input) {
|
||||
if (!input) return NULL;
|
||||
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
if (!root) return NULL;
|
||||
|
||||
char *input_copy = strdup(input);
|
||||
if (!input_copy) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *save_ptr_line;
|
||||
char *line = strtok_r(input_copy, "\n", &save_ptr_line);
|
||||
|
||||
while (line) {
|
||||
// Пропускаем пустые строки и комментарии
|
||||
if (strlen(line) == 0 || line[0] == '#') {
|
||||
line = strtok_r(NULL, "\n", &save_ptr_line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Разбиваем строку на поля
|
||||
char *fields[1024];
|
||||
int field_count = 0;
|
||||
|
||||
char *save_ptr_field;
|
||||
char *token = strtok_r(line, " \t", &save_ptr_field);
|
||||
|
||||
while (token && field_count < 1024) {
|
||||
fields[field_count++] = token;
|
||||
token = strtok_r(NULL, " \t", &save_ptr_field);
|
||||
}
|
||||
|
||||
if (field_count > 0) {
|
||||
char *key = fields[0];
|
||||
|
||||
if (field_count == 1) {
|
||||
cJSON_AddItemToObject(root, key, cJSON_CreateArray());
|
||||
} else if (field_count == 2) {
|
||||
cJSON_AddStringToObject(root, key, fields[1]);
|
||||
} else {
|
||||
cJSON *arr = cJSON_CreateArray();
|
||||
for (int i = 1; i < field_count; i++) {
|
||||
cJSON_AddItemToArray(arr, cJSON_CreateString(fields[i]));
|
||||
}
|
||||
cJSON_AddItemToObject(root, key, arr);
|
||||
}
|
||||
}
|
||||
|
||||
line = strtok_r(NULL, "\n", &save_ptr_line);
|
||||
}
|
||||
|
||||
free(input_copy);
|
||||
return root;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "settings.h"
|
||||
|
||||
char **decode_resolvs(char *input, int *count) {
|
||||
if (!input) {
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *input_copy = strdup(input);
|
||||
if (!input_copy) {
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **result = NULL;
|
||||
int result_count = 0;
|
||||
const char *prefix = "nameserver ";
|
||||
const int prefix_len = strlen(prefix);
|
||||
|
||||
char *save_ptr;
|
||||
char *line = strtok_r(input_copy, "\n", &save_ptr);
|
||||
|
||||
while (line) {
|
||||
// Пропускаем пробелы в начале строки
|
||||
char *start = line;
|
||||
while (isspace(*start)) start++;
|
||||
|
||||
// Обрезаем пробелы в конце строки
|
||||
char *end = start + strlen(start) - 1;
|
||||
while (end > start && isspace(*end)) {
|
||||
*end = '\0';
|
||||
end--;
|
||||
}
|
||||
|
||||
if (strncmp(start, prefix, prefix_len) == 0) {
|
||||
char *value = start + prefix_len;
|
||||
while (isspace(*value)) value++;
|
||||
|
||||
if (*value != '\0') {
|
||||
char **new_result =
|
||||
realloc(result, (result_count + 1) * sizeof(char *));
|
||||
if (!new_result) {
|
||||
// Освобождаем уже выделенную память в случае ошибки
|
||||
for (int i = 0; i < result_count; i++) {
|
||||
free(result[i]);
|
||||
}
|
||||
free(result);
|
||||
free(input_copy);
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = new_result;
|
||||
result[result_count] = strdup(value);
|
||||
if (!result[result_count]) {
|
||||
// Освобождаем уже выделенную память в случае ошибки
|
||||
for (int i = 0; i < result_count; i++) {
|
||||
free(result[i]);
|
||||
}
|
||||
free(result);
|
||||
free(input_copy);
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
result_count++;
|
||||
}
|
||||
}
|
||||
line = strtok_r(NULL, "\n", &save_ptr);
|
||||
}
|
||||
|
||||
free(input_copy);
|
||||
*count = result_count;
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <file.h>
|
||||
#include "config.h"
|
||||
#include "settings.h"
|
||||
|
||||
void get_settings(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
cJSON *response = cJSON_CreateObject();
|
||||
if (!response) {
|
||||
mg_http_reply(c, 500, HTTP_HEADERS, "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("can't create response object"));
|
||||
return;
|
||||
}
|
||||
char *filename = cm_get_parameter_as_string(config, "dnsmasq_config");
|
||||
if (!filename) {
|
||||
mg_http_reply(c, 500, HTTP_HEADERS, "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("can't read config file"));
|
||||
cJSON_Delete(response);
|
||||
return;
|
||||
}
|
||||
char *filedata = read_file(filename);
|
||||
if (!filedata) {
|
||||
mg_http_reply(c, 500, HTTP_HEADERS, "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("can't read config file"));
|
||||
free(filename);
|
||||
cJSON_Delete(response);
|
||||
return;
|
||||
}
|
||||
cJSON *jsonfiledata = decode_dnsmasq_settings(filedata, "\n", "=");
|
||||
cJSON *cachesize = cJSON_GetObjectItem(jsonfiledata, "cache-size");
|
||||
if (!cachesize) {
|
||||
mg_http_reply(c, 500, HTTP_HEADERS, "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("can't read config file"));
|
||||
free(filename);
|
||||
free(filedata);
|
||||
cJSON_Delete(jsonfiledata);
|
||||
cJSON_Delete(response);
|
||||
return;
|
||||
}
|
||||
cJSON_AddNumberToObject(response, "cache_size", atoi(cachesize->valuestring));
|
||||
cJSON *resolv_filename = cJSON_GetObjectItem(jsonfiledata, "resolv-file");
|
||||
|
||||
char *resolvfiledata = NULL;
|
||||
char **resolvs = NULL;
|
||||
int resolvs_count = 0;
|
||||
char *hostsfiledata = NULL;
|
||||
cJSON *decoded_hosts = NULL;
|
||||
|
||||
if (resolv_filename) {
|
||||
resolvfiledata = read_file(resolv_filename->valuestring);
|
||||
if (resolvfiledata) {
|
||||
resolvs = decode_resolvs(resolvfiledata, &resolvs_count);
|
||||
}
|
||||
|
||||
if (resolvs_count > 0) {
|
||||
cJSON *arr = cJSON_CreateArray();
|
||||
for (int i = 0; i < resolvs_count; i++) {
|
||||
cJSON_AddItemToArray(arr, cJSON_CreateString(resolvs[i]));
|
||||
}
|
||||
cJSON_AddItemToObject(response, "resolv", arr);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON *addn_hosts = cJSON_GetObjectItem(jsonfiledata, "addn-hosts");
|
||||
if (addn_hosts) {
|
||||
hostsfiledata = read_file(addn_hosts->valuestring);
|
||||
if (hostsfiledata) {
|
||||
decoded_hosts = decode_hosts(hostsfiledata);
|
||||
if (decoded_hosts) {
|
||||
cJSON_AddItemToObject(response, "hosts", decoded_hosts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *response_str = cJSON_PrintUnformatted(response);
|
||||
mg_http_reply(c, 200, HTTP_HEADERS, "%s", response_str);
|
||||
|
||||
free(response_str);
|
||||
free(filename);
|
||||
free(filedata);
|
||||
cJSON_Delete(jsonfiledata);
|
||||
cJSON_Delete(response);
|
||||
free(resolvfiledata);
|
||||
|
||||
if (resolvs) {
|
||||
for (int i = 0; i < resolvs_count; i++) {
|
||||
free(resolvs[i]);
|
||||
}
|
||||
free(resolvs);
|
||||
}
|
||||
|
||||
free(hostsfiledata);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "ConfigManager.h"
|
||||
#include "settings_file.h"
|
||||
#include "config.h"
|
||||
#include <file.h>
|
||||
|
||||
void get_settings_file(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
char *filename = cm_get_parameter_as_string(config, "dnsmasq_config");
|
||||
if (!filename) {
|
||||
mg_http_reply(c, 500, HTTP_HEADERS, "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("can't read config file"));
|
||||
return;
|
||||
}
|
||||
char *data = read_file(filename);
|
||||
mg_http_reply(c, 200, "Content-Type: text/plain\r\nAccess-Control-Allow-Origin: *\r\n", data);
|
||||
free(data);
|
||||
free(filename);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#include "ConfigManager.h"
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "file.h"
|
||||
|
||||
typedef struct ConfigManager {
|
||||
cJSON *config;
|
||||
pthread_mutex_t config_file_mutex;
|
||||
char *config_file_name;
|
||||
} ConfigManager;
|
||||
|
||||
ConfigManager *cm_new_config() {
|
||||
ConfigManager *newcm = malloc(sizeof(ConfigManager));
|
||||
newcm->config_file_name = nullptr;
|
||||
newcm->config = nullptr;
|
||||
return newcm;
|
||||
}
|
||||
|
||||
ConfigManager *cm_new_config_from_file(const char *filename) {
|
||||
ConfigManager *newcm = malloc(sizeof(ConfigManager));
|
||||
newcm->config_file_name = strdup(filename);
|
||||
pthread_mutex_lock(&(newcm->config_file_mutex));
|
||||
char *config_file_content = read_file(newcm->config_file_name);
|
||||
newcm->config = cJSON_Parse(config_file_content);
|
||||
pthread_mutex_unlock(&(newcm->config_file_mutex));
|
||||
return newcm;
|
||||
}
|
||||
|
||||
ConfigManager *cm_new_config_from_object(cJSON *config) {
|
||||
ConfigManager *newcm = malloc(sizeof(ConfigManager));
|
||||
newcm->config = config;
|
||||
newcm->config_file_name = nullptr;
|
||||
return newcm;
|
||||
}
|
||||
|
||||
void cm_set_config_from_file(ConfigManager *cm, const char *filename) {
|
||||
cm->config_file_name = strdup(filename);
|
||||
pthread_mutex_lock(&(cm->config_file_mutex));
|
||||
char *config_file_content = read_file(cm->config_file_name);
|
||||
cm->config = cJSON_Parse(config_file_content);
|
||||
pthread_mutex_unlock(&(cm->config_file_mutex));
|
||||
}
|
||||
|
||||
void cm_set_config_from_object(ConfigManager *cm, cJSON *config) {
|
||||
cm->config = config;
|
||||
}
|
||||
|
||||
void cm_delete_config(ConfigManager *cm) {
|
||||
if (!cm) {
|
||||
return;
|
||||
}
|
||||
if (cm->config) {
|
||||
cJSON_Delete(cm->config);
|
||||
}
|
||||
if (cm->config_file_name) {
|
||||
free(cm->config_file_name);
|
||||
}
|
||||
free(cm);
|
||||
}
|
||||
|
||||
void cm_print_config(const ConfigManager *cm) {
|
||||
printf("Config: %s\n", cJSON_Print(cm->config));
|
||||
}
|
||||
|
||||
char *cm_get_config_filename(ConfigManager *cm) {
|
||||
return strdup(cm->config_file_name);
|
||||
}
|
||||
|
||||
cJSON *cm_get_config(ConfigManager *cm) {
|
||||
return cJSON_Duplicate(cm->config, (cJSON_bool) true);
|
||||
}
|
||||
|
||||
char *cm_get_parameter_as_string(ConfigManager *cm, const char *param_name) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, param_name);
|
||||
if (!param) return nullptr;
|
||||
char *param_value = strdup(param->valuestring);
|
||||
return param_value;
|
||||
}
|
||||
|
||||
int cm_get_parameter_as_int(ConfigManager *cm, const char *param_name) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, param_name);
|
||||
return param->valueint;
|
||||
}
|
||||
double cm_get_parameter_as_double(ConfigManager *cm, const char *param_name) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, param_name);
|
||||
return param->valuedouble;
|
||||
}
|
||||
float cm_get_parameter_as_float(ConfigManager *cm, const char *param_name) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, param_name);
|
||||
return param->valuedouble;
|
||||
}
|
||||
bool cm_get_parameter_as_bool(ConfigManager *cm, const char *param_name) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, param_name);
|
||||
if (!param) return false;
|
||||
return param->valueint;
|
||||
}
|
||||
|
||||
void cm_set_string_parameter(ConfigManager *cm, const char *name,
|
||||
const char *value) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, name);
|
||||
if (!param) {
|
||||
cJSON_AddStringToObject(cm->config, name, value);
|
||||
return;
|
||||
}
|
||||
cJSON_SetValuestring(param, value);
|
||||
}
|
||||
void cm_set_int_parameter(ConfigManager *cm, const char *name,
|
||||
const int value) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, name);
|
||||
if (!param) {
|
||||
cJSON_AddNumberToObject(cm->config, name, value);
|
||||
return;
|
||||
}
|
||||
cJSON_SetIntValue(param, value);
|
||||
}
|
||||
void cm_set_double_parameter(ConfigManager *cm, const char *name,
|
||||
const double value) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, name);
|
||||
if (!param) {
|
||||
cJSON_AddNumberToObject(cm->config, name, value);
|
||||
return;
|
||||
}
|
||||
cJSON_SetNumberValue(param, value);
|
||||
}
|
||||
void cm_set_float_parameter(ConfigManager *cm, const char *name,
|
||||
const float value) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, name);
|
||||
if (!param) {
|
||||
cJSON_AddNumberToObject(cm->config, name, value);
|
||||
return;
|
||||
}
|
||||
cJSON_SetNumberValue(param, value);
|
||||
}
|
||||
void cm_set_bool_parameter(ConfigManager *cm, const char *name,
|
||||
const bool value) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, name);
|
||||
if (!param) {
|
||||
cJSON_AddBoolToObject(cm->config, name, value);
|
||||
return;
|
||||
}
|
||||
cJSON_SetBoolValue(param, value);
|
||||
}
|
||||
void cm_set_null_parameter(ConfigManager *cm, const char *name) {
|
||||
cJSON *param = cJSON_GetObjectItem(cm->config, name);
|
||||
if (!param) {
|
||||
cJSON_AddNullToObject(cm->config, name);
|
||||
return;
|
||||
}
|
||||
cJSON_ReplaceItemInObject(cm->config, name, cJSON_CreateNull());
|
||||
}
|
||||
|
||||
void cm_save_config(ConfigManager *cm) {
|
||||
pthread_mutex_lock(&(cm->config_file_mutex));
|
||||
FILE *configfile = fopen(cm->config_file_name, "w+");
|
||||
char *configvalue = cJSON_Print(cm->config);
|
||||
fprintf(configfile, "%s", configvalue);
|
||||
fclose(configfile);
|
||||
free(configvalue);
|
||||
pthread_mutex_unlock(&(cm->config_file_mutex));
|
||||
}
|
||||
void cm_save_config_to_file(ConfigManager *cm, const char *filename) {
|
||||
pthread_mutex_lock(&(cm->config_file_mutex));
|
||||
FILE *configfile = fopen(filename, "w+");
|
||||
char *configvalue = cJSON_Print(cm->config);
|
||||
fprintf(configfile, "%s", configvalue);
|
||||
fclose(configfile);
|
||||
free(configvalue);
|
||||
pthread_mutex_unlock(&(cm->config_file_mutex));
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <cJSON.h>
|
||||
|
||||
typedef struct ConfigManager ConfigManager;
|
||||
|
||||
ConfigManager *cm_new_config();
|
||||
ConfigManager *cm_new_config_from_file(const char *filename);
|
||||
ConfigManager *cm_new_config_from_object(cJSON *config);
|
||||
|
||||
void cm_set_config_from_file(ConfigManager *cm, const char *filename);
|
||||
void cm_set_config_from_object(ConfigManager *cm, cJSON *config);
|
||||
|
||||
void cm_set_string_parameter(ConfigManager *cm, const char *name,
|
||||
const char *value);
|
||||
void cm_set_int_parameter(ConfigManager *cm, const char *name, const int value);
|
||||
void cm_set_double_parameter(ConfigManager *cm, const char *name,
|
||||
const double value);
|
||||
void cm_set_float_parameter(ConfigManager *cm, const char *name,
|
||||
const float value);
|
||||
void cm_set_bool_parameter(ConfigManager *cm, const char *name,
|
||||
const bool value);
|
||||
void cm_set_null_parameter(ConfigManager *cm, const char *name);
|
||||
|
||||
void cm_print_config(const ConfigManager *cm);
|
||||
|
||||
void cm_delete_config(ConfigManager *cm);
|
||||
|
||||
char *cm_get_config_filename(ConfigManager *cm);
|
||||
cJSON *cm_get_config(ConfigManager *cm);
|
||||
|
||||
char *cm_get_parameter_as_string(ConfigManager *cm, const char *param_name);
|
||||
int cm_get_parameter_as_int(ConfigManager *cm, const char *param_name);
|
||||
double cm_get_parameter_as_double(ConfigManager *cm, const char *param_name);
|
||||
float cm_get_parameter_as_float(ConfigManager *cm, const char *param_name);
|
||||
bool cm_get_parameter_as_bool(ConfigManager *cm, const char *param_name);
|
||||
|
||||
void cm_save_config(ConfigManager *cm);
|
||||
void cm_save_config_to_file(ConfigManager *cm, const char *filename);
|
||||
+3191
File diff suppressed because it is too large
Load Diff
+306
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_CIRCULAR_LIMIT
|
||||
#define CJSON_CIRCULAR_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
#ifndef C_COLORS_H
|
||||
#define C_COLORS_H
|
||||
|
||||
// reset
|
||||
#define RESET "\033[0m"
|
||||
|
||||
// regular colrs
|
||||
#define GREEN "\033[0;32m" // GREEN
|
||||
#define BLUE "\033[0;34m" // BLUE
|
||||
#define YELLOW "\033[1;33m" // YELLOW
|
||||
#define RED "\033[0;31m" // RED
|
||||
#define BLACK "\033[0;30m" // BLACK
|
||||
#define PURPLE "\033[0;35m" // PURPLE
|
||||
#define CYAN "\033[0;36m" // CYAN
|
||||
#define WHITE "\033[0;37m" // WHITE
|
||||
|
||||
// bold
|
||||
#define BBLACK "\033[1;30m" // BLACK
|
||||
#define BRED "\033[1;31m" // RED
|
||||
#define BGREEN "\033[1;32m" // GREEN
|
||||
#define BYELLOW "\033[1;33m" // YELLOW
|
||||
#define BBLUE "\033[1;34m" // BLUE
|
||||
#define BPURPLE "\033[1;35m" // PURPLE
|
||||
#define BCYAN "\033[1;36m" // CYAN
|
||||
#define BWHITE "\033[1;37m" // WHITE
|
||||
|
||||
// Underline
|
||||
#define UBLACK "\033[4;30m" // BLACK
|
||||
#define URED "\033[4;31m" // RED
|
||||
#define UGREEN "\033[4;32m" // GREEN
|
||||
#define UYELLOW "\033[4;33m" // YELLOW
|
||||
#define UBLUE "\033[4;34m" // BLUE
|
||||
#define UPURPLE "\033[4;35m" // PURPLE
|
||||
#define UCYAN "\033[4;36m" // CYAN
|
||||
#define UWHITE "\033[4;37m" // WHITE
|
||||
|
||||
// Background
|
||||
#define ON_BLACK "\033[40m" // BLACK
|
||||
#define ON_RED "\033[41m" // RED
|
||||
#define ON_GREEN "\033[42m" // GREEN
|
||||
#define ON_YELLOW "\033[43m" // YELLOW
|
||||
#define ON_BLUE "\033[44m" // BLUE
|
||||
#define ON_PURPLE "\033[45m" // PURPLE
|
||||
#define ON_CYAN "\033[46m" // CYAN
|
||||
#define ON_WHITE "\033[47m" // WHITE
|
||||
|
||||
// High Intensity
|
||||
#define IBLACK "\033[0;90m" // BLACK
|
||||
#define IRED "\033[0;91m" // RED
|
||||
#define IGREEN "\033[0;92m" // GREEN
|
||||
#define IYELLOW "\033[0;93m" // YELLOW
|
||||
#define IBLUE "\033[0;94m" // BLUE
|
||||
#define IPURPLE "\033[0;95m" // PURPLE
|
||||
#define ICYAN "\033[0;96m" // CYAN
|
||||
#define IWHITE "\033[0;97m" // WHITE
|
||||
|
||||
// Bold High Intensity
|
||||
#define BIBLACK "\033[1;90m" // BLACK
|
||||
#define BIRED "\033[1;91m" // RED
|
||||
#define BIGREEN "\033[1;92m" // GREEN
|
||||
#define BIYELLOW "\033[1;93m" // YELLOW
|
||||
#define BIBLUE "\033[1;94m" // BLUE
|
||||
#define BIPURPLE "\033[1;95m" // PURPLE
|
||||
#define BICYAN "\033[1;96m" // CYAN
|
||||
#define BIWHITE "\033[1;97m" // WHITE
|
||||
|
||||
// High Intensity backgrounds
|
||||
#define ON_IBLACK "\033[0;100m" // BLACK
|
||||
#define ON_IRED "\033[0;101m" // RED
|
||||
#define ON_IGREEN "\033[0;102m" // GREEN
|
||||
#define ON_IYELLOW "\033[0;103m" // YELLOW
|
||||
#define ON_IBLUE "\033[0;104m" // BLUE
|
||||
#define ON_IPURPLE "\033[0;105m" // PURPLE
|
||||
#define ON_ICYAN "\033[0;106m" // CYAN
|
||||
#define ON_IWHITE "\033[0;107m" // WHITE
|
||||
|
||||
#endif // C_COLORS_H
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "file.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *read_file(const char *path) {
|
||||
FILE *fp = fopen(path, "rb");
|
||||
if (fp == NULL) {
|
||||
printf("%s\n", path);
|
||||
perror("Error opening file");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long file_size = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
char *buffer = (char *)malloc(file_size + 1);
|
||||
if (!buffer) {
|
||||
perror("Error allocating memory");
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t bytes_read = fread(buffer, 1, file_size, fp);
|
||||
if (bytes_read != file_size) {
|
||||
perror("Error reading file");
|
||||
free(buffer);
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffer[file_size] = '\0';
|
||||
fclose(fp);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *write_file(const char *path, const char *data) {
|
||||
FILE *fp = fopen(path, "w");
|
||||
if (fp == NULL) {
|
||||
printf("%s\n", path);
|
||||
perror("Error opening file");
|
||||
return nullptr;
|
||||
}
|
||||
printf("%s\n%s\n", data, path);
|
||||
if (fprintf(fp, "%s", data) < 0) {
|
||||
perror("Error write file");
|
||||
return nullptr;
|
||||
}
|
||||
fclose(fp);
|
||||
char *ret = strdup(data);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
char *read_file(const char *path);
|
||||
char *write_file(const char *path, const char *data);
|
||||
+25471
File diff suppressed because it is too large
Load Diff
+3781
File diff suppressed because it is too large
Load Diff
+81
@@ -0,0 +1,81 @@
|
||||
#include <ConfigManager.h>
|
||||
#include <colors.h>
|
||||
#include <file.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "route.h"
|
||||
#include "static.h"
|
||||
#include "settings_file.h"
|
||||
#include "settings.h"
|
||||
|
||||
static const struct route routes[] = {
|
||||
{"GET", "/api/settings", get_settings},
|
||||
{"POST", "/api/settings", set_settings},
|
||||
{"GET", "/api/settings/file", get_settings_file},
|
||||
{"POST", "/api/settings/file", set_settings_file},
|
||||
{"GET", "/#", root_handler},
|
||||
{nullptr, nullptr, nullptr}
|
||||
};
|
||||
|
||||
void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_ERROR) {
|
||||
MG_LOG(MG_LL_ERROR, ("Ошибка соединения: %s", (char *) ev_data));
|
||||
}
|
||||
const bool tls_enabled = cm_get_parameter_as_bool(config, "tls_enabled");
|
||||
if (tls_enabled) {
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) {
|
||||
struct mg_tls_opts opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.cert =
|
||||
mg_str(read_file(cm_get_parameter_as_string(config, "tls_cert")));
|
||||
opts.key =
|
||||
mg_str(read_file(cm_get_parameter_as_string(config, "tls_key")));
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
}
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
const auto hm = (struct mg_http_message *) ev_data;
|
||||
bool route_found = false;
|
||||
|
||||
for (int i = 0; routes[i].path != nullptr; i++) {
|
||||
if (mg_match(hm->uri, mg_str(routes[i].path), nullptr) &&
|
||||
mg_match(hm->method, mg_str(routes[i].method), nullptr)) {
|
||||
mg_log("%s%.*s %s%.*s%s", GREEN, hm->uri.len, hm->uri.buf, BWHITE,
|
||||
hm->method.len, hm->method.buf, RESET);
|
||||
routes[i].handler(c, hm);
|
||||
route_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!route_found) {
|
||||
mg_http_reply(c, 404, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("URI not found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
init_config("config.json");
|
||||
struct mg_mgr mgr;
|
||||
mg_log_set(MG_LL_DEBUG);
|
||||
mg_mgr_init(&mgr);
|
||||
const char *address = cm_get_parameter_as_string(config, "address");
|
||||
char http_address[64];
|
||||
snprintf(http_address, sizeof(http_address), "http://%s", address);
|
||||
address ? mg_http_listen(&mgr, http_address, ev_handler, nullptr)
|
||||
: mg_http_listen(&mgr, "http://0.0.0.0:8321", ev_handler, nullptr);
|
||||
if (cm_get_parameter_as_bool(config, "tls_enabled")) {
|
||||
const char *tls_address = cm_get_parameter_as_string(config, "tls_address");
|
||||
char https_address[64];
|
||||
snprintf(https_address, sizeof(https_address), "https://%s", tls_address);
|
||||
tls_address
|
||||
? mg_http_listen(&mgr, https_address, ev_handler, nullptr)
|
||||
: mg_http_listen(&mgr, "https://0.0.0.0:8322", ev_handler, nullptr);
|
||||
}
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 1000);
|
||||
}
|
||||
mg_mgr_free(&mgr);
|
||||
return 0;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <mongoose.h>
|
||||
|
||||
typedef void (*route_handler_t)(struct mg_connection *c,
|
||||
struct mg_http_message *hm);
|
||||
|
||||
struct route {
|
||||
char *method;
|
||||
char *path;
|
||||
route_handler_t handler;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "settings.h"
|
||||
|
||||
void set_settings(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "settings_file.h"
|
||||
#include <file.h>
|
||||
#include "config.h"
|
||||
|
||||
void set_settings_file(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
char *filename = cm_get_parameter_as_string(config, "dnsmasq_config");
|
||||
if (!filename) {
|
||||
mg_http_reply(c, 500, HTTP_HEADERS, "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("can't read config file"));
|
||||
return;
|
||||
}
|
||||
char *res = write_file(cm_get_parameter_as_string(config, "dnsmasq_config"), hm->body.buf);
|
||||
if (!res) {
|
||||
mg_http_reply(c, 500, HTTP_HEADERS, "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("can't write file"));
|
||||
return;
|
||||
}
|
||||
mg_http_reply(c, 200, "Content-Type: text/plain\r\nAccess-Control-Allow-Origin: *\r\n", res);
|
||||
free(filename);
|
||||
free(res);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <mongoose.h>
|
||||
#include <cJSON.h>
|
||||
|
||||
#define HTTP_HEADERS \
|
||||
"Content-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\n"
|
||||
|
||||
void get_settings(struct mg_connection *c, struct mg_http_message *hm);
|
||||
void set_settings(struct mg_connection *c, struct mg_http_message *hm);
|
||||
cJSON *decode_dnsmasq_settings(char *input, char *pair_delim, char *kv_delim);
|
||||
char **decode_resolvs(char *input, int *count);
|
||||
cJSON *decode_hosts(const char *input);
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <mongoose.h>
|
||||
|
||||
#define HTTP_HEADERS \
|
||||
"Content-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\n"
|
||||
|
||||
void get_settings_file(struct mg_connection *c, struct mg_http_message *hm);
|
||||
void set_settings_file(struct mg_connection *c, struct mg_http_message *hm);
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "static.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void root_handler(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
struct mg_http_serve_opts opts = {
|
||||
.root_dir = cm_get_parameter_as_string(config, "web")};
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <mongoose.h>
|
||||
|
||||
void root_handler(struct mg_connection *c, struct mg_http_message *hm);
|
||||
Vendored
+6
File diff suppressed because one or more lines are too long
@@ -0,0 +1,70 @@
|
||||
.checkbox-wrapper-2 {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC {
|
||||
appearance: none;
|
||||
background-color: #dfe1e4;
|
||||
border-radius: 72px;
|
||||
border-style: none;
|
||||
flex-shrink: 0;
|
||||
height: 20px;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
width: 30px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC::before {
|
||||
bottom: -6px;
|
||||
content: "";
|
||||
left: -6px;
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: -6px;
|
||||
transition: 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC,
|
||||
.checkbox-wrapper-2 .ikxBAC::after {
|
||||
transition: 300ms;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC::after {
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
content: "";
|
||||
height: 14px;
|
||||
left: 3px;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
width: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 input[type="checkbox"] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC:hover {
|
||||
background-color: #c9cbcd;
|
||||
transition-duration: 0s;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC:checked {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC:checked::after {
|
||||
background-color: #fff;
|
||||
left: 13px;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 :focus:not(.focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.checkbox-wrapper-2 .ikxBAC:checked:hover {
|
||||
background-color: hsl(from green h s 20%);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
* {
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
transform: scale(0);
|
||||
height: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#save-settings-button {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 10px;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width"/>
|
||||
<link rel="stylesheet" href="css/index.css" />
|
||||
<link rel="stylesheet" href="css/checkbox.css" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<title>Dns Service</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<a href="/" class="navbar-brand">Dns Service</a>
|
||||
<p style="margin-bottom: 0;">Dark theme</p>
|
||||
<div class="checkbox-wrapper-2"><input type="checkbox" class="sc-gJwTLC ikxBAC" id="dark_theme"/></div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="settings-section d-grid gap-2 justify-content-center p-3">
|
||||
<div class="card">
|
||||
<div class="card-header"><h3 class="card-title">Upstream Dns Servers</h3></div>
|
||||
<div class="card-body">
|
||||
<table id="upstream-dns-servers-table" class="table">
|
||||
<thead><tr><th>Upstream Dns Servers</th></tr></thead>
|
||||
<tbody id="upstream-dns-servers-table-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
style="width: 100%"
|
||||
id="add_dns_server_button"
|
||||
>Add</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header"><h3 class="card-title">Local Domains</h3></div>
|
||||
<div class="card-body">
|
||||
<table class="local-domains-table table">
|
||||
<thead><tr><th>IP</th><th>Domain</th><th>Delete</th></tr></thead>
|
||||
<tbody id="local-domains-table-body">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
style="width: 100%"
|
||||
id="add_local_domain_button"
|
||||
>Add</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header d-flex align-items-center gap-3 justify-content-between">
|
||||
<h3>DHCP</h3>
|
||||
<div class="checkbox-wrapper-2"><input type="checkbox" class="sc-gJwTLC ikxBAC" id="dhcp_enabled"/></div>
|
||||
</div>
|
||||
<div class="card-body hidden" id="dhcp_rect_body">
|
||||
<h3 class="card-title">DHCP range</h3>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<input placeholder="192.168.0.2" type="text" id="start-dhcp-range" class="form-control"/>
|
||||
-
|
||||
<input placeholder="192.168.0.254" type="text" id="stop-dhcp-range" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header d-flex align-items-center gap3 justify-content-between">
|
||||
<h3>Cache size</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<input type="number" name="" id="cache-size-input" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="margin-bottom: 50px;">
|
||||
<div class="card-header d-flex align-items-center gap3 justify-content-between">
|
||||
<h3>Edit config file</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<textarea id="edit_file_input" style="width: 100%;height: 200px;"></textarea>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-primary" id="save_config_file_button" style="width: 100%">Save config file</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<button class="btn btn-primary" id="save-settings-button">Save</button>
|
||||
<script src="js/checkbox.js"></script>
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<script src="js/theme.js"></script>
|
||||
<script src="js/settings/settings.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+7
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
const dhcp_enabled = document.querySelector("#dhcp_enabled");
|
||||
const dhcp_rect_body = document.querySelector("#dhcp_rect_body");
|
||||
|
||||
dhcp_enabled.addEventListener("click", () => {
|
||||
!dhcp_enabled.checked
|
||||
? dhcp_rect_body.classList.add("hidden")
|
||||
: dhcp_rect_body.classList.remove("hidden");
|
||||
});
|
||||
@@ -0,0 +1,207 @@
|
||||
const upstream_dns_servers_table_body = document.querySelector(
|
||||
"#upstream-dns-servers-table-body",
|
||||
);
|
||||
const local_domains_table_body = document.querySelector(
|
||||
"#local-domains-table-body",
|
||||
);
|
||||
const cache_size_input = document.querySelector("#cache-size-input");
|
||||
const save_settings_button = document.querySelector("#save-settings-button");
|
||||
const add_dns_server_button = document.querySelector("#add_dns_server_button");
|
||||
const add_local_domain_button = document.querySelector(
|
||||
"#add_local_domain_button",
|
||||
);
|
||||
const edit_file_input = document.querySelector("#edit_file_input");
|
||||
const save_config_file_button = document.querySelector(
|
||||
"#save_config_file_button",
|
||||
);
|
||||
|
||||
var settings = {};
|
||||
var configFile = "";
|
||||
|
||||
const updateDnsServersTable = () => {
|
||||
upstream_dns_servers_table_body.innerHTML = "";
|
||||
for (var i = 0; i < settings.resolv.length; i++) {
|
||||
upstream_dns_servers_table_body.innerHTML += `<tr>
|
||||
<th class="d-flex align-items-center justify-content-between">
|
||||
${settings.resolv[i]}
|
||||
<button id="${i}" class="delete-table-button btn btn-danger">Del</button>
|
||||
</th>
|
||||
</tr>`;
|
||||
}
|
||||
};
|
||||
|
||||
const updateLocalDomainsTable = () => {
|
||||
local_domains_table_body.innerHTML = "";
|
||||
for (const [key, value] of Object.entries(settings.hosts)) {
|
||||
if (Array.isArray(value)) {
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
local_domains_table_body.innerHTML += `<tr>
|
||||
<th>${key}</th>
|
||||
<th>${value[i]}</th>
|
||||
<th><button class="deldomain btn btn-danger" id="${key}|${value[i]}">Del</button>
|
||||
</th>
|
||||
</tr>`;
|
||||
}
|
||||
} else {
|
||||
local_domains_table_body.innerHTML += `<tr>
|
||||
<th>${key}</th>
|
||||
<th>${value}</th>
|
||||
<th><button class="deldomain btn btn-danger" id="${key}|${value}">Del</button>
|
||||
</th>
|
||||
</tr>`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const updateInterface = () => {
|
||||
updateDnsServersTable();
|
||||
updateLocalDomainsTable();
|
||||
cache_size_input.value = settings.cache_size;
|
||||
};
|
||||
|
||||
const getSettings = () => {
|
||||
fetch(window.location.origin + "/api/settings")
|
||||
.then((data) => data.json())
|
||||
.then((jsondata) => {
|
||||
settings = jsondata;
|
||||
updateInterface();
|
||||
})
|
||||
.catch((e) => alert(e));
|
||||
};
|
||||
|
||||
const setSettings = () => {
|
||||
fetch(window.location.origin + "/api/settings", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(settings),
|
||||
})
|
||||
.then((data) => data.json())
|
||||
.then((jsondata) => {
|
||||
settings = jsondata;
|
||||
updateInterface();
|
||||
alert("Success set settings");
|
||||
})
|
||||
.catch((e) => alert(e));
|
||||
};
|
||||
|
||||
save_settings_button.addEventListener("click", () => {
|
||||
setSettings();
|
||||
});
|
||||
|
||||
const write_cache_size = (value) => {
|
||||
settings.cache_size = value;
|
||||
};
|
||||
|
||||
cache_size_input.addEventListener("change", (e) => {
|
||||
write_cache_size(e.target.value);
|
||||
});
|
||||
|
||||
cache_size_input.addEventListener("input", (e) => {
|
||||
write_cache_size(e.target.value);
|
||||
});
|
||||
|
||||
getSettings();
|
||||
|
||||
add_dns_server_button.addEventListener("click", () => {
|
||||
const dns_server = prompt("Input your DNS server:");
|
||||
if (dns_server === null) return;
|
||||
if (confirm("Confirm DNS settings? (add DNS server)")) {
|
||||
if (Array.isArray(settings.resolv)) {
|
||||
if (!settings.resolv.includes(dns_server)) {
|
||||
settings.resolv.push(dns_server);
|
||||
updateDnsServersTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
upstream_dns_servers_table_body.addEventListener("click", (e) => {
|
||||
if (e.target.classList.contains("delete-table-button")) {
|
||||
if (
|
||||
confirm(`Confirm DNS settings? (delete DNS server: ${e.target.id})`)
|
||||
) {
|
||||
if (Array.isArray(settings.resolv)) {
|
||||
settings.resolv.splice(e.target.id, 1);
|
||||
updateDnsServersTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_local_domain_button.addEventListener("click", () => {
|
||||
const domainip = prompt("Input localdomain IP:");
|
||||
if (domainip === null) return;
|
||||
const domain = prompt("Input domain:");
|
||||
if (domainip === null || domain === null) return;
|
||||
if (
|
||||
confirm(
|
||||
`Confirm DNS settings? (Add Local Domain: ${domainip} ${domain})`,
|
||||
)
|
||||
) {
|
||||
for (const [key, value] of Object.entries(settings.hosts)) {
|
||||
if (key === domainip) {
|
||||
if (Array.isArray(value)) {
|
||||
if (!value.includes(domain)) {
|
||||
value.push(domain);
|
||||
updateLocalDomainsTable();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const domainsarray = [value, domain];
|
||||
settings.hosts[key] = domainsarray;
|
||||
updateLocalDomainsTable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
settings.hosts[domainip] = domain;
|
||||
updateLocalDomainsTable();
|
||||
}
|
||||
});
|
||||
|
||||
local_domains_table_body.addEventListener("click", (e) => {
|
||||
if (e.target.classList.contains("deldomain")) {
|
||||
if (confirm(`Confirm DNS settings? (delete domain: ${e.target.id})`)) {
|
||||
const domainip = e.target.id.split("|")[0];
|
||||
const domain = e.target.id.split("|")[1];
|
||||
for (const [key, value] of Object.entries(settings.hosts)) {
|
||||
if (key === domainip) {
|
||||
if (Array.isArray(value)) {
|
||||
if (value.includes(domain)) {
|
||||
value.splice(value.indexOf(domain), 1);
|
||||
updateLocalDomainsTable();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
delete settings.hosts[key];
|
||||
updateLocalDomainsTable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const getConfigFile = () => {
|
||||
fetch(window.location.origin + "/api/settings/file")
|
||||
.then((data) => data.text())
|
||||
.then((textdata) => (edit_file_input.value = textdata))
|
||||
.catch((e) => alert(e));
|
||||
};
|
||||
|
||||
getConfigFile();
|
||||
|
||||
save_config_file_button.addEventListener("click", () => {
|
||||
if (confirm("Save Config file?")) {
|
||||
fetch(window.location.origin + "/api/settings/file", {
|
||||
method: "POST",
|
||||
body: edit_file_input.value,
|
||||
})
|
||||
.then((data) => data.text())
|
||||
.then((textdata) => {
|
||||
edit_file_input.value = textdata;
|
||||
alert("Success write settings file");
|
||||
})
|
||||
.catch((e) => alert(e));
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
const dark_theme = document.querySelector('#dark_theme')
|
||||
|
||||
dark_theme.addEventListener('click', () => {
|
||||
if (dark_theme.checked) {
|
||||
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
||||
localStorage.setItem('data-bs-theme', 'dark')
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-bs-theme', 'light')
|
||||
localStorage.setItem('data-bs-theme', 'light')
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
var theme = localStorage.getItem('data-bs-theme')
|
||||
if (theme) {
|
||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
||||
if (theme === 'dark') {
|
||||
dark_theme.checked = true
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user