initial commit
This commit is contained in:
commit
9246e48f03
39 files changed
+34142
No files matched your search
@@ -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
@@ -0,0 +1,6 @@
|
||||
@charset "UTF-8";/*!
|
||||
* Bootstrap v5.3.5 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherLine truncated
|
||||
/*# sourceMappingURL=bootstrap.min.css.map */
|
||||
@@ -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
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Bootstrap v5.3.5 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),a=t=>{t.dispatchEvent(new Event(o))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,h=t=>{if(!l(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},d=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),u=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?u(t.parentNode):null},_=()=>{},g=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,m=[],p=()=>"rtl"===document.documentElement.dir,b=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of m)t()})),m.push(e)):e()},v=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,y=(t,e,i=!0)=>{if(!i)return void v(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),v(t))};e.addEventListener(o,r),setTimeout((()=>{n||a(e)}),s)},w=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},A=/[^.]*(?=\..*)\.|.*/,E=/\..*/,C=/::\d+$/,T={};let k=1;const $={mouseenter:"mouseover",mouseleave:"mouseout"},S=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${k++}`||t.uidEvent||k++}function O(t){const e=L(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function I(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function D(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=M(t);return S.has(o)||(o=t),[s,n,o]}function N(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=D(e,i,s);if(e in $){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=O(t),c=l[a]||(l[a]={}),h=I(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=L(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return F(n,{delegateTarget:r}),s.oneOff&&j.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return F(s,{delegateTarget:t}),i.oneOff&&j.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function P(t,e,i,s,n){const o=I(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function x(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(Line truncated
|
||||
//# sourceMappingURL=bootstrap.min.js.map
|
||||
@@ -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