init rewrite
This commit is contained in:
		
							parent
							
								
									9a44bc494e
								
							
						
					
					
						commit
						6d828fcffc
					
				
					 100 changed files with 50541 additions and 2707 deletions
				
			
		
							
								
								
									
										7
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
build
 | 
					build/
 | 
				
			||||||
cmake-build-debug
 | 
					docs/
 | 
				
			||||||
.idea
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
sql/*.h
 | 
					include/migrations/*.sql.h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
[submodule "drogon"]
 | 
					 | 
				
			||||||
	path = drogon
 | 
					 | 
				
			||||||
	url = https://github.com/an-tao/drogon.git
 | 
					 | 
				
			||||||
							
								
								
									
										103
									
								
								CMakeLists.txt
									
										
									
									
									
								
							
							
						
						
									
										103
									
								
								CMakeLists.txt
									
										
									
									
									
								
							| 
						 | 
					@ -1,70 +1,57 @@
 | 
				
			||||||
cmake_minimum_required (VERSION 3.2)
 | 
					cmake_minimum_required (VERSION 3.7)
 | 
				
			||||||
project(core)
 | 
					project(core)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(CheckIncludeFileCXX)
 | 
					add_executable(core main.c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
check_include_file_cxx(any HAS_ANY)
 | 
					option(WIRING_PI_DEBUG "Use WiringPi Debugging Tool (OFF)" OFF)
 | 
				
			||||||
check_include_file_cxx(string_view HAS_STRING_VIEW)
 | 
					 | 
				
			||||||
if(HAS_ANY AND HAS_STRING_VIEW)
 | 
					 | 
				
			||||||
    set(CMAKE_CXX_STANDARD 17)
 | 
					 | 
				
			||||||
else()
 | 
					 | 
				
			||||||
    set(CMAKE_CXX_STANDARD 14)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
 | 
					#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -Wpedantic -lwiringPi -lwiringPiDev -luuid -llmdb -g")
 | 
				
			||||||
set(CMAKE_CXX_EXTENSIONS OFF)
 | 
					SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wpedantic -Werror -Wall -Wextra -luuid -lsqlite3 -g")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -latomic")
 | 
					string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
 | 
				
			||||||
 | 
					add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########
 | 
					if(WIRING_PI_DEBUG)
 | 
				
			||||||
# If you include the drogon source code locally in your project, use this method to add drogon
 | 
					    message("Showing wiringPi calls as debug")
 | 
				
			||||||
# add_subdirectory(drogon)
 | 
					    add_definitions("-DWIRING_PI_DEBUG")
 | 
				
			||||||
# set(Drogon_DIR ${PROJECT_BINARY_DIR}/drogon)
 | 
					endif(WIRING_PI_DEBUG)
 | 
				
			||||||
# find_package(Drogon CONFIG REQUIRED NO_DEFAULT_PATH)
 | 
					 | 
				
			||||||
# include_directories(${DROGON_INCLUDE_DIRS})
 | 
					 | 
				
			||||||
# link_libraries(${DROGON_LIBRARIES})
 | 
					 | 
				
			||||||
##########
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# find_package(Drogon CONFIG REQUIRED)
 | 
					add_definitions("-DMG_ENABLE_EXTRA_ERRORS_DESC")
 | 
				
			||||||
# include_directories(${DROGON_INCLUDE_DIRS})
 | 
					 | 
				
			||||||
# link_libraries(${DROGON_LIBRARIES})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(CMAKE_CXX_STANDARD LESS 17)
 | 
					aux_source_directory(vendor VENDOR_SRC) # vendor first to put their warnings on top
 | 
				
			||||||
    #With C++14, use boost to support any and string_view
 | 
					aux_source_directory(. SRC_DIR)
 | 
				
			||||||
    message(STATUS "use c++14")
 | 
					aux_source_directory(models MODELS_SRC)
 | 
				
			||||||
    find_package(Boost 1.61.0 REQUIRED)
 | 
					aux_source_directory(helpers HELPERS_SRC)
 | 
				
			||||||
    include_directories(${Boost_INCLUDE_DIRS})
 | 
					aux_source_directory(handlers HANDLERS_SRC)
 | 
				
			||||||
else()
 | 
					aux_source_directory(endpoints ENDPOINTSS_SRC)
 | 
				
			||||||
    message(STATUS "use c++17")
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
aux_source_directory(./ SRC_DIR)
 | 
					configure_file("core.ini" "core.ini" COPYONLY)
 | 
				
			||||||
aux_source_directory(controllers CTL_SRC)
 | 
					 | 
				
			||||||
aux_source_directory(filters FILTER_SRC)
 | 
					 | 
				
			||||||
aux_source_directory(plugins PLUGIN_SRC)
 | 
					 | 
				
			||||||
aux_source_directory(models MODEL_SRC)
 | 
					 | 
				
			||||||
aux_source_directory(helpers HELPER_SRC)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/views/*.csp)
 | 
					target_sources(core PRIVATE ${VENDOR_SRC} ${SRC_DIR} ${HANDLERS_SRC} ${HELPERS_SRC} ${MODELS_SRC} ${ENDPOINTSS_SRC})
 | 
				
			||||||
foreach(cspFile ${SCP_LIST})
 | 
					target_include_directories(core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
 | 
				
			||||||
    message(STATUS "cspFile:" ${cspFile})
 | 
					target_include_directories(core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor)
 | 
				
			||||||
    EXEC_PROGRAM(basename ARGS "${cspFile} .csp" OUTPUT_VARIABLE classname)
 | 
					 | 
				
			||||||
    message(STATUS "view classname:" ${classname})
 | 
					 | 
				
			||||||
    ADD_CUSTOM_COMMAND(OUTPUT ${classname}.h ${classname}.cc
 | 
					 | 
				
			||||||
            COMMAND drogon_ctl
 | 
					 | 
				
			||||||
            ARGS create view ${cspFile}
 | 
					 | 
				
			||||||
            DEPENDS ${cspFile}
 | 
					 | 
				
			||||||
            VERBATIM )
 | 
					 | 
				
			||||||
    set(VIEWSRC ${VIEWSRC} ${classname}.cc)
 | 
					 | 
				
			||||||
endforeach()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
configure_file("config.json" "config.json" COPYONLY)
 | 
					add_custom_target(migrations
 | 
				
			||||||
 | 
					    COMMAND ./compile_migrations.sh
 | 
				
			||||||
 | 
					    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 | 
					add_custom_target(run
 | 
				
			||||||
add_executable(core ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC} ${HELPER_SRC})
 | 
					    COMMAND ./core start
 | 
				
			||||||
 | 
					    DEPENDS core
 | 
				
			||||||
add_custom_target(compiled_migrations ${CMAKE_CURRENT_SOURCE_DIR}/compile_migrations.sh)
 | 
					    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
				
			||||||
add_dependencies(core compiled_migrations)
 | 
					)
 | 
				
			||||||
 | 
					add_custom_target(debug
 | 
				
			||||||
add_subdirectory(drogon)
 | 
					    COMMAND valgrind ./core start
 | 
				
			||||||
target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
 | 
					    DEPENDS core
 | 
				
			||||||
 | 
					    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					add_custom_target(debug-full
 | 
				
			||||||
 | 
					    COMMAND valgrind --leak-check=full --show-leak-kinds=all ./core start
 | 
				
			||||||
 | 
					    DEPENDS core
 | 
				
			||||||
 | 
					    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					add_custom_target(docs
 | 
				
			||||||
 | 
					    COMMAND doxygen
 | 
				
			||||||
 | 
					    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@ migration_num=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
while [ -f sql/migration_$migration_num.sql ]
 | 
					while [ -f sql/migration_$migration_num.sql ]
 | 
				
			||||||
do
 | 
					do
 | 
				
			||||||
  xxd -i sql/migration_$migration_num.sql | sed 's/\([0-9a-f]\)$/\0, 0x00/' > sql/migration_$migration_num.h
 | 
					  xxd -i sql/migration_$migration_num.sql | sed 's/\([0-9a-f]\)$/\0, 0x00/' > include/migrations/$migration_num.sql.h
 | 
				
			||||||
  ((migration_num++));
 | 
					  ((migration_num++));
 | 
				
			||||||
done;
 | 
					done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										74
									
								
								config.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								config.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,74 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config_t global_config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONFINI_IS_KEY(SECTION, KEY) \
 | 
				
			||||||
 | 
					    (ini_array_match(SECTION, disp->append_to, '.', disp->format) && \
 | 
				
			||||||
 | 
					     ini_string_match_ii(KEY, disp->data, disp->format))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					config_load(IniDispatch *disp, void *config_void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    config_t *config = (config_t*)config_void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(disp->type == INI_KEY)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(CONFINI_IS_KEY("core", "database"))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config->database = malloc(sizeof(char) * (strlen(disp->value) + 1));
 | 
				
			||||||
 | 
					            strcpy(config->database, disp->value);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(CONFINI_IS_KEY("core", "log-level"))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(strcasecmp(disp->value, "trace") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                config->log_level = LOG_LEVEL_TRACE;
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(strcasecmp(disp->value, "debug") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                config->log_level = LOG_LEVEL_DEBUG;
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(strcasecmp(disp->value, "info") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                config->log_level = LOG_LEVEL_INFO;
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(strcasecmp(disp->value, "warn") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                config->log_level = LOG_LEVEL_WARN;
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(strcasecmp(disp->value, "error") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                config->log_level = LOG_LEVEL_ERROR;
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(strcasecmp(disp->value, "fatal") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                config->log_level = LOG_LEVEL_FATAL;
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            LOG_WARN("invalid log-level '%s'\n", disp->value);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(CONFINI_IS_KEY("core", "discovery-port"))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config->discovery_port = atoi(disp->value);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(CONFINI_IS_KEY("core", "server-port"))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            strcpy(config->server_port, disp->value);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								config.cc
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								config.cc
									
										
									
									
									
								
							| 
						 | 
					@ -1,22 +0,0 @@
 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace config
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    char version[] = "0.0.1";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint16_t discover_max_client_backlog = 20;
 | 
					 | 
				
			||||||
    uint16_t discover_port_dev = 4420;
 | 
					 | 
				
			||||||
    uint16_t discover_port = 4419;
 | 
					 | 
				
			||||||
    uint16_t discover_timeout_ms = 2000;
 | 
					 | 
				
			||||||
    uint8_t discover_code_accept = 0;
 | 
					 | 
				
			||||||
    uint8_t discover_code_reject = 100;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t command_code_get_time = 1;
 | 
					 | 
				
			||||||
    uint8_t command_code_get_id = 2;
 | 
					 | 
				
			||||||
    uint8_t command_code_set_name = 100;
 | 
					 | 
				
			||||||
    uint8_t command_code_get_name = 101;
 | 
					 | 
				
			||||||
    uint8_t command_code_set_schedule = 102;
 | 
					 | 
				
			||||||
    uint8_t command_code_get_schedule = 103;
 | 
					 | 
				
			||||||
    uint8_t command_code_set_relay_name = 104;
 | 
					 | 
				
			||||||
    uint8_t command_code_get_relay_name = 105;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										27
									
								
								config.h
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								config.h
									
										
									
									
									
								
							| 
						 | 
					@ -1,27 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_CONFIG_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_CONFIG_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdint-gcc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace config
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    extern char version[];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    extern uint16_t discover_max_client_backlog;
 | 
					 | 
				
			||||||
    extern uint16_t discover_port_dev;
 | 
					 | 
				
			||||||
    extern uint16_t discover_port;
 | 
					 | 
				
			||||||
    extern uint16_t discover_timeout_ms;
 | 
					 | 
				
			||||||
    extern uint8_t discover_code_accept;
 | 
					 | 
				
			||||||
    extern uint8_t discover_code_reject;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    extern uint8_t command_code_get_time;
 | 
					 | 
				
			||||||
    extern uint8_t command_code_get_id;
 | 
					 | 
				
			||||||
    extern uint8_t command_code_set_name;
 | 
					 | 
				
			||||||
    extern uint8_t command_code_get_name;
 | 
					 | 
				
			||||||
    extern uint8_t command_code_set_schedule;
 | 
					 | 
				
			||||||
    extern uint8_t command_code_get_schedule;
 | 
					 | 
				
			||||||
    extern uint8_t command_code_set_relay_name;
 | 
					 | 
				
			||||||
    extern uint8_t command_code_get_relay_name;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_CONFIG_H
 | 
					 | 
				
			||||||
							
								
								
									
										63
									
								
								config.json
									
										
									
									
									
								
							
							
						
						
									
										63
									
								
								config.json
									
										
									
									
									
								
							| 
						 | 
					@ -1,63 +0,0 @@
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    "listeners": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "address": "0.0.0.0",
 | 
					 | 
				
			||||||
            "port": 5000,
 | 
					 | 
				
			||||||
            "https": false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "app": {
 | 
					 | 
				
			||||||
        "threads_num": 1,
 | 
					 | 
				
			||||||
        "enable_session": false,
 | 
					 | 
				
			||||||
        "session_timeout": 0,
 | 
					 | 
				
			||||||
        "document_root": "./static/",
 | 
					 | 
				
			||||||
        "home_page": "index.html",
 | 
					 | 
				
			||||||
        "upload_path": "uploads",
 | 
					 | 
				
			||||||
        "file_types": [
 | 
					 | 
				
			||||||
            "gif",
 | 
					 | 
				
			||||||
            "png",
 | 
					 | 
				
			||||||
            "jpg",
 | 
					 | 
				
			||||||
            "js",
 | 
					 | 
				
			||||||
            "css",
 | 
					 | 
				
			||||||
            "html",
 | 
					 | 
				
			||||||
            "ico",
 | 
					 | 
				
			||||||
            "swf",
 | 
					 | 
				
			||||||
            "xap",
 | 
					 | 
				
			||||||
            "apk",
 | 
					 | 
				
			||||||
            "cur",
 | 
					 | 
				
			||||||
            "xml"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "max_connections": 100000,
 | 
					 | 
				
			||||||
        "max_connections_per_ip": 0,
 | 
					 | 
				
			||||||
        "load_dynamic_views": false,
 | 
					 | 
				
			||||||
        "dynamic_views_path": [
 | 
					 | 
				
			||||||
            "./views"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "log": {
 | 
					 | 
				
			||||||
            "logfile_base_name": "",
 | 
					 | 
				
			||||||
            "log_size_limit": 100000000,
 | 
					 | 
				
			||||||
            "log_level": "DEBUG"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "run_as_daemon": false,
 | 
					 | 
				
			||||||
        "relaunch_on_error": false,
 | 
					 | 
				
			||||||
        "use_sendfile": true,
 | 
					 | 
				
			||||||
        "use_gzip": true,
 | 
					 | 
				
			||||||
        "static_files_cache_time": 5,
 | 
					 | 
				
			||||||
        "idle_connection_timeout": 60,
 | 
					 | 
				
			||||||
        "server_header_field": "",
 | 
					 | 
				
			||||||
        "keepalive_requests": 0,
 | 
					 | 
				
			||||||
        "pipelining_requests": 0,
 | 
					 | 
				
			||||||
        "gzip_static": true,
 | 
					 | 
				
			||||||
        "client_max_body_size": "1M",
 | 
					 | 
				
			||||||
        "client_max_memory_body_size": "64K",
 | 
					 | 
				
			||||||
        "client_max_websocket_message_size": "128K"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "plugins": [{
 | 
					 | 
				
			||||||
        "dependencies": [],
 | 
					 | 
				
			||||||
        "config": {
 | 
					 | 
				
			||||||
            "heartbeat_interval": 2
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    }],
 | 
					 | 
				
			||||||
    "custom_config": {}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										185
									
								
								config.template
									
										
									
									
									
								
							
							
						
						
									
										185
									
								
								config.template
									
										
									
									
									
								
							| 
						 | 
					@ -1,185 +0,0 @@
 | 
				
			||||||
/* This is a JSON format configuration file
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
    //ssl:The global ssl files setting
 | 
					 | 
				
			||||||
    "ssl": {
 | 
					 | 
				
			||||||
        "cert": "../../trantor/trantor/tests/server.pem",
 | 
					 | 
				
			||||||
        "key": "../../trantor/trantor/tests/server.pem"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "listeners": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            //address: Ip address,0.0.0.0 by default
 | 
					 | 
				
			||||||
            "address": "0.0.0.0",
 | 
					 | 
				
			||||||
            //port: Port number
 | 
					 | 
				
			||||||
            "port": 80,
 | 
					 | 
				
			||||||
            //https: If true, use https for security,false by default
 | 
					 | 
				
			||||||
            "https": false
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "address": "0.0.0.0",
 | 
					 | 
				
			||||||
            "port": 443,
 | 
					 | 
				
			||||||
            "https": true,
 | 
					 | 
				
			||||||
            //cert,key: Cert file path and key file path, empty by default,
 | 
					 | 
				
			||||||
            //if empty, use the global setting
 | 
					 | 
				
			||||||
            "cert": "",
 | 
					 | 
				
			||||||
            "key": ""
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "db_clients": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            //name: Name of the client,'default' by default
 | 
					 | 
				
			||||||
            //"name":"",
 | 
					 | 
				
			||||||
            //rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
 | 
					 | 
				
			||||||
            "rdbms": "postgresql",
 | 
					 | 
				
			||||||
            //filename: Sqlite3 db file name
 | 
					 | 
				
			||||||
            //"filename":"",
 | 
					 | 
				
			||||||
            //host: Server address,localhost by default
 | 
					 | 
				
			||||||
            "host": "127.0.0.1",
 | 
					 | 
				
			||||||
            //port: Server port, 5432 by default
 | 
					 | 
				
			||||||
            "port": 5432,
 | 
					 | 
				
			||||||
            //dbname: Database name
 | 
					 | 
				
			||||||
            "dbname": "test",
 | 
					 | 
				
			||||||
            //user: 'postgres' by default
 | 
					 | 
				
			||||||
            "user": "",
 | 
					 | 
				
			||||||
            //passwd: '' by default
 | 
					 | 
				
			||||||
            "passwd": "",
 | 
					 | 
				
			||||||
            //is_fast: false by default, if it is true, the client is faster but user can't call
 | 
					 | 
				
			||||||
            //any synchronous interface of it.
 | 
					 | 
				
			||||||
            "is_fast": false,
 | 
					 | 
				
			||||||
            //connection_number: 1 by default, valid only if is_fast is false.
 | 
					 | 
				
			||||||
            "connection_number": 1
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ],*/
 | 
					 | 
				
			||||||
    "app": {
 | 
					 | 
				
			||||||
        //threads_num: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
 | 
					 | 
				
			||||||
        //is the number of CPU cores
 | 
					 | 
				
			||||||
        "threads_num": 1,
 | 
					 | 
				
			||||||
        //enable_session: False by default
 | 
					 | 
				
			||||||
        "enable_session": false,
 | 
					 | 
				
			||||||
        "session_timeout": 0,
 | 
					 | 
				
			||||||
        //document_root: Root path of HTTP document, defaut path is ./
 | 
					 | 
				
			||||||
        "document_root": "./",
 | 
					 | 
				
			||||||
        //home_page: Set the HTML file of the home page, the default value is "index.html"
 | 
					 | 
				
			||||||
        //If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
 | 
					 | 
				
			||||||
        //to the request for "/".
 | 
					 | 
				
			||||||
        "home_page": "index.html",
 | 
					 | 
				
			||||||
        //upload_path: The path to save the uploaded file. "uploads" by default. 
 | 
					 | 
				
			||||||
        //If the path isn't prefixed with /, ./ or ../,
 | 
					 | 
				
			||||||
        //it is relative path of document_root path
 | 
					 | 
				
			||||||
        "upload_path": "uploads",
 | 
					 | 
				
			||||||
        /* file_types:
 | 
					 | 
				
			||||||
         * HTTP download file types,The file types supported by drogon
 | 
					 | 
				
			||||||
         * by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
 | 
					 | 
				
			||||||
         * "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
 | 
					 | 
				
			||||||
         * "gif", "bmp", "ico", "icns", etc. */
 | 
					 | 
				
			||||||
        "file_types": [
 | 
					 | 
				
			||||||
            "gif",
 | 
					 | 
				
			||||||
            "png",
 | 
					 | 
				
			||||||
            "jpg",
 | 
					 | 
				
			||||||
            "js",
 | 
					 | 
				
			||||||
            "css",
 | 
					 | 
				
			||||||
            "html",
 | 
					 | 
				
			||||||
            "ico",
 | 
					 | 
				
			||||||
            "swf",
 | 
					 | 
				
			||||||
            "xap",
 | 
					 | 
				
			||||||
            "apk",
 | 
					 | 
				
			||||||
            "cur",
 | 
					 | 
				
			||||||
            "xml"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        //max_connections: maximum connections number,100000 by default
 | 
					 | 
				
			||||||
        "max_connections": 100000,
 | 
					 | 
				
			||||||
        //max_connections_per_ip: maximum connections number per clinet,0 by default which means no limit
 | 
					 | 
				
			||||||
        "max_connections_per_ip": 0,
 | 
					 | 
				
			||||||
        //Load_dynamic_views: False by default, when set to true, drogon
 | 
					 | 
				
			||||||
        //compiles and loads dynamically "CSP View Files" in directories defined
 | 
					 | 
				
			||||||
        //by "dynamic_views_path"
 | 
					 | 
				
			||||||
        "load_dynamic_views": false,
 | 
					 | 
				
			||||||
        //dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
 | 
					 | 
				
			||||||
        //it is relative path of document_root path
 | 
					 | 
				
			||||||
        "dynamic_views_path": [
 | 
					 | 
				
			||||||
            "./views"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        //log: Set log output, drogon output logs to stdout by default
 | 
					 | 
				
			||||||
        "log": {
 | 
					 | 
				
			||||||
            //log_path: Log file path,empty by default,in which case,logs are output to the stdout
 | 
					 | 
				
			||||||
            //"log_path": "./",
 | 
					 | 
				
			||||||
            //logfile_base_name: Log file base name,empty by default which means drogon names logfile as
 | 
					 | 
				
			||||||
            //drogon.log ...
 | 
					 | 
				
			||||||
            "logfile_base_name": "",
 | 
					 | 
				
			||||||
            //log_size_limit: 100000000 bytes by default,
 | 
					 | 
				
			||||||
            //When the log file size reaches "log_size_limit", the log file is switched.
 | 
					 | 
				
			||||||
            "log_size_limit": 100000000,
 | 
					 | 
				
			||||||
            //log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
 | 
					 | 
				
			||||||
            //The TRACE level is only valid when built in DEBUG mode.
 | 
					 | 
				
			||||||
            "log_level": "DEBUG"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        //run_as_daemon: False by default
 | 
					 | 
				
			||||||
        "run_as_daemon": false,
 | 
					 | 
				
			||||||
        //relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
 | 
					 | 
				
			||||||
        "relaunch_on_error": false,
 | 
					 | 
				
			||||||
        //use_sendfile: True by default, if ture, the program 
 | 
					 | 
				
			||||||
        //uses sendfile() system-call to send static files to clients;
 | 
					 | 
				
			||||||
        "use_sendfile": true,
 | 
					 | 
				
			||||||
        //use_gzip: True by default, use gzip to compress the response body's content;
 | 
					 | 
				
			||||||
        "use_gzip": true,
 | 
					 | 
				
			||||||
        //static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
 | 
					 | 
				
			||||||
        //0 means cache forever, the negative value means no cache
 | 
					 | 
				
			||||||
        "static_files_cache_time": 5,
 | 
					 | 
				
			||||||
        //simple_controllers_map: Used to configure mapping from path to simple controller
 | 
					 | 
				
			||||||
        "simple_controllers_map": [{
 | 
					 | 
				
			||||||
            "path": "/path/name",
 | 
					 | 
				
			||||||
            "controller": "controllerClassName",
 | 
					 | 
				
			||||||
            "http_methods": [
 | 
					 | 
				
			||||||
                "get",
 | 
					 | 
				
			||||||
                "post"
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            "filters": [
 | 
					 | 
				
			||||||
                "FilterClassName"
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        }],
 | 
					 | 
				
			||||||
        //idle_connection_timeout: Defaults to 60 seconds, the lifetime 
 | 
					 | 
				
			||||||
        //of the connection without read or write
 | 
					 | 
				
			||||||
        "idle_connection_timeout": 60,
 | 
					 | 
				
			||||||
        //server_header_field: Set the 'server' header field in each response sent by drogon,
 | 
					 | 
				
			||||||
        //empty string by default with which the 'server' header field is set to "Server: drogon/version string\r\n"
 | 
					 | 
				
			||||||
        "server_header_field": "",
 | 
					 | 
				
			||||||
        //keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection. 
 | 
					 | 
				
			||||||
        //After the maximum number of requests are made, the connection is closed.
 | 
					 | 
				
			||||||
        //The default value of 0 means no limit.
 | 
					 | 
				
			||||||
        "keepalive_requests": 0,
 | 
					 | 
				
			||||||
        //pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer. 
 | 
					 | 
				
			||||||
        //After the maximum number of requests are made, the connection is closed.
 | 
					 | 
				
			||||||
        //The default value of 0 means no limit.
 | 
					 | 
				
			||||||
        "pipelining_requests": 0,
 | 
					 | 
				
			||||||
        //gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed 
 | 
					 | 
				
			||||||
        //file with the extension ".gz" in the same path and send the compressed file to the client.
 | 
					 | 
				
			||||||
        //The default value of gzip_static is true.
 | 
					 | 
				
			||||||
        "gzip_static": true,
 | 
					 | 
				
			||||||
        //client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
 | 
					 | 
				
			||||||
        //One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
 | 
					 | 
				
			||||||
        "client_max_body_size": "1M",
 | 
					 | 
				
			||||||
        //max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
 | 
					 | 
				
			||||||
        //If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
 | 
					 | 
				
			||||||
        //Setting it to "" means no limit.
 | 
					 | 
				
			||||||
        "client_max_memory_body_size": "64K",
 | 
					 | 
				
			||||||
        //client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
 | 
					 | 
				
			||||||
        //One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
 | 
					 | 
				
			||||||
        "client_max_websocket_message_size": "128K"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    //plugins: Define all plugins running in the application
 | 
					 | 
				
			||||||
    "plugins": [{
 | 
					 | 
				
			||||||
        //name: The class name of the plugin
 | 
					 | 
				
			||||||
        //"name": "TestPlugin",
 | 
					 | 
				
			||||||
        //dependencies: Plugins that the plugin depends on. It can be commented out
 | 
					 | 
				
			||||||
        "dependencies": [],
 | 
					 | 
				
			||||||
        //config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
 | 
					 | 
				
			||||||
        //It can be commented out
 | 
					 | 
				
			||||||
        "config": {
 | 
					 | 
				
			||||||
            "heartbeat_interval": 2
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    }],
 | 
					 | 
				
			||||||
    //custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method. 
 | 
					 | 
				
			||||||
    "custom_config": {}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,107 +0,0 @@
 | 
				
			||||||
#include <models/controller_dbo.h>
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#include "api_v1_controllers.h"
 | 
					 | 
				
			||||||
using namespace api::v1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controllers::get_all(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    controller_dbo **all_controllers = controller_dbo::get_all();
 | 
					 | 
				
			||||||
    Json::Value all_controllers_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; all_controllers[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        all_controllers_json.append(all_controllers[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(all_controllers_json);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    controller_dbo::free_list(all_controllers);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controllers::get_one_by_id(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string& controller_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t) &sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(controllers[0])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpJsonResponse(controllers[0]->to_json());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    controller_dbo::free_list(controllers);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controllers::delete_one_by_id(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string& controller_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t) &sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(controllers[0])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        if(!controllers[0]->remove())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    controller_dbo::free_list(controllers);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controllers::put_one_by_id(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
 | 
					 | 
				
			||||||
                           const std::string &controller_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value body = *req->getJsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t) &sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(controllers[0])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        strncpy(controllers[0]->name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
        strncpy(controllers[0]->ip, body["ip"].asCString(), 16);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        controllers[0]->name[127] = '\0';
 | 
					 | 
				
			||||||
        controllers[0]->ip[16] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        if(controllers[0]->update())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            controllers[0]->command(config::command_code_set_name, controllers[0]->name);
 | 
					 | 
				
			||||||
            resp = HttpResponse::newHttpJsonResponse(controllers[0]->to_json());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    controller_dbo::free_list(controllers);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,31 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
#include <drogon/HttpController.h>
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
namespace api::v1
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        class controllers:public drogon::HttpController<controllers>
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        public:
 | 
					 | 
				
			||||||
            METHOD_LIST_BEGIN
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::post_discover, "/discover", Post, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::get_all, "/", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::get_one_by_id, "/{1}", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::delete_one_by_id, "/{1}", Delete, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::put_one_by_id, "/{1}", Put, Options, "filters::json_required", "filters::controllers::valid_json");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::get_relays_all, "/{1}/relays/", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::get_relays_one_by_id_and_num, "/{1}/relays/{2}", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(controllers::put_relays_one_by_id_and_num, "/{1}/relays/{2}", Put, Options, "filters::json_required", "filters::relays::valid_json");
 | 
					 | 
				
			||||||
            METHOD_LIST_END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            static void post_discover(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback);
 | 
					 | 
				
			||||||
            static void get_all(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback);
 | 
					 | 
				
			||||||
            static void get_one_by_id(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id);
 | 
					 | 
				
			||||||
            static void delete_one_by_id(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id);
 | 
					 | 
				
			||||||
            static void put_one_by_id(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            static void get_relays_all(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id);
 | 
					 | 
				
			||||||
            static void get_relays_one_by_id_and_num(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id, int relay_num);
 | 
					 | 
				
			||||||
            static void put_relays_one_by_id_and_num(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id, int relay_num);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,180 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <cmath>
 | 
					 | 
				
			||||||
#include <models/controller_dbo.h>
 | 
					 | 
				
			||||||
#include "api_v1_controllers.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace api::v1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void controllers::post_discover(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int discover_server_socket = helpers::bind_tcp_server("0.0.0.0", "0", config::discover_max_client_backlog);
 | 
					 | 
				
			||||||
    int discover_server_port = helpers::get_server_port(discover_server_socket);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(discover_server_port == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value payload;
 | 
					 | 
				
			||||||
    payload["port"] = discover_server_port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::StreamWriterBuilder json_writer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(helpers::send_udp_broadcast("255.255.255.255", config::discover_port_dev, Json::writeString(json_writer, payload).c_str()) < 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct sockaddr_storage their_addr{};
 | 
					 | 
				
			||||||
    socklen_t addr_size;
 | 
					 | 
				
			||||||
    int client_fd, s_ret;
 | 
					 | 
				
			||||||
    fd_set accept_fds;
 | 
					 | 
				
			||||||
    struct timeval timeout{};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t discover_answer_buf[1];
 | 
					 | 
				
			||||||
    uint8_t discover_header_buf[1];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    controller_dbo **known_controllers = controller_dbo::get_all();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while(true)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        addr_size = sizeof(their_addr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        FD_ZERO(&accept_fds);
 | 
					 | 
				
			||||||
        FD_SET(discover_server_socket, &accept_fds); // NOLINT(hicpp-signed-bitwise)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        timeout.tv_sec = config::discover_timeout_ms / 1000;
 | 
					 | 
				
			||||||
        timeout.tv_usec = (config::discover_timeout_ms % 1000) * 1000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        s_ret = select(discover_server_socket + 1, &accept_fds, nullptr, nullptr, &timeout);
 | 
					 | 
				
			||||||
        if(s_ret == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if((client_fd = accept(discover_server_socket, (struct sockaddr *) &their_addr, &addr_size)) < 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Accepting client " << strerror(errno);
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(recv(client_fd, discover_header_buf, 1, 0) < 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Receiving header from client";
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            size_t payload_length = discover_header_buf[0];
 | 
					 | 
				
			||||||
            char *answer_payload = (char*)malloc((payload_length + 1) * sizeof(*answer_payload));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(recv(client_fd, answer_payload, payload_length, 0) < 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Receiving payload from client";
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            struct sockaddr_in addr{};
 | 
					 | 
				
			||||||
            socklen_t client_addr_size = sizeof(struct sockaddr_in);
 | 
					 | 
				
			||||||
            if(getpeername(client_fd, (struct sockaddr *)&addr, &client_addr_size) != 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Receiving payload from client";
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            answer_payload[payload_length] = '\0';
 | 
					 | 
				
			||||||
            std::istringstream answer_payload_stream(answer_payload);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Json::CharReaderBuilder json_reader;
 | 
					 | 
				
			||||||
            json_reader["strictRoot"] = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            std::string errors;
 | 
					 | 
				
			||||||
            Json::Value client_info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!Json::parseFromStream(json_reader, answer_payload_stream, &client_info, &errors))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Failed to parse response: " << errors;
 | 
					 | 
				
			||||||
                discover_answer_buf[0] = config::discover_code_reject;
 | 
					 | 
				
			||||||
                send(client_fd, discover_answer_buf, sizeof(uint8_t), 0);
 | 
					 | 
				
			||||||
                close(client_fd);
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            free(answer_payload);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const char *discovered_id = client_info["id"].asCString();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            bool found_discovered_in_list = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for(int i = 0; known_controllers[i] != nullptr; i++)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if(!found_discovered_in_list)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if(strcmp(known_controllers[i]->id, discovered_id) == 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        known_controllers[i]->active = true;
 | 
					 | 
				
			||||||
                        known_controllers[i]->update();
 | 
					 | 
				
			||||||
                        delete known_controllers[i];
 | 
					 | 
				
			||||||
                        found_discovered_in_list = true;
 | 
					 | 
				
			||||||
                        known_controllers[i] = known_controllers[i + 1];
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    known_controllers[i] = known_controllers[i + 1];
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(!found_discovered_in_list)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                controller_dbo discovered_controller{};
 | 
					 | 
				
			||||||
                strcpy(discovered_controller.ip, inet_ntoa(addr.sin_addr));
 | 
					 | 
				
			||||||
                strcpy(discovered_controller.id, discovered_id);
 | 
					 | 
				
			||||||
                strcpy(discovered_controller.name, client_info["name"].asCString());
 | 
					 | 
				
			||||||
                discovered_controller.relay_count = client_info["relay_count"].asInt();
 | 
					 | 
				
			||||||
                discovered_controller.port = client_info["port"].asInt();
 | 
					 | 
				
			||||||
                discovered_controller.active = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                discovered_controller.insert();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            discover_answer_buf[0] = config::discover_code_accept;
 | 
					 | 
				
			||||||
            send(client_fd, discover_answer_buf, sizeof(uint8_t), 0);
 | 
					 | 
				
			||||||
            close(client_fd);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for(int i = 0; known_controllers[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        known_controllers[i]->active = false;
 | 
					 | 
				
			||||||
        known_controllers[i]->update();
 | 
					 | 
				
			||||||
        LOG_DEBUG << "Lost: " << known_controllers[i]->name;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    controller_dbo::free_list(known_controllers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    controller_dbo **all_controllers = controller_dbo::get_all();
 | 
					 | 
				
			||||||
    Json::Value all_controllers_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; all_controllers[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        all_controllers_json.append(all_controllers[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(all_controllers_json);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    controller_dbo::free_list(all_controllers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,119 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <models/relay_dbo.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <models/controller_dbo.h>
 | 
					 | 
				
			||||||
#include <models/schedule_dbo.h>
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#include "api_v1_controllers.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace api::v1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controllers::get_relays_all(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
 | 
					 | 
				
			||||||
                        const std::string& controller_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    relay_dbo **all_controller_relays = relay_dbo::get_by_simple("controller_id", (void *) controller_id.c_str(), (intptr_t) sqlite3_bind_text);
 | 
					 | 
				
			||||||
    Json::Value all_relays_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; all_controller_relays[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        all_relays_json.append(all_controller_relays[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(all_relays_json);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    relay_dbo::free_list(all_controller_relays);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controllers::get_relays_one_by_id_and_num(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                                      std::function<void(const HttpResponsePtr &)> &&callback, const std::string& controller_id,
 | 
					 | 
				
			||||||
                                      int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id.c_str(), relay_num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(relay)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpJsonResponse(relay->to_json());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        delete relay;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                                      std::function<void(const HttpResponsePtr &)> &&callback, const std::string& controller_id,
 | 
					 | 
				
			||||||
                                      int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(!relay_dbo::valid_num_for_controller(controller_id.c_str(), relay_num))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id.c_str(), relay_num);
 | 
					 | 
				
			||||||
    Json::Value body = *req->getJsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool db_action_result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(relay)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        strncpy(relay->name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
        strncpy(relay->active_schedule_id, body["active_schedule"].asCString(), 32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        db_action_result = relay->update();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        relay = new relay_dbo();
 | 
					 | 
				
			||||||
        relay->number = relay_num;
 | 
					 | 
				
			||||||
        strncpy(relay->name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
        strncpy(relay->active_schedule_id, body["active_schedule"].asCString(), 32);
 | 
					 | 
				
			||||||
        strncpy(relay->controller_id, controller_id.c_str(), 32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        relay->reload_active_schedule();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        db_action_result = relay->insert();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!db_action_result)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto schedules = schedule_dbo::get_by_simple("id", body["active_schedule"].asCString(), (intptr_t)&sqlite3_bind_text);
 | 
					 | 
				
			||||||
        auto controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t)&sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Json::Value payload;
 | 
					 | 
				
			||||||
        payload["target"] = relay_num;
 | 
					 | 
				
			||||||
        payload["schedule"] = schedules[0]->to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Json::StreamWriterBuilder json_writer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        controllers[0]->command(config::command_code_set_schedule, Json::writeString(json_writer, payload).c_str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpJsonResponse(relay->to_json());
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
        controller_dbo::free_list(controllers);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    delete relay;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <models/relay_dbo.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "api_v1_relays.h"
 | 
					 | 
				
			||||||
using namespace api::v1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
relays::get_all(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    relay_dbo **all_relays = relay_dbo::get_all();
 | 
					 | 
				
			||||||
    Json::Value all_relays_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; all_relays[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        all_relays_json.append(all_relays[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(all_relays_json);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    relay_dbo::free_list(all_relays);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,15 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
#include <drogon/HttpController.h>
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
namespace api::v1
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        class relays:public drogon::HttpController<relays>
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        public:
 | 
					 | 
				
			||||||
            METHOD_LIST_BEGIN
 | 
					 | 
				
			||||||
            METHOD_ADD(relays::get_all, "/", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_LIST_END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            static void get_all(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,152 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <models/schedule_dbo.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "api_v1_schedules.h"
 | 
					 | 
				
			||||||
using namespace api::v1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedules::get_all(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    schedule_dbo **all_schedules = schedule_dbo::get_all();
 | 
					 | 
				
			||||||
    Json::Value all_schedules_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; all_schedules[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        all_schedules_json.append(all_schedules[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::StreamWriterBuilder jw;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(all_schedules_json);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo::free_list(all_schedules);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedules::get_one_by_id(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string& schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id.c_str(), (intptr_t) &sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(schedules[0])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpJsonResponse(schedules[0]->to_json());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedules::delete_one_by_id(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string& schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(strcmp(schedule_id.c_str(), "off") == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k403Forbidden);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id.c_str(), (intptr_t) &sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(schedules[0])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        if(!schedules[0]->remove())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedules::post_new(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value body = *req->jsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo new_schedule{};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    strncpy(new_schedule.name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
    new_schedule.name[127] = '\0';
 | 
					 | 
				
			||||||
    strncpy(new_schedule.id, drogon::utils::getUuid().c_str(), 32);
 | 
					 | 
				
			||||||
    new_schedule.id[32] = '\0';
 | 
					 | 
				
			||||||
    new_schedule.periods = helpers::parse_periods(body["periods"]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!new_schedule.insert())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpJsonResponse(new_schedule.to_json());
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedules::put_one_by_id(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
 | 
					 | 
				
			||||||
                         const std::string &schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(strcmp(schedule_id.c_str(), "off") == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k403Forbidden);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value body = *req->jsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id.c_str(), (intptr_t) &sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(schedules[0])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        strncpy(schedules[0]->name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
        schedules[0]->name[127] = '\0';
 | 
					 | 
				
			||||||
        delete schedules[0]->periods;
 | 
					 | 
				
			||||||
        schedules[0]->periods = helpers::parse_periods(body["periods"]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(!schedules[0]->update())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
            resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
            callback(resp);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto resp = HttpResponse::newHttpJsonResponse(schedules[0]->to_json());
 | 
					 | 
				
			||||||
            callback(resp);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,27 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
#include <drogon/HttpController.h>
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
namespace api::v1
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        class schedules:public drogon::HttpController<schedules>
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        public:
 | 
					 | 
				
			||||||
            METHOD_LIST_BEGIN
 | 
					 | 
				
			||||||
            METHOD_ADD(schedules::post_new, "/", Post, Options, "filters::json_required", "filters::schedules::valid_json");
 | 
					 | 
				
			||||||
            METHOD_ADD(schedules::get_all, "/", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(schedules::get_one_by_id, "/{1}", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(schedules::delete_one_by_id, "/{1}", Delete, Options);
 | 
					 | 
				
			||||||
            METHOD_ADD(schedules::put_one_by_id, "/{1}", Put, Options, "filters::json_required", "filters::schedules::valid_json");
 | 
					 | 
				
			||||||
            //METHOD_ADD(controllers::get_relays_all,"/{1}/relays",Get);
 | 
					 | 
				
			||||||
            //METHOD_ADD(controllers::get_relays_one,"/{1}/relays/{2}",Get);
 | 
					 | 
				
			||||||
            METHOD_LIST_END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            static void post_new(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback);
 | 
					 | 
				
			||||||
            static void get_all(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback);
 | 
					 | 
				
			||||||
            static void get_one_by_id(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& schedule_id);
 | 
					 | 
				
			||||||
            static void delete_one_by_id(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& schedule_id);
 | 
					 | 
				
			||||||
            static void put_one_by_id(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& schedule_id);
 | 
					 | 
				
			||||||
            //void get_relays_all(const HttpRequestPtr& req,std::function<void (const HttpResponsePtr &)> &&callback,std::string schedule_id);
 | 
					 | 
				
			||||||
            //void get_relays_one(const HttpRequestPtr& req,std::function<void (const HttpResponsePtr &)> &&callback,std::string schedule_id,std::string relay_id);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
							
								
								
									
										5
									
								
								core.ini
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								core.ini
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					[core]
 | 
				
			||||||
 | 
					server-port = 5000
 | 
				
			||||||
 | 
					discovery-port = 4421
 | 
				
			||||||
 | 
					database = core.sqlite
 | 
				
			||||||
 | 
					log-level = debug
 | 
				
			||||||
							
								
								
									
										67
									
								
								database.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								database.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,67 @@
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <migrations/0.sql.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sqlite3 *global_database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					database_migrate()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16_t version_num = 0;
 | 
				
			||||||
 | 
					    int s, rc;
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT version_num FROM meta LIMIT 1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        version_num = sqlite3_column_int(stmt, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        version_num = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t new_version_num = version_num;
 | 
				
			||||||
 | 
					    char* err_msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(version_num)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case 0:
 | 
				
			||||||
 | 
					            LOG_INFO("migrating LEVEL 0\n");
 | 
				
			||||||
 | 
					            rc = sqlite3_exec(global_database, (const char *)sql_migration_0_sql, NULL, NULL, &err_msg);
 | 
				
			||||||
 | 
					            if(rc != 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_FATAL("couldn't migrate LEVEL 0 (%s)\n", err_msg);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            new_version_num = 1;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(version_num == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "INSERT INTO meta (version_num) VALUES (?1);", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "UPDATE meta SET version_num=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, new_version_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    if (rc != SQLITE_DONE)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("couldn't write new schema version");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc != SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								drivers/gpio.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								drivers/gpio.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					#include <wiringPi.h>
 | 
				
			||||||
 | 
					#include <piFace.h>
 | 
				
			||||||
 | 
					#include <wiring_debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <drivers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					driver_gpio_set(int pin, int value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // disable "unused parameter" warning (happens when using wiring_debug)
 | 
				
			||||||
 | 
					    (void)pin;
 | 
				
			||||||
 | 
					    (void)value;
 | 
				
			||||||
 | 
					    digitalWrite(pin, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								drivers/piface.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								drivers/piface.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					#include <wiringPi.h>
 | 
				
			||||||
 | 
					#include <piFace.h>
 | 
				
			||||||
 | 
					#include <wiring_debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <drivers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					driver_piface_set(int pin, int value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // disable "unused parameter" warning (happens when using wiring_debug)
 | 
				
			||||||
 | 
					    (void)pin;
 | 
				
			||||||
 | 
					    (void)value;
 | 
				
			||||||
 | 
					    digitalWrite(PIFACE_GPIO_BASE + pin, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								drogon
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								drogon
									
										
									
									
									
								
							| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
Subproject commit 543d1a8c8062b3873ef89c64ffd7394c6dd7c7e8
 | 
					 | 
				
			||||||
							
								
								
									
										159
									
								
								endpoints/api_v1_schedules.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								endpoints/api_v1_schedules.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,159 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_schedules.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/schedule.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_POST(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)args;
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_ParseWithLength(hm->body.p, hm->body.len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(json == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const char *error_ptr = cJSON_GetErrorPtr();
 | 
				
			||||||
 | 
					        if (error_ptr != NULL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_ERROR("error before: %s\n", error_ptr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name");
 | 
				
			||||||
 | 
					    if(!cJSON_IsString(json_name) || (json_name->valuestring == NULL))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        char *error_msg = "ERROR: no name for schedule provided";
 | 
				
			||||||
 | 
					        mg_send_head(c, 400, strlen(error_msg), "Content-Type: text/plain");
 | 
				
			||||||
 | 
					        mg_printf(c, "%s", error_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON *json_period;
 | 
				
			||||||
 | 
					    cJSON *json_periods = cJSON_GetObjectItemCaseSensitive(json, "periods");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t *new_schedule = malloc(sizeof(schedule_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_schedule->id = 0;
 | 
				
			||||||
 | 
					    uuid_generate(new_schedule->uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strncpy(new_schedule->name, json_name->valuestring, MAX_NAME_LENGTH);
 | 
				
			||||||
 | 
					    new_schedule->name[MAX_NAME_LENGTH] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int periods_count = cJSON_GetArraySize(json_periods);
 | 
				
			||||||
 | 
					    new_schedule->periods = malloc(sizeof(period_t) * periods_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int periods_valid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_ArrayForEach(json_period, json_periods)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_period_start = cJSON_GetObjectItemCaseSensitive(json_period, "start");
 | 
				
			||||||
 | 
					        cJSON *json_period_end = cJSON_GetObjectItemCaseSensitive(json_period, "end");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!cJSON_IsString(json_period_start) || (json_period_start->valuestring == NULL))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("period is missing start\n");
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(!cJSON_IsString(json_period_end) || (json_period_end->valuestring == NULL))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("period is missing end\n");
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint16_t start;
 | 
				
			||||||
 | 
					        uint16_t end;
 | 
				
			||||||
 | 
					        if(period_helper_parse_hhmm(json_period_start->valuestring, &start))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("couldn't parse start '%s'\n", json_period_start->valuestring);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(period_helper_parse_hhmm(json_period_end->valuestring, &end))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("couldn't parse end '%s'\n", json_period_end->valuestring);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        new_schedule->periods[periods_valid].start = start;
 | 
				
			||||||
 | 
					        new_schedule->periods[periods_valid].end = end;
 | 
				
			||||||
 | 
					        ++periods_valid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_schedule->periods_count = periods_valid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_save(new_schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    junction_tag_remove_for_schedule(new_schedule->id);
 | 
				
			||||||
 | 
					    cJSON *json_tag;
 | 
				
			||||||
 | 
					    cJSON *json_tags = cJSON_GetObjectItemCaseSensitive(json, "tags");
 | 
				
			||||||
 | 
					    cJSON_ArrayForEach(json_tag, json_tags)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					            if(!cJSON_IsString(json_tag) || (json_tag->valuestring == NULL))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_DEBUG("invalid tag in tags\n");
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const char *tag = json_tag->valuestring;
 | 
				
			||||||
 | 
					            int tag_id = tag_get_id(tag);
 | 
				
			||||||
 | 
					            if(tag_id == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tag_save(tag_id, tag);
 | 
				
			||||||
 | 
					                tag_id = tag_get_id(tag);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            junction_tag_insert(tag_id, 0, new_schedule->id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    json = schedule_to_json(new_schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print schedule json\n");
 | 
				
			||||||
 | 
					        mg_send_head(c, 201, 2, "Content-Type: application/json");
 | 
				
			||||||
 | 
					        mg_printf(c, "{}");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mg_send_head(c, 201, strlen(json_str), "Content-Type: application/json");
 | 
				
			||||||
 | 
					        mg_printf(c, "%s", json_str);
 | 
				
			||||||
 | 
					        free(json_str);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    schedule_free(new_schedule);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)args;
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					    schedule_t** all_schedules = schedule_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; all_schedules[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_schedule = schedule_to_json(all_schedules[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json, json_schedule);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print schedules json\n");
 | 
				
			||||||
 | 
					        mg_send_head(c, 500, 2, "Content-Type: application/json");
 | 
				
			||||||
 | 
					        mg_printf(c, "[]");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mg_send_head(c, 200, strlen(json_str), "Content-Type: application/json");
 | 
				
			||||||
 | 
					        mg_printf(c, "%s", json_str);
 | 
				
			||||||
 | 
					        free(json_str);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    schedule_free_list(all_schedules);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								endpoints/api_v1_schedules_STR.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								endpoints/api_v1_schedules_STR.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_schedules.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/schedule.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)args;
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(schedule_uid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to unparse uid\n");
 | 
				
			||||||
 | 
					        mg_send_head(c, 400, 2, "Content-Type: application/json");
 | 
				
			||||||
 | 
					        mg_printf(c, "{}");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char debug_str[40];
 | 
				
			||||||
 | 
					    uuid_unparse(target_uid, debug_str);
 | 
				
			||||||
 | 
					    LOG_DEBUG("uid: %s\n", debug_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t** all_schedules = schedule_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; all_schedules[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_schedule = schedule_to_json(all_schedules[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json, json_schedule);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print schedules json\n");
 | 
				
			||||||
 | 
					        mg_send_head(c, 500, 2, "Content-Type: application/json");
 | 
				
			||||||
 | 
					        mg_printf(c, "[]");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mg_send_head(c, 200, strlen(json_str), "Content-Type: application/json");
 | 
				
			||||||
 | 
					        mg_printf(c, "%s", json_str);
 | 
				
			||||||
 | 
					        free(json_str);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    schedule_free_list(all_schedules);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,34 +0,0 @@
 | 
				
			||||||
#include <models/relay_dbo.h>
 | 
					 | 
				
			||||||
#include "controllers_valid_json.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
using namespace filters::controllers;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void valid_json::doFilter(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                         FilterCallback &&fcb,
 | 
					 | 
				
			||||||
                         FilterChainCallback &&fccb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(req->getMethod() == Options)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        fccb();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value body = *req->jsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool is_valid = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    is_valid &= body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    is_valid &= body["ip"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        //Passed
 | 
					 | 
				
			||||||
        fccb();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    //Check failed
 | 
					 | 
				
			||||||
    auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
    res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
    fcb(res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <drogon/HttpFilter.h>
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
namespace filters::controllers
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class valid_json : public HttpFilter<valid_json>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        valid_json() = default;
 | 
					 | 
				
			||||||
        void doFilter(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                      FilterCallback &&fcb,
 | 
					 | 
				
			||||||
                      FilterChainCallback &&fccb) override;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,29 +0,0 @@
 | 
				
			||||||
#include "json_required.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
using namespace filters;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void json_required::doFilter(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                         FilterCallback &&fcb,
 | 
					 | 
				
			||||||
                         FilterChainCallback &&fccb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(req->getMethod() == Options)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        fccb();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // TODO remove this workaround
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    HttpMethod original_method = req->getMethod();
 | 
					 | 
				
			||||||
    req->setMethod(Post);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(req->jsonObject())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        req->setMethod(original_method);
 | 
					 | 
				
			||||||
        fccb();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
    res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
    fcb(res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <drogon/HttpFilter.h>
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
namespace filters
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class json_required : public HttpFilter<json_required>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        json_required() = default;
 | 
					 | 
				
			||||||
        void
 | 
					 | 
				
			||||||
        doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) override;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,40 +0,0 @@
 | 
				
			||||||
#include <models/schedule_dbo.h>
 | 
					 | 
				
			||||||
#include "relays_valid_json.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
using namespace filters::relays;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void valid_json::doFilter(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                         FilterCallback &&fcb,
 | 
					 | 
				
			||||||
                         FilterChainCallback &&fccb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(req->getMethod() == Options)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        fccb();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value body = *req->jsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool is_valid = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    is_valid &= body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    is_valid &= body["active_schedule"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        schedule_dbo **schedules = schedule_dbo::get_by_simple("id", body["active_schedule"].asCString(), (intptr_t)&sqlite3_bind_text);
 | 
					 | 
				
			||||||
        bool schedule_found = schedules[0] != nullptr;
 | 
					 | 
				
			||||||
        schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
        if(schedule_found)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            //Passed
 | 
					 | 
				
			||||||
            fccb();
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    //Check failed
 | 
					 | 
				
			||||||
    auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
    res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
    fcb(res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <drogon/HttpFilter.h>
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
namespace filters::relays
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class valid_json : public HttpFilter<valid_json>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        valid_json() = default;
 | 
					 | 
				
			||||||
        void doFilter(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                      FilterCallback &&fcb,
 | 
					 | 
				
			||||||
                      FilterChainCallback &&fccb) override;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,33 +0,0 @@
 | 
				
			||||||
#include "schedules_valid_json.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
using namespace filters::schedules;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void valid_json::doFilter(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                         FilterCallback &&fcb,
 | 
					 | 
				
			||||||
                         FilterChainCallback &&fccb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(req->getMethod() == Options)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        fccb();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value body = *req->jsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool is_valid = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    is_valid &= body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    is_valid &= body["periods"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        //Passed
 | 
					 | 
				
			||||||
        fccb();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    //Check failed
 | 
					 | 
				
			||||||
    auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
    res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
    fcb(res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <drogon/HttpFilter.h>
 | 
					 | 
				
			||||||
using namespace drogon;
 | 
					 | 
				
			||||||
namespace filters::schedules
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class valid_json : public HttpFilter<valid_json>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        valid_json() = default;
 | 
					 | 
				
			||||||
        void doFilter(const HttpRequestPtr &req,
 | 
					 | 
				
			||||||
                      FilterCallback &&fcb,
 | 
					 | 
				
			||||||
                      FilterChainCallback &&fccb) override;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,7 +0,0 @@
 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace globals
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3 *db;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,9 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_GLOBALS_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_GLOBALS_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace globals
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    extern sqlite3 *db;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_GLOBALS_H
 | 
					 | 
				
			||||||
							
								
								
									
										28
									
								
								handlers/connection.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								handlers/connection.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					#include <mongoose.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					#include <handlers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					handler_connection(struct mg_connection *c, int ev, void *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (ev == MG_EV_HTTP_REQUEST)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("new http request\n");
 | 
				
			||||||
 | 
					        struct http_message *hm = (struct http_message *) p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        endpoint_t *endpoint = router_find_endpoint(hm->uri.p, hm->uri.len, &hm->method);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(endpoint && endpoint->func)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            endpoint->func(c, endpoint->args, p);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            mg_send_head(c, 501, 0, "Content-Type: text/plain");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //mg_printf(c, "%.*s", (int)hm->message.len, hm->message.p);
 | 
				
			||||||
 | 
					        //mg_printf(c, "%.*s", (int)hm->body.len, hm->body.p);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								helpers.h
									
										
									
									
									
								
							
							
						
						
									
										43
									
								
								helpers.h
									
										
									
									
									
								
							| 
						 | 
					@ -1,43 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_HELPERS_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_HELPERS_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <models/period.h>
 | 
					 | 
				
			||||||
#include <models/period_list.h>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace helpers
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int
 | 
					 | 
				
			||||||
    bind_tcp_server(const char *addr, const char *port, int max_client_backlog);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int
 | 
					 | 
				
			||||||
    get_server_port(int fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int
 | 
					 | 
				
			||||||
    send_udp_broadcast(const char *addr, uint16_t port, const char* message);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    period_list*
 | 
					 | 
				
			||||||
    parse_periods(Json::Value periods_json);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    typedef struct sql_filter_builder
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        sql_filter_builder(const char *col_name, const void *value, intptr_t bind_func, const char *logic);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const char *col_name;
 | 
					 | 
				
			||||||
        const void *value;
 | 
					 | 
				
			||||||
        intptr_t bind_func;
 | 
					 | 
				
			||||||
        const char *logic;
 | 
					 | 
				
			||||||
    } sql_filter_builder;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_stmt*
 | 
					 | 
				
			||||||
    create_sql_filtered_query(const char *sql, sql_filter_builder **filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int
 | 
					 | 
				
			||||||
    open_tcp_connection(char* host, char* port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int
 | 
					 | 
				
			||||||
    migrate_sql();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_HELPERS_H
 | 
					 | 
				
			||||||
							
								
								
									
										52
									
								
								helpers/bind_server.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								helpers/bind_server.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,52 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_bind_tcp_server(char* addr, uint16_t port, int max_client_backlog)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char port_str[6];
 | 
				
			||||||
 | 
					    sprintf(port_str, "%d", port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct addrinfo hints, *res;
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					    int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&hints, 0, sizeof hints);
 | 
				
			||||||
 | 
					    hints.ai_family = AF_UNSPEC;
 | 
				
			||||||
 | 
					    hints.ai_socktype = SOCK_STREAM;
 | 
				
			||||||
 | 
					    hints.ai_flags = AI_PASSIVE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((status = getaddrinfo(addr, port_str, &hints, &res)) != 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("getaddrinfo: %s\n", gai_strerror(status));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((status = bind(fd, res->ai_addr, res->ai_addrlen)) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error binding socket: %s\n", strerror(errno));
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((status = listen(fd, max_client_backlog)) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error setting up listener: %s\n", strerror(errno));
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    freeaddrinfo(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,43 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
helpers::bind_tcp_server(const char *addr, const char *port, int max_client_backlog)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct addrinfo hints{}, *res;
 | 
					 | 
				
			||||||
    int fd;
 | 
					 | 
				
			||||||
    int status;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memset(&hints, 0, sizeof hints);
 | 
					 | 
				
			||||||
    hints.ai_family = AF_UNSPEC;
 | 
					 | 
				
			||||||
    hints.ai_socktype = SOCK_STREAM;
 | 
					 | 
				
			||||||
    hints.ai_flags = AI_PASSIVE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((status = getaddrinfo(addr, port, &hints, &res)) != 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error getting address info: " << gai_strerror(status);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((status = bind(fd, res->ai_addr, res->ai_addrlen)) == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error binding socket. " << status;
 | 
					 | 
				
			||||||
        freeaddrinfo(res);
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((status = listen(fd, max_client_backlog)) == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error setting up listener. " << status;
 | 
					 | 
				
			||||||
        freeaddrinfo(res);
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    freeaddrinfo(res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return fd;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										39
									
								
								helpers/connect_server.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								helpers/connect_server.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_connect_tcp_server(char* host, uint16_t port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char port_str[6];
 | 
				
			||||||
 | 
					    sprintf(port_str, "%d", port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int s, status;
 | 
				
			||||||
 | 
					    struct addrinfo hints, *res;
 | 
				
			||||||
 | 
					    memset(&hints, 0, sizeof hints);
 | 
				
			||||||
 | 
					    hints.ai_family = AF_INET; //set IP Protocol flag (IPv4 or IPv6 - we don't care)
 | 
				
			||||||
 | 
					    hints.ai_socktype = SOCK_STREAM; //set socket flag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { //getaddrinfo() will evaluate the given address, using the hints-flags and port, and return an IP address and other server infos
 | 
				
			||||||
 | 
					        LOG_ERROR("getaddrinfo: %s\n", gai_strerror(status));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //res got filled out by getaddrinfo() for us
 | 
				
			||||||
 | 
					    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //creating Socket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((status = connect(s, res->ai_addr, res->ai_addrlen)) != 0) {
 | 
				
			||||||
 | 
					        LOG_ERROR("connect() failed\n");
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    freeaddrinfo(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,58 +0,0 @@
 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <drogon/drogon.h>
 | 
					 | 
				
			||||||
#include <globals.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sqlite3_stmt*
 | 
					 | 
				
			||||||
helpers::create_sql_filtered_query(const char *sql, sql_filter_builder **filters)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    char *old_query = (char*)sql;
 | 
					 | 
				
			||||||
    char *new_query;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sql_filter_builder *filter;
 | 
					 | 
				
			||||||
    int filter_count = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    do
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        filter = filters[filter_count];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        filter_count++;
 | 
					 | 
				
			||||||
        asprintf(&new_query, " %s %s=?%d %s", old_query, filter->col_name, filter_count, filter->logic);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(old_query != sql)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            free(old_query);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        old_query = new_query;
 | 
					 | 
				
			||||||
    } while(filter->logic[0] != ';');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, new_query, -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    free(new_query);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; i < filter_count; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        filter = filters[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(filter->bind_func == (intptr_t)&sqlite3_bind_int)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sqlite3_bind_int(stmt, i + 1, (int)(intptr_t)filter->value);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(filter->bind_func == (intptr_t)&sqlite3_bind_text)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sqlite3_bind_text(stmt, i + 1, (char*)filter->value, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return stmt;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
helpers::sql_filter_builder::sql_filter_builder(const char *col_name, const void *value, intptr_t bind_func,
 | 
					 | 
				
			||||||
                                                const char *logic)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->col_name = col_name;
 | 
					 | 
				
			||||||
    this->value = value;
 | 
					 | 
				
			||||||
    this->bind_func = bind_func;
 | 
					 | 
				
			||||||
    this->logic = logic;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										12
									
								
								helpers/get_day_of_week.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								helpers/get_day_of_week.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_get_weekday(const time_t timestamp_now)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct tm *now = localtime(×tamp_now);
 | 
				
			||||||
 | 
					    int wday_sun_sat = now->tm_wday;
 | 
				
			||||||
 | 
					    int wday_mon_sun = (wday_sun_sat + 6) % 7;
 | 
				
			||||||
 | 
					    return wday_mon_sun;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								helpers/get_port.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								helpers/get_port.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t
 | 
				
			||||||
 | 
					helper_get_port(int sock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct sockaddr_in sin;
 | 
				
			||||||
 | 
					    socklen_t len = sizeof(sin);
 | 
				
			||||||
 | 
					    if (getsockname(sock, (struct sockaddr *)&sin, &len) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("could not get socket name for port: %s\n", strerror(errno));
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ntohs(sin.sin_port);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,18 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
helpers::get_server_port(int fd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(fd == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    struct sockaddr_in sin{};
 | 
					 | 
				
			||||||
    socklen_t addr_len = sizeof(sin);
 | 
					 | 
				
			||||||
    if(getsockname(fd, (struct sockaddr *)&sin, &addr_len) == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return ntohs(sin.sin_port);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,63 +0,0 @@
 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <globals.h>
 | 
					 | 
				
			||||||
#include <drogon/trantor/trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <sql/migration_0.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
helpers::migrate_sql()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uint16_t version_num = 0;
 | 
					 | 
				
			||||||
    int s, rc;
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT version_num FROM meta LIMIT 1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    s = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    if (s == SQLITE_ROW)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        version_num = sqlite3_column_int(stmt, 0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        version_num = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint16_t new_version_num = version_num;
 | 
					 | 
				
			||||||
    char* err_msg;
 | 
					 | 
				
			||||||
    char* sql;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch(version_num)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        case 0:
 | 
					 | 
				
			||||||
            rc = sqlite3_exec(globals::db, (const char *)sql_migration_0_sql, nullptr, nullptr, &err_msg);
 | 
					 | 
				
			||||||
            if(rc != 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_FATAL << "Couldn't migrate LEVEL 0 (" << err_msg << ")";
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            new_version_num = 1;
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(version_num == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        sqlite3_prepare_v2(globals::db, "INSERT INTO meta (version_num) VALUES (?1);", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        sqlite3_prepare_v2(globals::db, "UPDATE meta SET version_num=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, new_version_num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    if (rc != SQLITE_DONE)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_FATAL << "Couldn't write new Schema Version";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										57
									
								
								helpers/open_discovery_socket.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								helpers/open_discovery_socket.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,57 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_open_discovery_socket(uint16_t discovery_port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct addrinfo hints, *res;
 | 
				
			||||||
 | 
					    int fd, status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&hints, 0, sizeof hints);
 | 
				
			||||||
 | 
					    hints.ai_family = AF_INET; // use ipv4
 | 
				
			||||||
 | 
					    hints.ai_socktype = SOCK_DGRAM; //set socket flag
 | 
				
			||||||
 | 
					    hints.ai_flags = AI_PASSIVE; // get my IP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char discovery_port_str[6];
 | 
				
			||||||
 | 
					    sprintf(discovery_port_str, "%u", discovery_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //get connection info for our computer
 | 
				
			||||||
 | 
					    if ((status = getaddrinfo(NULL, discovery_port_str, &hints, &res)) != 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("getaddrinfo: %s\n", gai_strerror(status));
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //creating socket
 | 
				
			||||||
 | 
					    fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
 | 
				
			||||||
 | 
					    int yes = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // lose the pesky "Address already in use" error message
 | 
				
			||||||
 | 
					    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("setsockopt: %s\n", strerror(errno));
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bind(fd, res->ai_addr, res->ai_addrlen) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("bind: %s\n", strerror(errno));
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    freeaddrinfo(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LOG_INFO("opened discovery socket on port %u\n", discovery_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,33 +0,0 @@
 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
helpers::open_tcp_connection(char *host, char *port)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int s, status;
 | 
					 | 
				
			||||||
    struct addrinfo hints{}, *res;
 | 
					 | 
				
			||||||
    memset(&hints, 0, sizeof hints);
 | 
					 | 
				
			||||||
    hints.ai_family = AF_INET;
 | 
					 | 
				
			||||||
    hints.ai_socktype = SOCK_STREAM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((status = getaddrinfo(host, port, &hints, &res)) != 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error getting address info: " << gai_strerror(status);
 | 
					 | 
				
			||||||
        freeaddrinfo(res);
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //creating Socket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((status = connect(s, res->ai_addr, res->ai_addrlen)) != 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error opening connection " << status;
 | 
					 | 
				
			||||||
        freeaddrinfo(res);
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    freeaddrinfo(res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return s;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										62
									
								
								helpers/parse_cli.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								helpers/parse_cli.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,62 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <argparse.h>
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const usage[] = {
 | 
				
			||||||
 | 
					    "controller [options] [[--] args]",
 | 
				
			||||||
 | 
					    "controller [options]",
 | 
				
			||||||
 | 
					    NULL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PERM_READ  (1<<0)
 | 
				
			||||||
 | 
					#define PERM_WRITE (1<<1)
 | 
				
			||||||
 | 
					#define PERM_EXEC  (1<<2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					helper_parse_cli(int argc, const char **argv, config_t *config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct argparse_option options[] =
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        OPT_HELP(),
 | 
				
			||||||
 | 
					        OPT_GROUP("Basic options"),
 | 
				
			||||||
 | 
					        OPT_STRING('c', "config", &config->file, "path to config file", NULL, 0, OPT_NONEG),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        OPT_END(),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct argparse argparse;
 | 
				
			||||||
 | 
					    argparse_init(&argparse, options, usage, 0);
 | 
				
			||||||
 | 
					    argparse_describe(
 | 
				
			||||||
 | 
					            &argparse,
 | 
				
			||||||
 | 
					            "\nA brief description of what the program does and how it works.",
 | 
				
			||||||
 | 
					            "\nAdditional description of the program after the description of the arguments."
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    argc = argparse_parse(&argparse, argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(argc == 1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(strcmp(argv[0], "start") == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config->run_type = RUN_TYPE_START;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(strcmp(argv[0], "test") == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config->run_type = RUN_TYPE_TEST;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        LOG_FATAL("bad action '%s' given ('start', 'test')\n", argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("no action given ('start', 'test')\n");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,68 +0,0 @@
 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <drogon/drogon.h>
 | 
					 | 
				
			||||||
#include <models/period_list.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
parse_HHMM(const char *begin, uint16_t *h, uint16_t *m)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uint16_t tmp_h, tmp_m;
 | 
					 | 
				
			||||||
    char *check = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tmp_h = (uint16_t)strtol(begin, &check, 10);
 | 
					 | 
				
			||||||
    if(begin == check)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    begin = check + 1;
 | 
					 | 
				
			||||||
    tmp_m = (uint16_t)strtol(begin, &check, 10);
 | 
					 | 
				
			||||||
    if(begin == check)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    *h = tmp_h;
 | 
					 | 
				
			||||||
    *m = tmp_m;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
period_list*
 | 
					 | 
				
			||||||
helpers::parse_periods(Json::Value periods_json)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto result = new period_list();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (Json::Value::ArrayIndex i = 0; i != periods_json.size(); i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Json::Value p = periods_json[i];
 | 
					 | 
				
			||||||
        if(!(p.isMember("start") && p.isMember("end")))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        const char *start_str = p["start"].asCString();
 | 
					 | 
				
			||||||
        const char *end_str = p["end"].asCString();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint16_t h, m, start, end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(parse_HHMM(start_str, &h, &m))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        start = (uint16_t)((h * 60) + m);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(parse_HHMM(end_str, &h, &m))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        end = (uint16_t)((h * 60) + m);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(start < 0 || start > 24 * 60 || end < 0 || end > 24 * 60)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        result->add_period(start, end);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,39 +0,0 @@
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
helpers::send_udp_broadcast(const char *addr, uint16_t port, const char* message)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct sockaddr_in their_addr{};
 | 
					 | 
				
			||||||
    int fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error creating socket";
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int broadcast = 1;
 | 
					 | 
				
			||||||
    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) < 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error setting broadcast";
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memset(&their_addr, 0, sizeof(their_addr));
 | 
					 | 
				
			||||||
    their_addr.sin_family = AF_INET;
 | 
					 | 
				
			||||||
    their_addr.sin_port = htons(port);
 | 
					 | 
				
			||||||
    their_addr.sin_addr.s_addr = inet_addr(addr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(sendto(fd, message, strlen(message), 0, (struct sockaddr *)&their_addr, sizeof(their_addr)) < 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Error sending broadcast " << errno << " " << strerror(errno);
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    close(fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										18
									
								
								include/colors.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								include/colors.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					#ifndef CORE_COLORS_H
 | 
				
			||||||
 | 
					#define CORE_COLORS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COLOR_RED "\033[0;31m"
 | 
				
			||||||
 | 
					#define COLORB_RED "\033[1;31m"
 | 
				
			||||||
 | 
					#define COLOR_GREEN "\033[0;32m"
 | 
				
			||||||
 | 
					#define COLORB_GREEN "\033[1;32m"
 | 
				
			||||||
 | 
					#define COLOR_YELLOW "\033[0;33m"
 | 
				
			||||||
 | 
					#define COLORB_YELLOW "\033[1;33m"
 | 
				
			||||||
 | 
					#define COLOR_BLUE "\033[0;34m"
 | 
				
			||||||
 | 
					#define COLORB_BLUE "\033[1;34m"
 | 
				
			||||||
 | 
					#define COLOR_MAGENTA "\033[0;35m"
 | 
				
			||||||
 | 
					#define COLORB_MAGENTA "\033[1;35m"
 | 
				
			||||||
 | 
					#define COLOR_CYAN "\033[0;36m"
 | 
				
			||||||
 | 
					#define COLORB_CYAN "\033[1;36m"
 | 
				
			||||||
 | 
					#define COLOR_NONE "\033[0m"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //CORE_COLORS_H
 | 
				
			||||||
							
								
								
									
										24
									
								
								include/config.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								include/config.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#ifndef CORE_CONFIG_H
 | 
				
			||||||
 | 
					#define CORE_CONFIG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <confini.h>
 | 
				
			||||||
 | 
					#include <enums.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *file;
 | 
				
			||||||
 | 
					    char *database;
 | 
				
			||||||
 | 
					    log_level_t log_level;
 | 
				
			||||||
 | 
					    run_type_t run_type;
 | 
				
			||||||
 | 
					    char server_port[6];
 | 
				
			||||||
 | 
					    uint16_t discovery_port;
 | 
				
			||||||
 | 
					} config_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern config_t global_config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					config_load(IniDispatch *disp, void *config_void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_CONFIG_H */
 | 
				
			||||||
							
								
								
									
										31
									
								
								include/constants.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								include/constants.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					#ifndef CORE_CONTANTS_H
 | 
				
			||||||
 | 
					#define CORE_CONTANTS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SECONDS_PER_DAY 86400 // 60 * 60 * 24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SECONDS_PER_MINUTE 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define POLL_FDS_COUNT 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Limit the maximum length of a controller/relay/etc name
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The NULL terminator is not included. Arrays of length #MAX_NAME_LENGTH + 1 are required.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MAX_NAME_LENGTH 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Maximum number of dbs for the databases for the MDB_env
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Used when calling mdb_env_set_maxdbs() in database_setup()
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MDB_MAXDBS 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief How many milli seconds to wait until poll timeout in main loop
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ACCEPT_TIMEOUT_MSECONDS 1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PIFACE_GPIO_BASE 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_CONTANTS_H */
 | 
				
			||||||
							
								
								
									
										11
									
								
								include/database.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								include/database.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					#ifndef CORE_DATABASE_H
 | 
				
			||||||
 | 
					#define CORE_DATABASE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sqlite3.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern sqlite3 *global_database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					database_migrate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_DATABASE_H */
 | 
				
			||||||
							
								
								
									
										13
									
								
								include/drivers.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/drivers.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					#ifndef CORE_DRIVERS_H
 | 
				
			||||||
 | 
					#define CORE_DRIVERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					#include <enums.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					driver_piface_set(int pin, int value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					driver_gpio_set(int pin, int value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_DRIVERS_H */
 | 
				
			||||||
							
								
								
									
										15
									
								
								include/endpoints/api_v1_schedules.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								include/endpoints/api_v1_schedules.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ENDPOINTS_API_V1_SCHEDULES_H
 | 
				
			||||||
 | 
					#define CORE_ENDPOINTS_API_V1_SCHEDULES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_POST(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_ENDPOINTS_API_V1_SCHEDULES_H */
 | 
				
			||||||
							
								
								
									
										64
									
								
								include/enums.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								include/enums.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ENUMS_H
 | 
				
			||||||
 | 
					#define CORE_ENUMS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    POLL_FDS_DISCOVERY,
 | 
				
			||||||
 | 
					    POLL_FDS_COMMAND
 | 
				
			||||||
 | 
					} poll_fds_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_ID = 0,
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_NAME = 1,
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_COMMAND_PORT = 2,
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_RELAY_COUNT = 3,
 | 
				
			||||||
 | 
					} discovery_mapping_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    COMMAND_MAPPING_CODE = 0,
 | 
				
			||||||
 | 
					    COMMAND_MAPPING_NAME = 1,
 | 
				
			||||||
 | 
					    COMMAND_MAPPING_RELAY_NUM = 2,
 | 
				
			||||||
 | 
					    COMMAND_MAPPING_SCHEDULES_ARRAY = 3,
 | 
				
			||||||
 | 
					    COMMAND_MAPPING_SCHEDULE_ID = 4,
 | 
				
			||||||
 | 
					    COMMAND_MAPPING_PERIODS_COUNT = 5,
 | 
				
			||||||
 | 
					    COMMAND_MAPPING_PERIODS_BLOB = 6,
 | 
				
			||||||
 | 
					} control_mapping_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    COMMAND_CODE_GET_TIME = 1,
 | 
				
			||||||
 | 
					    COMMAND_CODE_GET_ID = 2,
 | 
				
			||||||
 | 
					    COMMAND_CODE_SET_NAME = 100,
 | 
				
			||||||
 | 
					    COMMAND_CODE_GET_NAME = 101,
 | 
				
			||||||
 | 
					    COMMAND_CODE_SET_SCHEDULE = 102,
 | 
				
			||||||
 | 
					    COMMAND_CODE_GET_SCHEDULE = 103,
 | 
				
			||||||
 | 
					    COMMAND_CODE_SET_RELAY_NAME = 104,
 | 
				
			||||||
 | 
					    COMMAND_CODE_GET_RELAY_NAME = 105,
 | 
				
			||||||
 | 
					} command_code_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    RELAY_DRIVER_NONE,
 | 
				
			||||||
 | 
					    RELAY_DRIVER_GPIO,
 | 
				
			||||||
 | 
					    RELAY_DRIVER_PIFACE,
 | 
				
			||||||
 | 
					} relay_driver_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    RUN_TYPE_START,
 | 
				
			||||||
 | 
					    RUN_TYPE_TEST,
 | 
				
			||||||
 | 
					} run_type_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LOG_LEVEL_TRACE = 5,
 | 
				
			||||||
 | 
					    LOG_LEVEL_DEBUG = 4,
 | 
				
			||||||
 | 
					    LOG_LEVEL_INFO  = 3,
 | 
				
			||||||
 | 
					    LOG_LEVEL_WARN  = 2,
 | 
				
			||||||
 | 
					    LOG_LEVEL_ERROR = 1,
 | 
				
			||||||
 | 
					    LOG_LEVEL_FATAL = 0,
 | 
				
			||||||
 | 
					} log_level_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_ENUMS_H */
 | 
				
			||||||
							
								
								
									
										7
									
								
								include/handlers.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								include/handlers.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#ifndef CORE_HANDLERS_H
 | 
				
			||||||
 | 
					#define CORE_HANDLERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					handler_connection(struct mg_connection *c, int ev, void *p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_HANDLERS_H */
 | 
				
			||||||
							
								
								
									
										34
									
								
								include/helpers.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								include/helpers.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					#ifndef CORE_HELPERS_H
 | 
				
			||||||
 | 
					#define CORE_HELPERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#include <confini.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_connect_tcp_server(char* host, uint16_t port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_bind_tcp_server(char* addr, uint16_t port, int max_client_backlog);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t
 | 
				
			||||||
 | 
					helper_get_port(int sock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Open socket for discovery
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Will exit program when unable to open socket.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param discovery_port Port number to listen on for discovery broadcasts
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return Open socket to accept discovery broadcasts on
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_open_discovery_socket(uint16_t discovery_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					helper_parse_cli(int argc, const char **argv, config_t *config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_get_weekday(const time_t timestamp_now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_HELPERS_H */
 | 
				
			||||||
							
								
								
									
										21
									
								
								include/logger.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								include/logger.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					#ifndef CORE_LOGGER_H
 | 
				
			||||||
 | 
					#define CORE_LOGGER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <colors.h>
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					logger_log(FILE *stream, log_level_t level, const char *filename, int line, const char *func, const char *msg, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_TRACE(...) logger_log(stdout, LOG_LEVEL_TRACE, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define LOG_DEBUG(...) logger_log(stdout, LOG_LEVEL_DEBUG, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define LOG_INFO(...)  logger_log(stdout, LOG_LEVEL_INFO , __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define LOG_WARN(...)  logger_log(stdout, LOG_LEVEL_WARN , __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define LOG_ERROR(...) logger_log(stderr, LOG_LEVEL_ERROR, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define LOG_FATAL(...) logger_log(stderr, LOG_LEVEL_FATAL, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //CORE_LOGGER_H
 | 
				
			||||||
							
								
								
									
										13
									
								
								include/macros.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/macros.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					#ifndef CORE_MACROS_H
 | 
				
			||||||
 | 
					#define CORE_MACROS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <colors.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SOURCE_PATH_SIZE
 | 
				
			||||||
 | 
					    #define SOURCE_PATH_SIZE 0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //CORE_MACROS_H
 | 
				
			||||||
							
								
								
									
										45
									
								
								include/models/controller.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/models/controller.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,45 @@
 | 
				
			||||||
 | 
					#ifndef CORE_MODELS_CONTROLLER_H
 | 
				
			||||||
 | 
					#define CORE_MODELS_CONTROLLER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <uuid/uuid.h>
 | 
				
			||||||
 | 
					#include <sqlite3.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uuid_t id;
 | 
				
			||||||
 | 
					    char name[128];
 | 
				
			||||||
 | 
					    char ip[17];
 | 
				
			||||||
 | 
					    int active;
 | 
				
			||||||
 | 
					    int port;
 | 
				
			||||||
 | 
					    int relay_count;
 | 
				
			||||||
 | 
					    relay_t **relays;
 | 
				
			||||||
 | 
					} controller_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					controller_free(controller_t* contoller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					controller_save(controller_t* contoller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					controller_remove(controller_t* contoller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char*
 | 
				
			||||||
 | 
					controller_to_json(controller_t* contoller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					controller_t**
 | 
				
			||||||
 | 
					controller_get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					controller_t**
 | 
				
			||||||
 | 
					controller_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					controller_command(int command_code, char *payload, uint32_t payload_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					controller_free_list(controller_t **controllers_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_MODELS_CONTROLLER_H */
 | 
				
			||||||
							
								
								
									
										19
									
								
								include/models/junction_relay_schedule.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								include/models/junction_relay_schedule.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					#ifndef CORE_MODELS_JUNCTION_RELAY_SCHEDULE_H
 | 
				
			||||||
 | 
					#define CORE_MODELS_JUNCTION_RELAY_SCHEDULE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_get_schedule_id(uint8_t weekday, int relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_insert(uint8_t weekday, int relay_id, int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_remove(uint8_t weekday, int relay_id, int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_remove_for_relay(int relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_remove_for_schedule(int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_MODELS_JUNCTION_RELAY_SCHEDULE_H */
 | 
				
			||||||
							
								
								
									
										32
									
								
								include/models/junction_tag.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								include/models/junction_tag.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					#ifndef CORE_MODELS_JUNCTION_TAG_H
 | 
				
			||||||
 | 
					#define CORE_MODELS_JUNCTION_TAG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_relays_for_tag_id(int tag_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_schedules_for_tag_id(int tag_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_tags_for_relay_id(int relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_tags_for_schedule_id(int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_insert(int tag_id, int relay_id, int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove(int tag_id, int relay_id, int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove_for_tag(int tag_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove_for_relay(int relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove_for_schedule(int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_MODELS_JUNCTION_TAG_H */
 | 
				
			||||||
							
								
								
									
										21
									
								
								include/models/period.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								include/models/period.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					#ifndef CORE_PERIOD_H
 | 
				
			||||||
 | 
					#define CORE_PERIOD_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16_t start;
 | 
				
			||||||
 | 
					    uint16_t end;
 | 
				
			||||||
 | 
					} period_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					period_t*
 | 
				
			||||||
 | 
					period_create(uint16_t start, uint16_t end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					period_includes_time(period_t *period, uint16_t timestamp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					period_helper_parse_hhmm(const char *hhmm_str, uint16_t *hhmm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_PERIOD_H */
 | 
				
			||||||
							
								
								
									
										49
									
								
								include/models/relay.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								include/models/relay.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					#ifndef CORE_RELAY_H
 | 
				
			||||||
 | 
					#define CORE_RELAY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <uuid/uuid.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					#include <models/schedule.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int id;
 | 
				
			||||||
 | 
					    char name[128];
 | 
				
			||||||
 | 
					    int number;
 | 
				
			||||||
 | 
					    uuid_t controller_id;
 | 
				
			||||||
 | 
					    int active_schedule_id;
 | 
				
			||||||
 | 
					    schedule_t *active_schedule;
 | 
				
			||||||
 | 
					    schedule_t *schedules[7];
 | 
				
			||||||
 | 
					} relay_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					relay_save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					relay_remove();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char*
 | 
				
			||||||
 | 
					relay_to_json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					relay_free_list(relay_t **relays_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t*
 | 
				
			||||||
 | 
					relay_get_by_id(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t*
 | 
				
			||||||
 | 
					relay_get_relay_for_controller(uuid_t controller_id, int relay_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					relay_valid_num_is_for_controller(uuid_t controller_id, int relay_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_RELAY_H */
 | 
				
			||||||
							
								
								
									
										58
									
								
								include/models/schedule.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								include/models/schedule.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,58 @@
 | 
				
			||||||
 | 
					#ifndef CORE_SCHEDULE_H
 | 
				
			||||||
 | 
					#define CORE_SCHEDULE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <uuid/uuid.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <models/period.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int id;
 | 
				
			||||||
 | 
					    uuid_t uid;
 | 
				
			||||||
 | 
					    char name[MAX_NAME_LENGTH + 1];
 | 
				
			||||||
 | 
					    uint16_t periods_count;
 | 
				
			||||||
 | 
					    period_t *periods;
 | 
				
			||||||
 | 
					} schedule_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_save(schedule_t *schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_remove(schedule_t *schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule_free(schedule_t *schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule_free_list(schedule_t **schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON*
 | 
				
			||||||
 | 
					schedule_to_json(schedule_t *schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule_free_list(schedule_t **schedules_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t*
 | 
				
			||||||
 | 
					schedule_periods_to_blob(schedule_t *schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t**
 | 
				
			||||||
 | 
					schedule_get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_id_or_off(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_id(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t**
 | 
				
			||||||
 | 
					schedule_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_uid_parse(const char *uid_str, uuid_t result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule_uid_unparse(const uuid_t uid, char *result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_SCHEDULE_H */
 | 
				
			||||||
							
								
								
									
										17
									
								
								include/models/tag.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								include/models/tag.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#ifndef CORE_MODELS_TAG_H
 | 
				
			||||||
 | 
					#define CORE_MODELS_TAG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					tag_save(int id, const char *tag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					tag_remove(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char*
 | 
				
			||||||
 | 
					tag_get_tag(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					tag_get_id(const char* tag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_MODELS_TAG_H */
 | 
				
			||||||
							
								
								
									
										52
									
								
								include/router.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								include/router.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,52 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ROUTER_H
 | 
				
			||||||
 | 
					#define CORE_ROUTER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mongoose.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ENDPOINTS_MAX_COUNT 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ENDPOINT_ARG_TYPE_INT,
 | 
				
			||||||
 | 
					    ENDPOINT_ARG_TYPE_STR
 | 
				
			||||||
 | 
					} endpoint_arg_type_e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    endpoint_arg_type_e type;
 | 
				
			||||||
 | 
					    union
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int v_int;
 | 
				
			||||||
 | 
					        char *v_str;
 | 
				
			||||||
 | 
					    } value;
 | 
				
			||||||
 | 
					} endpoint_args_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void (*endpoint_func_f)(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char **route;
 | 
				
			||||||
 | 
					    char *route_keeper;
 | 
				
			||||||
 | 
					    int methods;
 | 
				
			||||||
 | 
					    endpoint_func_f func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int args_count;
 | 
				
			||||||
 | 
					    endpoint_args_t *args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int possible_route;
 | 
				
			||||||
 | 
					    int args_found;
 | 
				
			||||||
 | 
					} endpoint_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					router_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					router_register_endpoint(const char *route, int methods, endpoint_func_f func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endpoint_t*
 | 
				
			||||||
 | 
					router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					router_free();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_ROUTER_H */
 | 
				
			||||||
							
								
								
									
										59
									
								
								logger.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								logger.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COLOR_TRACE COLOR_GREEN
 | 
				
			||||||
 | 
					#define COLOR_DEBUG COLOR_BLUE
 | 
				
			||||||
 | 
					#define COLOR_INFO COLOR_CYAN
 | 
				
			||||||
 | 
					#define COLOR_WARN COLOR_YELLOW
 | 
				
			||||||
 | 
					#define COLOR_ERROR COLOR_RED
 | 
				
			||||||
 | 
					#define COLOR_FATAL COLOR_MAGENTA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					logger_log(FILE *stream, log_level_t level, const char *filename, int line, const char *func, const char *msg, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(global_config.log_level < level)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(level)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case LOG_LEVEL_TRACE:
 | 
				
			||||||
 | 
					            fprintf(stream, COLOR_TRACE "[TRACE] ");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case LOG_LEVEL_DEBUG:
 | 
				
			||||||
 | 
					            fprintf(stream, COLOR_DEBUG "[DEBUG] ");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case LOG_LEVEL_INFO:
 | 
				
			||||||
 | 
					            fprintf(stream, COLOR_INFO  "[INFO ] ");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case LOG_LEVEL_WARN:
 | 
				
			||||||
 | 
					            fprintf(stream, COLOR_WARN  "[WARN ] ");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case LOG_LEVEL_ERROR:
 | 
				
			||||||
 | 
					            fprintf(stream, COLOR_ERROR "[ERROR] ");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case LOG_LEVEL_FATAL:
 | 
				
			||||||
 | 
					            fprintf(stream, COLOR_FATAL "[FATAL] ");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            fprintf(stream, COLOR_NONE  "[LOG  ] ");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char timestamp_str[32];
 | 
				
			||||||
 | 
					    time_t rawtime;
 | 
				
			||||||
 | 
					    time(&rawtime);
 | 
				
			||||||
 | 
					    strftime(timestamp_str, 32, "%Y-%m-%d %H:%M:%S", localtime(&rawtime));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fprintf(stream, "%s %s:%d:%s " COLOR_NONE, timestamp_str, filename, line, func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    va_list args;
 | 
				
			||||||
 | 
					    va_start(args, msg);
 | 
				
			||||||
 | 
					    vfprintf(stream, msg, args);
 | 
				
			||||||
 | 
					    va_end(args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										107
									
								
								main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								main.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mongoose.h>
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					#include <handlers.h>
 | 
				
			||||||
 | 
					#include <enums.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					#include <confini.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct mg_mgr mgr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					terminate(int signum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LOG_INFO("terminating controller (%d)\n", signum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mg_mgr_free(&mgr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_close(global_database);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(global_config.database);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    router_free();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exit(signum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief The main function
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param argc UNUSED
 | 
				
			||||||
 | 
					 * @param argv UNUSED
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return Statuscode to indicate success (0) or failure (!0)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, const char** argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    signal(SIGINT, terminate);
 | 
				
			||||||
 | 
					    signal(SIGABRT, terminate);
 | 
				
			||||||
 | 
					    signal(SIGTERM, terminate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /******************** LOAD CONFIG ********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global_config.file = "core.ini";
 | 
				
			||||||
 | 
					    global_config.log_level = LOG_LEVEL_INFO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    helper_parse_cli(argc, argv, &global_config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FILE * const ini_file = fopen(global_config.file, "rb");
 | 
				
			||||||
 | 
					    if(ini_file == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("config file '%s' was not found\n", global_config.file);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(load_ini_file( ini_file, INI_DEFAULT_FORMAT, NULL, config_load, &global_config))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("unable to parse ini file\n");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fclose(ini_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /******************** SETUP DATABASE ********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int rc = sqlite3_open(global_config.database, &global_database);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(rc) {
 | 
				
			||||||
 | 
					        LOG_FATAL("can't open database: %s\n", sqlite3_errmsg(global_database));
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(database_migrate())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        terminate(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /******************** INIT ROUTER ********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    router_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /******************** START MAIN LOOP ********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct mg_connection *c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mg_mgr_init(&mgr, NULL);
 | 
				
			||||||
 | 
					    c = mg_bind(&mgr, global_config.server_port, handler_connection);
 | 
				
			||||||
 | 
					    mg_set_protocol_http_websocket(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mg_mgr_poll(&mgr, 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    terminate(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										68
									
								
								main.cc
									
										
									
									
									
								
							
							
						
						
									
										68
									
								
								main.cc
									
										
									
									
									
								
							| 
						 | 
					@ -1,68 +0,0 @@
 | 
				
			||||||
#include <drogon/drogon.h>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <models/controller_dbo.h>
 | 
					 | 
				
			||||||
#include <csignal>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
add_cors_headers(const drogon::HttpRequestPtr &requestPtr, const drogon::HttpResponsePtr &responsePtr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    responsePtr->addHeader("Access-Control-Allow-Origin", "*");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
terminate(int signum)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    LOG_INFO << "Terminating Server (" << signum << ")";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_close(globals::db);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    quick_exit(signum);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*static void test()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    LOG_DEBUG << "LOOP";
 | 
					 | 
				
			||||||
}*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    signal(SIGINT, terminate);
 | 
					 | 
				
			||||||
    signal(SIGABRT, terminate);
 | 
					 | 
				
			||||||
    signal(SIGTERM, terminate);
 | 
					 | 
				
			||||||
    signal(SIGKILL, terminate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Open database */
 | 
					 | 
				
			||||||
    rc = sqlite3_open("core.sqlite", &globals::db);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if( rc ) {
 | 
					 | 
				
			||||||
        LOG_FATAL << "Can't open database: " << sqlite3_errmsg(globals::db);
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!helpers::migrate_sql())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        terminate(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Load config file
 | 
					 | 
				
			||||||
    drogon::app().loadConfigFile("config.json");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    drogon::app().registerPostHandlingAdvice(add_cors_headers);
 | 
					 | 
				
			||||||
    drogon::app().instance().setCustom404Page(drogon::HttpResponse::newFileResponse("./static/index.html", "", drogon::CT_TEXT_HTML));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //drogon::app().getLoop()->runEvery(1, &test);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Run HTTP framework,the method will block in the internal event loop
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LOG_INFO << "Starting Emgauwa Core (" << config::version << ")";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    drogon::app().run();
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,246 +0,0 @@
 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "controller_dbo.h"
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
controller_dbo::~controller_dbo()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(this->relays)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        relay_dbo::free_list(this->relays);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool controller_db_update_insert(controller_dbo *controller, sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 1, controller->id, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 2, controller->name, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 3, controller->ip, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 4, controller->active);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 5, controller->port);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 6, controller->relay_count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    if (rc != SQLITE_DONE)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        printf("ERROR inserting data: %s\n", sqlite3_errmsg(globals::db));
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static controller_dbo*
 | 
					 | 
				
			||||||
controller_db_select_mapper(sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto *new_controller = new controller_dbo();
 | 
					 | 
				
			||||||
    for(int i = 0; i < sqlite3_column_count(stmt); i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        const char *name = sqlite3_column_name(stmt, i);
 | 
					 | 
				
			||||||
        switch(name[0])
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            case 'a': // active
 | 
					 | 
				
			||||||
                new_controller->active = (bool)sqlite3_column_int(stmt, i);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'i':
 | 
					 | 
				
			||||||
                switch(name[1])
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case 'd': // id
 | 
					 | 
				
			||||||
                        strncpy(new_controller->id, (const char*)sqlite3_column_text(stmt, i), 32);
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case 'p': // ip
 | 
					 | 
				
			||||||
                        strncpy(new_controller->ip, (const char*)sqlite3_column_text(stmt, i), 16);
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    default: // ignore columns not implemented
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'n': // name
 | 
					 | 
				
			||||||
                strncpy(new_controller->name, (const char*)sqlite3_column_text(stmt, i), 127);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'p': // port
 | 
					 | 
				
			||||||
                new_controller->port = sqlite3_column_int(stmt, i);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'r': // relay_count
 | 
					 | 
				
			||||||
                new_controller->relay_count = sqlite3_column_int(stmt, i);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default: // ignore columns not implemented
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return new_controller;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static controller_dbo**
 | 
					 | 
				
			||||||
controller_db_select(sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto **all_controllers = (controller_dbo**)malloc(sizeof(controller_dbo*));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int row = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while(true)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int s;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        s = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
        if (s == SQLITE_ROW)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            controller_dbo *new_controller = controller_db_select_mapper(stmt);
 | 
					 | 
				
			||||||
            new_controller->relays = relay_dbo::get_by_simple("controller_id", new_controller->id, (intptr_t)&sqlite3_bind_text);
 | 
					 | 
				
			||||||
            row++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            all_controllers = (controller_dbo**)realloc(all_controllers, sizeof(controller_dbo*) * (row + 1));
 | 
					 | 
				
			||||||
            all_controllers[row - 1] = new_controller;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (s == SQLITE_DONE)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Selecting controllers from database";
 | 
					 | 
				
			||||||
                sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
                return nullptr;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
    all_controllers[row] = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return all_controllers;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
controller_dbo::update()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "UPDATE controllers set name = ?2, ip = ?3, active = ?4, port = ?5, relay_count = ?6 WHERE id = ?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return controller_db_update_insert(this, stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
controller_dbo::insert()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "INSERT INTO controllers(id, name, ip, active, port, relay_count) values (?1, ?2, ?3, ?4, ?5, ?6);", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return controller_db_update_insert(this, stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
controller_dbo::remove()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM controllers WHERE id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 1, this->id, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Json::Value
 | 
					 | 
				
			||||||
controller_dbo::to_json()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value controller_json;
 | 
					 | 
				
			||||||
    controller_json["name"] = this->name;
 | 
					 | 
				
			||||||
    controller_json["id"] = this->id;
 | 
					 | 
				
			||||||
    controller_json["ip"] = this->ip;
 | 
					 | 
				
			||||||
    //controller_json["port"] = this->port;
 | 
					 | 
				
			||||||
    controller_json["relay_count"] = this->relay_count;
 | 
					 | 
				
			||||||
    controller_json["active"] = this->active;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    controller_json["relays"] = Json::arrayValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; this->relays[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        controller_json["relays"].append(this->relays[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return controller_json;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
controller_dbo**
 | 
					 | 
				
			||||||
controller_dbo::get_all()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT * FROM controllers;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return controller_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
controller_dbo**
 | 
					 | 
				
			||||||
controller_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder *filters[1];
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                    key,
 | 
					 | 
				
			||||||
                    value,
 | 
					 | 
				
			||||||
                    bind_func,
 | 
					 | 
				
			||||||
                    ";"
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
    filters[0] = &filter;
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt = helpers::create_sql_filtered_query("SELECT * FROM controllers WHERE", filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return controller_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
controller_dbo**
 | 
					 | 
				
			||||||
controller_dbo::get_by(helpers::sql_filter_builder **filters)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt = helpers::create_sql_filtered_query("SELECT * FROM controllers WHERE", filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return controller_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
controller_dbo::command(int command_code, const char *payload)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    char port_str[6];
 | 
					 | 
				
			||||||
    sprintf(port_str, "%d", this->port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int controller_socket = helpers::open_tcp_connection(this->ip, port_str);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!controller_socket)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Can't open command socket " << this->ip << ":" << port_str;
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LOG_DEBUG << "Commanding (" << command_code << ") " << payload;
 | 
					 | 
				
			||||||
    send(controller_socket, &command_code, 1, 0);
 | 
					 | 
				
			||||||
    send(controller_socket, payload, strlen(payload), 0);
 | 
					 | 
				
			||||||
    close(controller_socket);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
controller_dbo::free_list(controller_dbo **controllers_list)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    for(int i = 0; controllers_list[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        delete controllers_list[i];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    free(controllers_list);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,53 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_controller_DBO_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_controller_DBO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "relay_dbo.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class controller_dbo
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char id[33];
 | 
					 | 
				
			||||||
    char name[128];
 | 
					 | 
				
			||||||
    char ip[17];
 | 
					 | 
				
			||||||
    bool active;
 | 
					 | 
				
			||||||
    int port;
 | 
					 | 
				
			||||||
    int relay_count;
 | 
					 | 
				
			||||||
    relay_dbo **relays;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ~controller_dbo();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    update();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    insert();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value
 | 
					 | 
				
			||||||
    to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static controller_dbo**
 | 
					 | 
				
			||||||
    get_by_simple(const char *key, const void *value, intptr_t bind_func);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static controller_dbo**
 | 
					 | 
				
			||||||
    get_by(helpers::sql_filter_builder **filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static controller_dbo**
 | 
					 | 
				
			||||||
    get_all();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    command(int command_code, const char *payload);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static void
 | 
					 | 
				
			||||||
    free_list(controller_dbo **controllers_list);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_controller_DBO_H
 | 
					 | 
				
			||||||
							
								
								
									
										114
									
								
								models/junction_relay_schedule.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								models/junction_relay_schedule.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,114 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <models/junction_relay_schedule.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_insert(uint8_t weekday, int relay_id, int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "INSERT INTO junction_relay_schedule(weekday, schedule_id, relay_id) values (?1, ?2, ?3);", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, weekday);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 2, schedule_id);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 3, relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    if (rc != SQLITE_DONE)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error inserting data: %s", sqlite3_errmsg(global_database));
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_get_schedule_id(uint8_t weekday, int relay_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int result = 0;
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT schedule_id FROM junction_relay_schedule WHERE weekday=?1 AND relay_id=?2 LIMIT 1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, weekday);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 2, relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					        if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            result = sqlite3_column_int(stmt, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (s == SQLITE_DONE)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error reading from database: %s", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_remove(uint8_t weekday, int relay_id, int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM junction_relay_schedule WHERE weekday=?1 AND schedule_id=?2 AND relay_id=?3;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, weekday);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 2, schedule_id);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 3, relay_id);
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_remove_for_relay(int relay_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM junction_relay_schedule WHERE relay_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, relay_id);
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_remove_for_schedule(int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM junction_relay_schedule WHERE schedule_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										175
									
								
								models/junction_tag.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								models/junction_tag.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,175 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sqlite3.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_insert(int tag_id, int relay_id, int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "INSERT INTO junction_tag(tag_id, schedule_id, relay_id) values (?1, ?2, ?3);", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, tag_id);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 2, schedule_id);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 3, relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    if (rc != SQLITE_DONE)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("ERROR inserting data: %s\n", sqlite3_errmsg(global_database));
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int*
 | 
				
			||||||
 | 
					get_ids(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int *ids = malloc(sizeof(int));
 | 
				
			||||||
 | 
					    int new_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int row = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					        if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            new_id = sqlite3_column_int(stmt, 0);
 | 
				
			||||||
 | 
					            row++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ids = (int*)realloc(ids, sizeof(int) * (row + 1));
 | 
				
			||||||
 | 
					            ids[row - 1] = new_id;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (s == SQLITE_DONE)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error selecting relays from database: %s\n", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					                return NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					    ids[row] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ids;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_relays_for_tag_id(int tag_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT relay_id FROM junction_tag WHERE tag_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, tag_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return get_ids(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_schedules_for_tag_id(int tag_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT schedule_id FROM junction_tag WHERE tag_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, tag_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return get_ids(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_tags_for_relay_id(int relay_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT tag_id FROM junction_tag WHERE relay_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return get_ids(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_tag_get_tags_for_schedule_id(int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT tag_id FROM junction_tag WHERE schedule_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return get_ids(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove(int tag_id, int relay_id, int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM junction_tag WHERE tag_id=?1 AND schedule_id=?2 AND relay_id=?3;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, tag_id);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 2, schedule_id);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 3, relay_id);
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove_for_tag(int tag_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM junction_tag WHERE tag_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, tag_id);
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove_for_relay(int relay_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM junction_tag WHERE relay_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, relay_id);
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_tag_remove_for_schedule(int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM junction_tag WHERE schedule_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										37
									
								
								models/period.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								models/period.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <models/period.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					period_helper_parse_hhmm(const char *hhmm_str, uint16_t *hhmm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(strlen(hhmm_str) != 5)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(hhmm_str[2] != ':')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for(int i = 0; i < 5; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(i != 2)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(hhmm_str[i] < '0' || hhmm_str[i] > '9')
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t tmp_h, tmp_m;
 | 
				
			||||||
 | 
					    tmp_h = (uint16_t)strtol(&hhmm_str[0], NULL, 10);
 | 
				
			||||||
 | 
					    tmp_m = (uint16_t)strtol(&hhmm_str[3], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *hhmm = (tmp_h * 60) + tmp_m;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,39 +0,0 @@
 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include "period.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
period::period(uint16_t start, uint16_t end)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->start = start;
 | 
					 | 
				
			||||||
    this->end = end;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Json::Value
 | 
					 | 
				
			||||||
period::to_json()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char start_str[8], end_str[8];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sprintf(start_str, "%02d:%02d", this->start / 60, this->start % 60);
 | 
					 | 
				
			||||||
    sprintf(end_str, "%02d:%02d", this->end / 60, this->end % 60);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    result["start"] = std::string(start_str);
 | 
					 | 
				
			||||||
    result["end"] = std::string(end_str);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
period::is_in_period(uint16_t timestamp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(this->start < this->end)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return this->start <= timestamp and timestamp <= this->end;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if(this->start > this->end)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return this->end <= timestamp and timestamp <= this->start;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return this->start == timestamp;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_PERIOD_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_PERIOD_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <json/json.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class period
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    uint16_t start;
 | 
					 | 
				
			||||||
    uint16_t end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    period(uint16_t start, uint16_t end);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value
 | 
					 | 
				
			||||||
    to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    is_in_period(uint16_t timestamp);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_PERIOD_H
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,70 +0,0 @@
 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <cstdlib>
 | 
					 | 
				
			||||||
#include "period_list.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
period_list::period_list()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->periods = (period**)malloc(0);
 | 
					 | 
				
			||||||
    this->length = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
period_list::period_list(const uint16_t* periods_blob)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->length = periods_blob[0];
 | 
					 | 
				
			||||||
    this->periods = (period**)malloc(sizeof(period*) * this->length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; i < length; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto new_period = new period(periods_blob[(i * 2) + 1], periods_blob[(i * 2) + 2]);
 | 
					 | 
				
			||||||
        periods[i] = new_period;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
period_list::period_list(period **periods, uint16_t length)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->periods = periods;
 | 
					 | 
				
			||||||
    this->length = length;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
period_list::~period_list()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    for(int i = 0; i < length; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        delete this->periods[i];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    free(this->periods);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
period_list::add_period(uint16_t start, uint16_t end)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->length++;
 | 
					 | 
				
			||||||
    this->periods = (period**)realloc(this->periods, sizeof(period*) * this->length);
 | 
					 | 
				
			||||||
    this->periods[this->length - 1] = new period(start, end);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Json::Value
 | 
					 | 
				
			||||||
period_list::to_json()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value result(Json::arrayValue);
 | 
					 | 
				
			||||||
    for(int i = 0; i < this->length; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        result.append(this->periods[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint16_t*
 | 
					 | 
				
			||||||
period_list::to_db_blob()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto result = (uint16_t*)malloc(sizeof(uint16_t) * ((this->length * 2) + 1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    result[0] = this->length;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; i < this->length; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        result[(i * 2) + 1] = this->periods[i]->start;
 | 
					 | 
				
			||||||
        result[(i * 2) + 2] = this->periods[i]->end;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,28 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_PERIOD_LIST_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_PERIOD_LIST_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <json/json.h>
 | 
					 | 
				
			||||||
#include "period.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class period_list
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    period **periods;
 | 
					 | 
				
			||||||
    uint16_t length;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    period_list();
 | 
					 | 
				
			||||||
    explicit period_list(const uint16_t *periods_blob);
 | 
					 | 
				
			||||||
    period_list(period **periods, uint16_t length);
 | 
					 | 
				
			||||||
    ~period_list();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void
 | 
					 | 
				
			||||||
    add_period(uint16_t start, uint16_t end);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value
 | 
					 | 
				
			||||||
    to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint16_t*
 | 
					 | 
				
			||||||
    to_db_blob();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_PERIOD_LIST_H
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,257 +0,0 @@
 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "relay_dbo.h"
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
#include "controller_dbo.h"
 | 
					 | 
				
			||||||
#include "schedule_dbo.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool relay_db_update_insert(relay_dbo *relay, sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, relay->id);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 2, relay->number);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 3, relay->name, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 4, relay->active_schedule_id, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 5, relay->controller_id, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    if (rc != SQLITE_DONE)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        printf("ERROR inserting data: %s\n", sqlite3_errmsg(globals::db));
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static relay_dbo*
 | 
					 | 
				
			||||||
relay_db_select_mapper(sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto *new_relay = new relay_dbo();
 | 
					 | 
				
			||||||
    for(int i = 0; i < sqlite3_column_count(stmt); i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        const char *name = sqlite3_column_name(stmt, i);
 | 
					 | 
				
			||||||
        switch(name[0])
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            case 'a': // active_schedule_id
 | 
					 | 
				
			||||||
                strncpy(new_relay->active_schedule_id, (const char*)sqlite3_column_text(stmt, i), 32);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'c': // controller_id
 | 
					 | 
				
			||||||
                strncpy(new_relay->controller_id, (const char*)sqlite3_column_text(stmt, i), 32);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'i':
 | 
					 | 
				
			||||||
                new_relay->id = sqlite3_column_int(stmt, i);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'n':
 | 
					 | 
				
			||||||
                switch(name[1])
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case 'a': // name
 | 
					 | 
				
			||||||
                        strncpy(new_relay->name, (const char*)sqlite3_column_text(stmt, i), 127);
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case 'u': // number
 | 
					 | 
				
			||||||
                        new_relay->number = sqlite3_column_int(stmt, i);
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    default:
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            default: // ignore columns not implemented
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return new_relay;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static relay_dbo**
 | 
					 | 
				
			||||||
relay_db_select(sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto **all_relays = (relay_dbo**)malloc(sizeof(relay_dbo*));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int row = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while(true)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int s;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        s = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
        if (s == SQLITE_ROW)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            relay_dbo *new_relay = relay_db_select_mapper(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new_relay->reload_active_schedule();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            row++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            all_relays = (relay_dbo**)realloc(all_relays, sizeof(relay_dbo*) * (row + 1));
 | 
					 | 
				
			||||||
            all_relays[row - 1] = new_relay;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (s == SQLITE_DONE)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Selecting relays from database: " << sqlite3_errstr(s);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
    all_relays[row] = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return all_relays;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
relay_dbo::reload_active_schedule()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    schedule_dbo **schedules = schedule_dbo::get_by_simple("id", this->active_schedule_id, (intptr_t)&sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!schedules[0])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        free(schedules);
 | 
					 | 
				
			||||||
        schedules = schedule_dbo::get_by_simple("id", "off", (intptr_t)&sqlite3_bind_text);
 | 
					 | 
				
			||||||
        strcpy(this->active_schedule_id, "off");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this->active_schedule = schedules[0];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    free(schedules);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
relay_dbo::update()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "UPDATE relays set number = ?2, name = ?3, active_schedule_id = ?4, controller_id = ?5 WHERE id = ?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return relay_db_update_insert(this, stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
relay_dbo::insert()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "INSERT INTO relays(number, name, active_schedule_id, controller_id) values (?2, ?3, ?4, ?5);", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return relay_db_update_insert(this, stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
relay_dbo::remove()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM relays WHERE id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, this->id);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Json::Value
 | 
					 | 
				
			||||||
relay_dbo::to_json()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value relay_json;
 | 
					 | 
				
			||||||
    // relay_json["id"] = this->id;
 | 
					 | 
				
			||||||
    relay_json["name"] = this->name;
 | 
					 | 
				
			||||||
    relay_json["number"] = this->number;
 | 
					 | 
				
			||||||
    relay_json["active_schedule_id"] = this->active_schedule_id;
 | 
					 | 
				
			||||||
    relay_json["controller_id"] = this->controller_id;
 | 
					 | 
				
			||||||
    relay_json["active_schedule"] = this->active_schedule->to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return relay_json;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
relay_dbo**
 | 
					 | 
				
			||||||
relay_dbo::get_all()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT * FROM relays;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return relay_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
relay_dbo**
 | 
					 | 
				
			||||||
relay_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder *filters[1];
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        key,
 | 
					 | 
				
			||||||
        value,
 | 
					 | 
				
			||||||
        bind_func,
 | 
					 | 
				
			||||||
        ";"
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    filters[0] = &filter;
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt = helpers::create_sql_filtered_query("SELECT * FROM relays WHERE", filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return relay_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
relay_dbo**
 | 
					 | 
				
			||||||
relay_dbo::get_by(helpers::sql_filter_builder **filters)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt = helpers::create_sql_filtered_query("SELECT * FROM relays WHERE", filters);
 | 
					 | 
				
			||||||
    return relay_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
relay_dbo*
 | 
					 | 
				
			||||||
relay_dbo::get_relay_for_controller(const char *controller_id, int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder *filters[2];
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter(
 | 
					 | 
				
			||||||
            "number",
 | 
					 | 
				
			||||||
            (void*)(intptr_t)relay_num,
 | 
					 | 
				
			||||||
            (intptr_t)&sqlite3_bind_int,
 | 
					 | 
				
			||||||
            "AND"
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter2(
 | 
					 | 
				
			||||||
            "controller_id",
 | 
					 | 
				
			||||||
            (void*)controller_id,
 | 
					 | 
				
			||||||
            (intptr_t)sqlite3_bind_text,
 | 
					 | 
				
			||||||
            ";"
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    filters[0] = &filter;
 | 
					 | 
				
			||||||
    filters[1] = &filter2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto relays = relay_dbo::get_by(filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    relay_dbo *relay = relays[0];
 | 
					 | 
				
			||||||
    free(relays);
 | 
					 | 
				
			||||||
    return relay;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
relay_dbo::valid_num_for_controller(const char *search_controller_id, int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", search_controller_id, (intptr_t)&sqlite3_bind_text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool valid_id_and_num = controllers[0] && controllers[0]->relay_count > relay_num;
 | 
					 | 
				
			||||||
    controller_dbo::free_list(controllers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return valid_id_and_num;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
relay_dbo::free_list(relay_dbo **relays_list)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    for(int i = 0; relays_list[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        delete relays_list[i];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    free(relays_list);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,56 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_RELAY_DBO_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_RELAY_DBO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "schedule_dbo.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class relay_dbo
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int id;
 | 
					 | 
				
			||||||
    char name[128];
 | 
					 | 
				
			||||||
    int number;
 | 
					 | 
				
			||||||
    char controller_id[33];
 | 
					 | 
				
			||||||
    char active_schedule_id[33];
 | 
					 | 
				
			||||||
    schedule_dbo *active_schedule;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void
 | 
					 | 
				
			||||||
    reload_active_schedule();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    update();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    insert();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value
 | 
					 | 
				
			||||||
    to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static void
 | 
					 | 
				
			||||||
    free_list(relay_dbo **relays_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo**
 | 
					 | 
				
			||||||
    get_by_simple(const char *key, const void *value, intptr_t bind_func);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo**
 | 
					 | 
				
			||||||
    get_by(helpers::sql_filter_builder **filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo*
 | 
					 | 
				
			||||||
    get_relay_for_controller(const char *controller_id, int relay_num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static bool
 | 
					 | 
				
			||||||
    valid_num_for_controller(const char *search_controller_id, int relay_num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo**
 | 
					 | 
				
			||||||
    get_all();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_RELAY_DBO_H
 | 
					 | 
				
			||||||
							
								
								
									
										325
									
								
								models/schedule.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								models/schedule.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,325 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sqlite3.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					#include <models/schedule.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					db_update_insert(schedule_t *schedule, sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					    uint16_t *periods_blob = schedule_periods_to_blob(schedule);
 | 
				
			||||||
 | 
					    int blob_size = (int)sizeof(uint16_t) * ((periods_blob[0] * 2) + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, schedule->id);
 | 
				
			||||||
 | 
					    sqlite3_bind_blob(stmt, 2, schedule->uid, sizeof(uuid_t), SQLITE_STATIC);
 | 
				
			||||||
 | 
					    sqlite3_bind_text(stmt, 3, schedule->name, -1, SQLITE_STATIC);
 | 
				
			||||||
 | 
					    sqlite3_bind_blob(stmt, 4, periods_blob, blob_size, SQLITE_STATIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(periods_blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc != SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static schedule_t*
 | 
				
			||||||
 | 
					schedule_db_select_mapper(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const uint16_t *periods_blob;
 | 
				
			||||||
 | 
					    schedule_t *new_schedule = malloc(sizeof(schedule_t));
 | 
				
			||||||
 | 
					    for(int i = 0; i < sqlite3_column_count(stmt); i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const char *name = sqlite3_column_name(stmt, i);
 | 
				
			||||||
 | 
					        switch(name[0])
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case 'i': // id
 | 
				
			||||||
 | 
					                new_schedule->id = sqlite3_column_int(stmt, i);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'n': // name
 | 
				
			||||||
 | 
					                strncpy(new_schedule->name, (const char*)sqlite3_column_text(stmt, i), 127);
 | 
				
			||||||
 | 
					                new_schedule->name[127] = '\0';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'p': // periods
 | 
				
			||||||
 | 
					                periods_blob = sqlite3_column_blob(stmt, i);
 | 
				
			||||||
 | 
					                new_schedule->periods_count = periods_blob[0];
 | 
				
			||||||
 | 
					                new_schedule->periods = malloc(sizeof(period_t) * periods_blob[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for(int i = 0; i < periods_blob[0]; ++i)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new_schedule->periods[i].start = periods_blob[(i * 2) + 1];
 | 
				
			||||||
 | 
					                    new_schedule->periods[i].end   = periods_blob[(i * 2) + 2];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'u': // uid
 | 
				
			||||||
 | 
					                uuid_copy(new_schedule->uid, (const unsigned char*)sqlite3_column_blob(stmt, i));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default: // ignore columns not implemented
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new_schedule;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static schedule_t**
 | 
				
			||||||
 | 
					schedule_db_select(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    schedule_t **all_schedules = malloc(sizeof(schedule_t*));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int row = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					        if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            schedule_t *new_schedule = schedule_db_select_mapper(stmt);
 | 
				
			||||||
 | 
					            row++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            all_schedules = (schedule_t**)realloc(all_schedules, sizeof(schedule_t*) * (row + 1));
 | 
				
			||||||
 | 
					            all_schedules[row - 1] = new_schedule;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(s == SQLITE_DONE)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("srror selecting schedules from database: %s\n", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					    all_schedules[row] = NULL;
 | 
				
			||||||
 | 
					    return all_schedules;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_save(schedule_t *schedule)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    if(schedule->id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "UPDATE schedules SET uid = ?2, name = ?3, periods = ?4 WHERE id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "INSERT INTO schedules(uid, name, periods) values (?2, ?3, ?4);", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int result = db_update_insert(schedule, stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(schedule->id)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_ERROR("error inserting data: %s\n", sqlite3_errmsg(global_database));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_ERROR("error updating data: %s\n", sqlite3_errmsg(global_database));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        schedule->id = sqlite3_last_insert_rowid(global_database);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule_free(schedule_t *schedule)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    free(schedule->periods);
 | 
				
			||||||
 | 
					    free(schedule);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule_free_list(schedule_t **schedules)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(int i = 0; schedules[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        schedule_free(schedules[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(schedules);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t*
 | 
				
			||||||
 | 
					schedule_periods_to_blob(schedule_t *schedule)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16_t *blob = malloc(sizeof(uint16_t) * ((schedule->periods_count * 2) + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    blob[0] = schedule->periods_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; i < schedule->periods_count; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        blob[(i * 2) + 1] = schedule->periods[i].start;
 | 
				
			||||||
 | 
					        blob[(i * 2) + 2] = schedule->periods[i].end;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return blob;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON*
 | 
				
			||||||
 | 
					schedule_to_json(schedule_t *schedule)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_CreateString(schedule->name);
 | 
				
			||||||
 | 
					    if(json_name == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "name", json_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char uuid_str[UUID_STR_LEN];
 | 
				
			||||||
 | 
					    schedule_uid_unparse(schedule->uid, uuid_str);
 | 
				
			||||||
 | 
					    cJSON *json_id = cJSON_CreateString(uuid_str);
 | 
				
			||||||
 | 
					    if(json_name == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "id", json_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_periods = cJSON_CreateArray();
 | 
				
			||||||
 | 
					    if(json_periods == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "periods", json_periods);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; i < schedule->periods_count; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_period = cJSON_CreateObject();
 | 
				
			||||||
 | 
					        if (json_period == NULL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        char start_str[8], end_str[8];
 | 
				
			||||||
 | 
					        period_t *period = &schedule->periods[i];
 | 
				
			||||||
 | 
					        sprintf(start_str, "%02d:%02d", period->start / 60, period->start % 60);
 | 
				
			||||||
 | 
					        sprintf(end_str, "%02d:%02d", period->end / 60, period->end % 60);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON *json_period_start = cJSON_CreateString(start_str);
 | 
				
			||||||
 | 
					        if (json_period_start == NULL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("failed to add start period from string '%s'\n", start_str);
 | 
				
			||||||
 | 
					            cJSON_Delete(json_period);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cJSON_AddItemToObject(json_period, "start", json_period_start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON *json_period_end = cJSON_CreateString(end_str);
 | 
				
			||||||
 | 
					        if (json_period_end == NULL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("failed to add end period from string '%s'\n", end_str);
 | 
				
			||||||
 | 
					            cJSON_Delete(json_period);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cJSON_AddItemToObject(json_period, "end", json_period_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json_periods, json_period);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_tags = cJSON_CreateArray();
 | 
				
			||||||
 | 
					    int *tags_ids = junction_tag_get_tags_for_schedule_id(schedule->id);
 | 
				
			||||||
 | 
					    if(tags_ids != NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for(int i = 0; tags_ids[i] != 0; ++i)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            char *tag = tag_get_tag(tags_ids[i]);
 | 
				
			||||||
 | 
					            if(tag == NULL)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                continue;   
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cJSON *json_tag = cJSON_CreateString(tag);
 | 
				
			||||||
 | 
					            if (json_tag == NULL)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_DEBUG("failed to add tag from string '%s'\n", tag);
 | 
				
			||||||
 | 
					                free(tag);
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            cJSON_AddItemToArray(json_tags, json_tag);
 | 
				
			||||||
 | 
					            free(tag);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        free(tags_ids);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "tags", json_tags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return json;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t**
 | 
				
			||||||
 | 
					schedule_get_all()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM schedules;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return schedule_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_uid_parse(const char *uid_str, uuid_t result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(strcmp("off", uid_str) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        memset(result, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					        memcpy(result, "off", 3);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(strcmp("on", uid_str) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        memset(result, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					        memcpy(result, "on", 2);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(uuid_parse(uid_str, result))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule_uid_unparse(const uuid_t uid, char *result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uuid_t tmp_uuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					    memcpy(tmp_uuid, "off", 3);
 | 
				
			||||||
 | 
					    if(uuid_compare(uid, tmp_uuid) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        strcpy(result, "off");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					    memcpy(tmp_uuid, "on", 2);
 | 
				
			||||||
 | 
					    if(uuid_compare(uid, tmp_uuid) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        strcpy(result, "on");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_unparse(uid, result);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,197 +0,0 @@
 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "schedule_dbo.h"
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
#include "period.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool schedule_db_update_insert(schedule_dbo *schedule, sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
    uint16_t *periods_blob = schedule->periods->to_db_blob();
 | 
					 | 
				
			||||||
    int blob_size = (int)sizeof(uint16_t) * ((periods_blob[0] * 2) + 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 1, schedule->id, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 2, schedule->name, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    sqlite3_bind_blob(stmt, 3, periods_blob, blob_size, SQLITE_STATIC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
    free(periods_blob);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (rc != SQLITE_DONE)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "ERROR inserting/updating data: " << sqlite3_errmsg(globals::db);
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static schedule_dbo*
 | 
					 | 
				
			||||||
schedule_db_select_mapper(sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto new_schedule = new schedule_dbo();
 | 
					 | 
				
			||||||
    for(int i = 0; i < sqlite3_column_count(stmt); i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        const char *name = sqlite3_column_name(stmt, i);
 | 
					 | 
				
			||||||
        switch(name[0])
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            case 'i': // id
 | 
					 | 
				
			||||||
                strncpy(new_schedule->id, (const char*)sqlite3_column_text(stmt, i), 32);
 | 
					 | 
				
			||||||
                new_schedule->id[32] = '\0';
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'n': // name
 | 
					 | 
				
			||||||
                strncpy(new_schedule->name, (const char*)sqlite3_column_text(stmt, i), 127);
 | 
					 | 
				
			||||||
                new_schedule->name[127] = '\0';
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'p': // periods
 | 
					 | 
				
			||||||
                new_schedule->periods = new period_list((const uint16_t*)sqlite3_column_blob(stmt, i));
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default: // ignore columns not implemented
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return new_schedule;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static schedule_dbo**
 | 
					 | 
				
			||||||
schedule_db_select(sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto **all_schedules = (schedule_dbo**)malloc(sizeof(schedule_dbo*));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int row = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while(true)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int s;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        s = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
        if (s == SQLITE_ROW)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            schedule_dbo *new_schedule = schedule_db_select_mapper(stmt);
 | 
					 | 
				
			||||||
            row++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            all_schedules = (schedule_dbo**)realloc(all_schedules, sizeof(schedule_dbo*) * (row + 1));
 | 
					 | 
				
			||||||
            all_schedules[row - 1] = new_schedule;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(s == SQLITE_DONE)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Selecting schedules from database: " << sqlite3_errstr(s);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    all_schedules[row] = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return all_schedules;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
schedule_dbo::update()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "UPDATE schedules SET name = ?2, periods = ?3 WHERE id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return schedule_db_update_insert(this, stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
schedule_dbo::insert()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "INSERT INTO schedules(id, name, periods) values (?1, ?2, ?3);", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return schedule_db_update_insert(this, stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
schedule_dbo::remove()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM schedules WHERE id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_text(stmt, 1, this->id, -1, SQLITE_STATIC);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
schedule_dbo::~schedule_dbo()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    delete this->periods;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Json::Value
 | 
					 | 
				
			||||||
schedule_dbo::to_json()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value schedule_json;
 | 
					 | 
				
			||||||
    schedule_json["name"] = this->name;
 | 
					 | 
				
			||||||
    schedule_json["id"] = this->id;
 | 
					 | 
				
			||||||
    schedule_json["periods"] = this->periods->to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return schedule_json;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
schedule_dbo**
 | 
					 | 
				
			||||||
schedule_dbo::get_all()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT * FROM schedules;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return schedule_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
schedule_dbo**
 | 
					 | 
				
			||||||
schedule_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder *filters[1];
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        key,
 | 
					 | 
				
			||||||
        value,
 | 
					 | 
				
			||||||
        bind_func,
 | 
					 | 
				
			||||||
        ";"
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    filters[0] = &filter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt = helpers::create_sql_filtered_query("SELECT * FROM schedules WHERE", filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return schedule_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
schedule_dbo**
 | 
					 | 
				
			||||||
schedule_dbo::get_by(helpers::sql_filter_builder **filters)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt = helpers::create_sql_filtered_query("SELECT * FROM schedules WHERE", filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return schedule_db_select(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedule_dbo::free_list(schedule_dbo **schedules_list)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    for(int i = 0; schedules_list[i] != nullptr; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        delete schedules_list[i];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    free(schedules_list);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,47 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_SCHEDULE_DBO_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_SCHEDULE_DBO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "period.h"
 | 
					 | 
				
			||||||
#include "period_list.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class schedule_dbo
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char id[33];
 | 
					 | 
				
			||||||
    char name[128];
 | 
					 | 
				
			||||||
    period_list *periods;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    update();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    insert();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ~schedule_dbo();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value
 | 
					 | 
				
			||||||
    to_json();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static void
 | 
					 | 
				
			||||||
    free_list(schedule_dbo **schedules_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static schedule_dbo**
 | 
					 | 
				
			||||||
    get_by_simple(const char *key, const void *value, intptr_t bind_func);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static schedule_dbo**
 | 
					 | 
				
			||||||
    get_by(helpers::sql_filter_builder **filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static schedule_dbo**
 | 
					 | 
				
			||||||
    get_all();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_SCHEDULE_DBO_H
 | 
					 | 
				
			||||||
							
								
								
									
										133
									
								
								models/tag.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								models/tag.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,133 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					tag_save(int id, const char *tag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "UPDATE tags SET tag = ?2 WHERE id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "INSERT INTO tags(tag) values (?2);", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, id);
 | 
				
			||||||
 | 
					    sqlite3_bind_text(stmt, 2, tag, -1, SQLITE_STATIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    if (rc != SQLITE_DONE)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error saving tag: %s\n", sqlite3_errmsg(global_database));
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char*
 | 
				
			||||||
 | 
					tag_get_tag(int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT tag FROM tags WHERE id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *result = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					        if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            const char *found_tag = (const char *)sqlite3_column_text(stmt, 0);
 | 
				
			||||||
 | 
					            result = (char*)malloc(sizeof(char) * (strlen(found_tag) + 1));
 | 
				
			||||||
 | 
					            strcpy(result, found_tag);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (s == SQLITE_DONE)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error selecting tags from database: %s\n", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					                return NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					tag_get_id(const char *tag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT id FROM tags WHERE tag=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_text(stmt, 1, tag, -1, SQLITE_STATIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int result = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					        if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            result = sqlite3_column_int(stmt, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (s == SQLITE_DONE)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error selecting tags from database: %s\n", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					tag_remove(int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM tags WHERE id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										275
									
								
								router.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								router.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,275 @@
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_schedules.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const int HTTP_METHOD_GET     = (1 << 0);
 | 
				
			||||||
 | 
					static const int HTTP_METHOD_POST    = (1 << 1);
 | 
				
			||||||
 | 
					static const int HTTP_METHOD_PUT     = (1 << 2);
 | 
				
			||||||
 | 
					static const int HTTP_METHOD_DELETE  = (1 << 3);
 | 
				
			||||||
 | 
					static const int HTTP_METHOD_OPTIONS = (1 << 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static endpoint_t endpoints[ENDPOINTS_MAX_COUNT];
 | 
				
			||||||
 | 
					static endpoint_t endpoint_index;
 | 
				
			||||||
 | 
					static endpoint_t endpoint_not_found;
 | 
				
			||||||
 | 
					static int endpoints_registered = 0;
 | 
				
			||||||
 | 
					static const char delimiter[2] = "/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					endpoint_index_func(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)args;
 | 
				
			||||||
 | 
					    mg_send_head(c, 200, hm->body.len, "Content-Type: text/plain");
 | 
				
			||||||
 | 
					    //mg_printf(c, "%.*s", (int)hm->message.len, hm->message.p);
 | 
				
			||||||
 | 
					    mg_printf(c, "%.*s", (int)hm->body.len, hm->body.p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					endpoint_not_found_func(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)args;
 | 
				
			||||||
 | 
					    mg_send_head(c, 404, hm->body.len, "Content-Type: text/plain");
 | 
				
			||||||
 | 
					    //mg_printf(c, "%.*s", (int)hm->message.len, hm->message.p);
 | 
				
			||||||
 | 
					    mg_printf(c, "%.*s", (int)hm->body.len, hm->body.p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					router_init()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // add index endpoint
 | 
				
			||||||
 | 
					    endpoint_index.route = NULL;
 | 
				
			||||||
 | 
					    endpoint_index.func = endpoint_index_func;
 | 
				
			||||||
 | 
					    endpoint_index.methods = 0;
 | 
				
			||||||
 | 
					    endpoint_index.args_count = 0;
 | 
				
			||||||
 | 
					    endpoint_index.args = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // add 404 endpoint
 | 
				
			||||||
 | 
					    endpoint_not_found.route = NULL;
 | 
				
			||||||
 | 
					    endpoint_not_found.func = endpoint_not_found_func;
 | 
				
			||||||
 | 
					    endpoint_not_found.methods = 0;
 | 
				
			||||||
 | 
					    endpoint_not_found.args_count = 0;
 | 
				
			||||||
 | 
					    endpoint_not_found.args = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    router_register_endpoint("/api/v1/schedules/", HTTP_METHOD_GET, api_v1_schedules_GET);
 | 
				
			||||||
 | 
					    router_register_endpoint("/api/v1/schedules/", HTTP_METHOD_POST, api_v1_schedules_POST);
 | 
				
			||||||
 | 
					    router_register_endpoint("/api/v1/schedules/{str}/", HTTP_METHOD_GET, api_v1_schedules_STR_GET);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					router_register_endpoint(const char *route, int methods, endpoint_func_f func)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(endpoints_registered >= ENDPOINTS_MAX_COUNT)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("can't register more than %d endpoints\n", ENDPOINTS_MAX_COUNT);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    endpoint_t *endpoint = &endpoints[endpoints_registered];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int route_parts_count = 1;
 | 
				
			||||||
 | 
					    size_t route_len = strlen(route);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(size_t i = 0; i < route_len; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(route[i] == delimiter[0] || route[i] == '\0')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ++route_parts_count;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // +1 for NULL terminator
 | 
				
			||||||
 | 
					    endpoint->route = malloc(sizeof(char*) * (route_parts_count + 1));
 | 
				
			||||||
 | 
					    endpoint->route_keeper = malloc(sizeof(char) * (route_len + 1));
 | 
				
			||||||
 | 
					    strncpy(endpoint->route_keeper, route, route_len);
 | 
				
			||||||
 | 
					    endpoint->route_keeper[route_len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int route_part = 0;
 | 
				
			||||||
 | 
					    int route_args_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *route_token = strtok(endpoint->route_keeper, delimiter);
 | 
				
			||||||
 | 
					    while(route_token)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(strcmp(route_token, "{int}") == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ++route_args_count;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(strcmp(route_token, "{str}") == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ++route_args_count;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        endpoint->route[route_part] = route_token;
 | 
				
			||||||
 | 
					        ++route_part;
 | 
				
			||||||
 | 
					        route_token = strtok(NULL, delimiter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    endpoint->route[route_part] = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    endpoint->args_count = route_args_count;
 | 
				
			||||||
 | 
					    endpoint->args = NULL;
 | 
				
			||||||
 | 
					    if(route_args_count)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        endpoint->args = malloc(sizeof(endpoint_args_t) * route_args_count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    endpoint->func = func;
 | 
				
			||||||
 | 
					    endpoint->methods = methods;
 | 
				
			||||||
 | 
					    ++endpoints_registered;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					get_method_int_for_str(struct mg_str *method_str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(strncmp(method_str->p, "GET", method_str->len) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return HTTP_METHOD_GET;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(strncmp(method_str->p, "POST", method_str->len) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return HTTP_METHOD_POST;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(strncmp(method_str->p, "PUT", method_str->len) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return HTTP_METHOD_PUT;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(strncmp(method_str->p, "DELETE", method_str->len) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return HTTP_METHOD_DELETE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(strncmp(method_str->p, "OPTIONS", method_str->len) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return HTTP_METHOD_OPTIONS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return HTTP_METHOD_GET;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endpoint_t*
 | 
				
			||||||
 | 
					router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)uri_str;
 | 
				
			||||||
 | 
					    (void)uri_len;
 | 
				
			||||||
 | 
					    char *uri = malloc(sizeof(char) * (uri_len + 1));
 | 
				
			||||||
 | 
					    strncpy(uri, uri_str, uri_len);
 | 
				
			||||||
 | 
					    uri[uri_len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int method = get_method_int_for_str(method_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; i < endpoints_registered; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(endpoints[i].methods & method)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            endpoints[i].possible_route = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            endpoints[i].possible_route = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        endpoints[i].args_found = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *uri_token;
 | 
				
			||||||
 | 
					    char *uri_token_save;
 | 
				
			||||||
 | 
					    uri_token = strtok_r(uri, delimiter, &uri_token_save);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int route_part = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!uri_token)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        free(uri);
 | 
				
			||||||
 | 
					        return &endpoint_index;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(uri_token)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for(int i = 0; i < endpoints_registered; ++i)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(!endpoints[i].possible_route)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(!endpoints[i].route[route_part])
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                endpoints[i].possible_route = 0;
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(uri_token_save[0] == '\0' && endpoints[i].route[route_part + 1])
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                endpoints[i].possible_route = 0;
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(strcmp(endpoints[i].route[route_part], uri_token) == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                endpoints[i].possible_route += 3;
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(strcmp(endpoints[i].route[route_part], "{int}") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                char *endptr;
 | 
				
			||||||
 | 
					                errno = 0;
 | 
				
			||||||
 | 
					                int found_arg_int = strtol(uri_token, &endptr, 10);
 | 
				
			||||||
 | 
					                if(errno || (endptr && *endptr != '\0'))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    endpoints[i].possible_route = 0;
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                endpoints[i].possible_route += 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                endpoints[i].args[endpoints[i].args_found].type = ENDPOINT_ARG_TYPE_INT;
 | 
				
			||||||
 | 
					                endpoints[i].args[endpoints[i].args_found].value.v_int = found_arg_int;
 | 
				
			||||||
 | 
					                ++endpoints[i].args_found;
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(strcmp(endpoints[i].route[route_part], "{str}") == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                endpoints[i].possible_route += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                endpoints[i].args[endpoints[i].args_found].type = ENDPOINT_ARG_TYPE_STR;
 | 
				
			||||||
 | 
					                endpoints[i].args[endpoints[i].args_found].value.v_str = uri_token;
 | 
				
			||||||
 | 
					                ++endpoints[i].args_found;
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            endpoints[i].possible_route = 0;
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        uri_token = strtok_r(NULL, delimiter, &uri_token_save);
 | 
				
			||||||
 | 
					        ++route_part;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    endpoint_t *best_endpoint = &endpoint_not_found;
 | 
				
			||||||
 | 
					    for(int i = 0; i < endpoints_registered; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int rating = endpoints[i].possible_route;
 | 
				
			||||||
 | 
					        if(rating > best_endpoint->possible_route)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            best_endpoint = &endpoints[i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; i < best_endpoint->args_count; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(best_endpoint->args[i].type == ENDPOINT_ARG_TYPE_STR)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            char *arg_value_str = malloc(sizeof(char) * (strlen(best_endpoint->args[i].value.v_str) + 1));
 | 
				
			||||||
 | 
					            strcpy(arg_value_str, best_endpoint->args[i].value.v_str);
 | 
				
			||||||
 | 
					            best_endpoint->args[i].value.v_str = arg_value_str;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(uri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return best_endpoint;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					router_free()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(int i = 0; i < endpoints_registered; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        free(endpoints[i].route_keeper);
 | 
				
			||||||
 | 
					        free(endpoints[i].route);
 | 
				
			||||||
 | 
					        if(endpoints[i].args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            free(endpoints[i].args);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,40 +1,83 @@
 | 
				
			||||||
create table meta
 | 
					create table meta
 | 
				
			||||||
(
 | 
					(
 | 
				
			||||||
    version_num int not null
 | 
					    version_num INTEGER
 | 
				
			||||||
 | 
					                NOT NULL
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
create table controllers
 | 
					create table controllers
 | 
				
			||||||
(
 | 
					(
 | 
				
			||||||
    id          VARCHAR(33) not null
 | 
					    id      INTEGER
 | 
				
			||||||
        primary key
 | 
					            PRIMARY KEY
 | 
				
			||||||
        unique,
 | 
					            AUTOINCREMENT,
 | 
				
			||||||
 | 
					    uid     BLOB
 | 
				
			||||||
 | 
					            NOT NULL
 | 
				
			||||||
 | 
					            UNIQUE,
 | 
				
			||||||
    name        VARCHAR(128),
 | 
					    name        VARCHAR(128),
 | 
				
			||||||
    ip          VARCHAR(16),
 | 
					    ip          VARCHAR(16),
 | 
				
			||||||
    port        INTEGER,
 | 
					    port        INTEGER,
 | 
				
			||||||
    relay_count INTEGER,
 | 
					    relay_count INTEGER,
 | 
				
			||||||
    active      BOOLEAN     not null
 | 
					    active      BOOLEAN
 | 
				
			||||||
 | 
					                NOT NULL
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
create table relays
 | 
					create table relays
 | 
				
			||||||
(
 | 
					(
 | 
				
			||||||
    id                 INTEGER     not null
 | 
					    id              INTEGER
 | 
				
			||||||
        primary key
 | 
					                    PRIMARY KEY
 | 
				
			||||||
        unique,
 | 
					                    AUTOINCREMENT,
 | 
				
			||||||
    name               VARCHAR(128),
 | 
					    name            VARCHAR(128),
 | 
				
			||||||
    number             INTEGER     not null,
 | 
					    number          INTEGER
 | 
				
			||||||
    controller_id      VARCHAR(33) not null
 | 
					                    NOT NULL,
 | 
				
			||||||
        references controllers (id),
 | 
					    controller_id   INTEGER
 | 
				
			||||||
    active_schedule_id VARCHAR(33)
 | 
					                    NOT NULL
 | 
				
			||||||
        references schedules
 | 
					                    REFERENCES controllers (id)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
create table schedules
 | 
					create table schedules
 | 
				
			||||||
(
 | 
					(
 | 
				
			||||||
    id      VARCHAR(33) not null
 | 
					    id      INTEGER
 | 
				
			||||||
        primary key
 | 
					            PRIMARY KEY
 | 
				
			||||||
        unique,
 | 
					            AUTOINCREMENT,
 | 
				
			||||||
 | 
					    uid     BLOB
 | 
				
			||||||
 | 
					            NOT NULL
 | 
				
			||||||
 | 
					            UNIQUE,
 | 
				
			||||||
    name    VARCHAR(128),
 | 
					    name    VARCHAR(128),
 | 
				
			||||||
    periods BLOB
 | 
					    periods BLOB
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INSERT INTO schedules (id, name, periods) VALUES ('off', 'off', x'00');
 | 
					create table tags
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    id      INTEGER
 | 
				
			||||||
 | 
					            PRIMARY KEY
 | 
				
			||||||
 | 
					            AUTOINCREMENT,
 | 
				
			||||||
 | 
					    tag     VARCHAR(128)
 | 
				
			||||||
 | 
					            NOT NULL
 | 
				
			||||||
 | 
					            UNIQUE
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table junction_tag
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    tag_id          INTEGER
 | 
				
			||||||
 | 
					                    NOT NULL
 | 
				
			||||||
 | 
					                    REFERENCES tags (id),
 | 
				
			||||||
 | 
					    relay_id        INTEGER
 | 
				
			||||||
 | 
					                    REFERENCES relays (id),
 | 
				
			||||||
 | 
					    schedule_id     INTEGER
 | 
				
			||||||
 | 
					                    REFERENCES schedules (id)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table junction_relay_schedule
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    weekday         SMALLINT
 | 
				
			||||||
 | 
					                    NOT NULL,
 | 
				
			||||||
 | 
					    relay_id        INTEGER
 | 
				
			||||||
 | 
					                    NOT NULL
 | 
				
			||||||
 | 
					                    REFERENCES relays (id),
 | 
				
			||||||
 | 
					    schedule_id     INTEGER
 | 
				
			||||||
 | 
					                    NOT NULL
 | 
				
			||||||
 | 
					                    REFERENCES schedules (id)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSERT INTO schedules (uid, name, periods) VALUES (x'6f666600000000000000000000000000', 'off', x'00');
 | 
				
			||||||
 | 
					INSERT INTO schedules (uid, name, periods) VALUES (x'6f6e0000000000000000000000000000',  'on', x'010000009F05');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,18 @@
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -marm")
 | 
					set(CMAKE_C_COMPILER /usr/bin/arm-none-eabi-gcc)
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=vfp")
 | 
					set(CMAKE_C_COMPILER_WORKS 1)
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv6zk+fp")
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=arm1176jzf-s")
 | 
					set(ARM-SYSROOT /usr/arm-none-eabi)
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=arm1176jzf-s")
 | 
					
 | 
				
			||||||
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -marm")
 | 
				
			||||||
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp")
 | 
				
			||||||
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv6zk+fp")
 | 
				
			||||||
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=arm1176jzf-s")
 | 
				
			||||||
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mtune=arm1176jzf-s")
 | 
				
			||||||
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot=${ARM-SYSROOT}" CACHE INTERNAL "" FORCE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} --sysroot=${ARM-SYSROOT}" CACHE INTERNAL "" FORCE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set(CMAKE_FIND_ROOT_PATH ${ARM-SYSROOT})
 | 
				
			||||||
 | 
					set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 | 
				
			||||||
 | 
					set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 | 
				
			||||||
 | 
					set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										384
									
								
								vendor/argparse.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								vendor/argparse.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,384 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by a MIT-style license that can be found
 | 
				
			||||||
 | 
					 * in the LICENSE file.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include "argparse.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OPT_UNSET 1
 | 
				
			||||||
 | 
					#define OPT_LONG  (1 << 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *
 | 
				
			||||||
 | 
					prefix_skip(const char *str, const char *prefix)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t len = strlen(prefix);
 | 
				
			||||||
 | 
					    return strncmp(str, prefix, len) ? NULL : str + len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					prefix_cmp(const char *str, const char *prefix)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (;; str++, prefix++)
 | 
				
			||||||
 | 
					        if (!*prefix) {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        } else if (*str != *prefix) {
 | 
				
			||||||
 | 
					            return (unsigned char)*prefix - (unsigned char)*str;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					argparse_error(struct argparse *self, const struct argparse_option *opt,
 | 
				
			||||||
 | 
					               const char *reason, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)self;
 | 
				
			||||||
 | 
					    if (flags & OPT_LONG) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "error: option `--%s` %s\n", opt->long_name, reason);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        fprintf(stderr, "error: option `-%c` %s\n", opt->short_name, reason);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					argparse_getvalue(struct argparse *self, const struct argparse_option *opt,
 | 
				
			||||||
 | 
					                  int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char *s = NULL;
 | 
				
			||||||
 | 
					    if (!opt->value)
 | 
				
			||||||
 | 
					        goto skipped;
 | 
				
			||||||
 | 
					    switch (opt->type) {
 | 
				
			||||||
 | 
					    case ARGPARSE_OPT_BOOLEAN:
 | 
				
			||||||
 | 
					        if (flags & OPT_UNSET) {
 | 
				
			||||||
 | 
					            *(int *)opt->value = *(int *)opt->value - 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            *(int *)opt->value = *(int *)opt->value + 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (*(int *)opt->value < 0) {
 | 
				
			||||||
 | 
					            *(int *)opt->value = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case ARGPARSE_OPT_BIT:
 | 
				
			||||||
 | 
					        if (flags & OPT_UNSET) {
 | 
				
			||||||
 | 
					            *(int *)opt->value &= ~opt->data;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            *(int *)opt->value |= opt->data;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case ARGPARSE_OPT_STRING:
 | 
				
			||||||
 | 
					        if (self->optvalue) {
 | 
				
			||||||
 | 
					            *(const char **)opt->value = self->optvalue;
 | 
				
			||||||
 | 
					            self->optvalue             = NULL;
 | 
				
			||||||
 | 
					        } else if (self->argc > 1) {
 | 
				
			||||||
 | 
					            self->argc--;
 | 
				
			||||||
 | 
					            *(const char **)opt->value = *++self->argv;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            argparse_error(self, opt, "requires a value", flags);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case ARGPARSE_OPT_INTEGER:
 | 
				
			||||||
 | 
					        errno = 0;
 | 
				
			||||||
 | 
					        if (self->optvalue) {
 | 
				
			||||||
 | 
					            *(int *)opt->value = strtol(self->optvalue, (char **)&s, 0);
 | 
				
			||||||
 | 
					            self->optvalue     = NULL;
 | 
				
			||||||
 | 
					        } else if (self->argc > 1) {
 | 
				
			||||||
 | 
					            self->argc--;
 | 
				
			||||||
 | 
					            *(int *)opt->value = strtol(*++self->argv, (char **)&s, 0);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            argparse_error(self, opt, "requires a value", flags);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (errno)
 | 
				
			||||||
 | 
					            argparse_error(self, opt, strerror(errno), flags);
 | 
				
			||||||
 | 
					        if (s[0] != '\0')
 | 
				
			||||||
 | 
					            argparse_error(self, opt, "expects an integer value", flags);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case ARGPARSE_OPT_FLOAT:
 | 
				
			||||||
 | 
					        errno = 0;
 | 
				
			||||||
 | 
					        if (self->optvalue) {
 | 
				
			||||||
 | 
					            *(float *)opt->value = strtof(self->optvalue, (char **)&s);
 | 
				
			||||||
 | 
					            self->optvalue       = NULL;
 | 
				
			||||||
 | 
					        } else if (self->argc > 1) {
 | 
				
			||||||
 | 
					            self->argc--;
 | 
				
			||||||
 | 
					            *(float *)opt->value = strtof(*++self->argv, (char **)&s);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            argparse_error(self, opt, "requires a value", flags);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (errno)
 | 
				
			||||||
 | 
					            argparse_error(self, opt, strerror(errno), flags);
 | 
				
			||||||
 | 
					        if (s[0] != '\0')
 | 
				
			||||||
 | 
					            argparse_error(self, opt, "expects a numerical value", flags);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        assert(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					skipped:
 | 
				
			||||||
 | 
					    if (opt->callback) {
 | 
				
			||||||
 | 
					        return opt->callback(self, opt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					argparse_options_check(const struct argparse_option *options)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (; options->type != ARGPARSE_OPT_END; options++) {
 | 
				
			||||||
 | 
					        switch (options->type) {
 | 
				
			||||||
 | 
					        case ARGPARSE_OPT_END:
 | 
				
			||||||
 | 
					        case ARGPARSE_OPT_BOOLEAN:
 | 
				
			||||||
 | 
					        case ARGPARSE_OPT_BIT:
 | 
				
			||||||
 | 
					        case ARGPARSE_OPT_INTEGER:
 | 
				
			||||||
 | 
					        case ARGPARSE_OPT_FLOAT:
 | 
				
			||||||
 | 
					        case ARGPARSE_OPT_STRING:
 | 
				
			||||||
 | 
					        case ARGPARSE_OPT_GROUP:
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            fprintf(stderr, "wrong option type: %d", options->type);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					argparse_short_opt(struct argparse *self, const struct argparse_option *options)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (; options->type != ARGPARSE_OPT_END; options++) {
 | 
				
			||||||
 | 
					        if (options->short_name == *self->optvalue) {
 | 
				
			||||||
 | 
					            self->optvalue = self->optvalue[1] ? self->optvalue + 1 : NULL;
 | 
				
			||||||
 | 
					            return argparse_getvalue(self, options, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					argparse_long_opt(struct argparse *self, const struct argparse_option *options)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (; options->type != ARGPARSE_OPT_END; options++) {
 | 
				
			||||||
 | 
					        const char *rest;
 | 
				
			||||||
 | 
					        int opt_flags = 0;
 | 
				
			||||||
 | 
					        if (!options->long_name)
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rest = prefix_skip(self->argv[0] + 2, options->long_name);
 | 
				
			||||||
 | 
					        if (!rest) {
 | 
				
			||||||
 | 
					            // negation disabled?
 | 
				
			||||||
 | 
					            if (options->flags & OPT_NONEG) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // only OPT_BOOLEAN/OPT_BIT supports negation
 | 
				
			||||||
 | 
					            if (options->type != ARGPARSE_OPT_BOOLEAN && options->type !=
 | 
				
			||||||
 | 
					                ARGPARSE_OPT_BIT) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (prefix_cmp(self->argv[0] + 2, "no-")) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name);
 | 
				
			||||||
 | 
					            if (!rest)
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            opt_flags |= OPT_UNSET;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (*rest) {
 | 
				
			||||||
 | 
					            if (*rest != '=')
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            self->optvalue = rest + 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return argparse_getvalue(self, options, opt_flags | OPT_LONG);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					argparse_init(struct argparse *self, struct argparse_option *options,
 | 
				
			||||||
 | 
					              const char *const *usages, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    memset(self, 0, sizeof(*self));
 | 
				
			||||||
 | 
					    self->options     = options;
 | 
				
			||||||
 | 
					    self->usages      = usages;
 | 
				
			||||||
 | 
					    self->flags       = flags;
 | 
				
			||||||
 | 
					    self->description = NULL;
 | 
				
			||||||
 | 
					    self->epilog      = NULL;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					argparse_describe(struct argparse *self, const char *description,
 | 
				
			||||||
 | 
					                  const char *epilog)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    self->description = description;
 | 
				
			||||||
 | 
					    self->epilog      = epilog;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					argparse_parse(struct argparse *self, int argc, const char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    self->argc = argc - 1;
 | 
				
			||||||
 | 
					    self->argv = argv + 1;
 | 
				
			||||||
 | 
					    self->out  = argv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    argparse_options_check(self->options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (; self->argc; self->argc--, self->argv++) {
 | 
				
			||||||
 | 
					        const char *arg = self->argv[0];
 | 
				
			||||||
 | 
					        if (arg[0] != '-' || !arg[1]) {
 | 
				
			||||||
 | 
					            if (self->flags & ARGPARSE_STOP_AT_NON_OPTION) {
 | 
				
			||||||
 | 
					                goto end;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // if it's not option or is a single char '-', copy verbatim
 | 
				
			||||||
 | 
					            self->out[self->cpidx++] = self->argv[0];
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // short option
 | 
				
			||||||
 | 
					        if (arg[1] != '-') {
 | 
				
			||||||
 | 
					            self->optvalue = arg + 1;
 | 
				
			||||||
 | 
					            switch (argparse_short_opt(self, self->options)) {
 | 
				
			||||||
 | 
					            case -1:
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case -2:
 | 
				
			||||||
 | 
					                goto unknown;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            while (self->optvalue) {
 | 
				
			||||||
 | 
					                switch (argparse_short_opt(self, self->options)) {
 | 
				
			||||||
 | 
					                case -1:
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case -2:
 | 
				
			||||||
 | 
					                    goto unknown;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // if '--' presents
 | 
				
			||||||
 | 
					        if (!arg[2]) {
 | 
				
			||||||
 | 
					            self->argc--;
 | 
				
			||||||
 | 
					            self->argv++;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // long option
 | 
				
			||||||
 | 
					        switch (argparse_long_opt(self, self->options)) {
 | 
				
			||||||
 | 
					        case -1:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case -2:
 | 
				
			||||||
 | 
					            goto unknown;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unknown:
 | 
				
			||||||
 | 
					        fprintf(stderr, "error: unknown option `%s`\n", self->argv[0]);
 | 
				
			||||||
 | 
					        argparse_usage(self);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
					    memmove(self->out + self->cpidx, self->argv,
 | 
				
			||||||
 | 
					            self->argc * sizeof(*self->out));
 | 
				
			||||||
 | 
					    self->out[self->cpidx + self->argc] = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return self->cpidx + self->argc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					argparse_usage(struct argparse *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (self->usages) {
 | 
				
			||||||
 | 
					        fprintf(stdout, "Usage: %s\n", *self->usages++);
 | 
				
			||||||
 | 
					        while (*self->usages && **self->usages)
 | 
				
			||||||
 | 
					            fprintf(stdout, "   or: %s\n", *self->usages++);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        fprintf(stdout, "Usage:\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // print description
 | 
				
			||||||
 | 
					    if (self->description)
 | 
				
			||||||
 | 
					        fprintf(stdout, "%s\n", self->description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fputc('\n', stdout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const struct argparse_option *options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // figure out best width
 | 
				
			||||||
 | 
					    size_t usage_opts_width = 0;
 | 
				
			||||||
 | 
					    size_t len;
 | 
				
			||||||
 | 
					    options = self->options;
 | 
				
			||||||
 | 
					    for (; options->type != ARGPARSE_OPT_END; options++) {
 | 
				
			||||||
 | 
					        len = 0;
 | 
				
			||||||
 | 
					        if ((options)->short_name) {
 | 
				
			||||||
 | 
					            len += 2;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if ((options)->short_name && (options)->long_name) {
 | 
				
			||||||
 | 
					            len += 2;           // separator ", "
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if ((options)->long_name) {
 | 
				
			||||||
 | 
					            len += strlen((options)->long_name) + 2;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (options->type == ARGPARSE_OPT_INTEGER) {
 | 
				
			||||||
 | 
					            len += strlen("=<int>");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (options->type == ARGPARSE_OPT_FLOAT) {
 | 
				
			||||||
 | 
					            len += strlen("=<flt>");
 | 
				
			||||||
 | 
					        } else if (options->type == ARGPARSE_OPT_STRING) {
 | 
				
			||||||
 | 
					            len += strlen("=<str>");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        len = (len + 3) - ((len + 3) & 3);
 | 
				
			||||||
 | 
					        if (usage_opts_width < len) {
 | 
				
			||||||
 | 
					            usage_opts_width = len;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    usage_opts_width += 4;      // 4 spaces prefix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options = self->options;
 | 
				
			||||||
 | 
					    for (; options->type != ARGPARSE_OPT_END; options++) {
 | 
				
			||||||
 | 
					        size_t pos = 0;
 | 
				
			||||||
 | 
					        int pad    = 0;
 | 
				
			||||||
 | 
					        if (options->type == ARGPARSE_OPT_GROUP) {
 | 
				
			||||||
 | 
					            fputc('\n', stdout);
 | 
				
			||||||
 | 
					            fprintf(stdout, "%s", options->help);
 | 
				
			||||||
 | 
					            fputc('\n', stdout);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pos = fprintf(stdout, "    ");
 | 
				
			||||||
 | 
					        if (options->short_name) {
 | 
				
			||||||
 | 
					            pos += fprintf(stdout, "-%c", options->short_name);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (options->long_name && options->short_name) {
 | 
				
			||||||
 | 
					            pos += fprintf(stdout, ", ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (options->long_name) {
 | 
				
			||||||
 | 
					            pos += fprintf(stdout, "--%s", options->long_name);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (options->type == ARGPARSE_OPT_INTEGER) {
 | 
				
			||||||
 | 
					            pos += fprintf(stdout, "=<int>");
 | 
				
			||||||
 | 
					        } else if (options->type == ARGPARSE_OPT_FLOAT) {
 | 
				
			||||||
 | 
					            pos += fprintf(stdout, "=<flt>");
 | 
				
			||||||
 | 
					        } else if (options->type == ARGPARSE_OPT_STRING) {
 | 
				
			||||||
 | 
					            pos += fprintf(stdout, "=<str>");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (pos <= usage_opts_width) {
 | 
				
			||||||
 | 
					            pad = usage_opts_width - pos;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            fputc('\n', stdout);
 | 
				
			||||||
 | 
					            pad = usage_opts_width;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fprintf(stdout, "%*s%s\n", pad + 2, "", options->help);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // print epilog
 | 
				
			||||||
 | 
					    if (self->epilog)
 | 
				
			||||||
 | 
					        fprintf(stdout, "%s\n", self->epilog);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					argparse_help_cb(struct argparse *self, const struct argparse_option *option)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)option;
 | 
				
			||||||
 | 
					    argparse_usage(self);
 | 
				
			||||||
 | 
					    exit(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										130
									
								
								vendor/argparse.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								vendor/argparse.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,130 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by a MIT-style license that can be found
 | 
				
			||||||
 | 
					 * in the LICENSE file.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef ARGPARSE_H
 | 
				
			||||||
 | 
					#define ARGPARSE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* For c++ compatibility */
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct argparse;
 | 
				
			||||||
 | 
					struct argparse_option;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef int argparse_callback (struct argparse *self,
 | 
				
			||||||
 | 
					                               const struct argparse_option *option);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum argparse_flag {
 | 
				
			||||||
 | 
					    ARGPARSE_STOP_AT_NON_OPTION = 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum argparse_option_type {
 | 
				
			||||||
 | 
					    /* special */
 | 
				
			||||||
 | 
					    ARGPARSE_OPT_END,
 | 
				
			||||||
 | 
					    ARGPARSE_OPT_GROUP,
 | 
				
			||||||
 | 
					    /* options with no arguments */
 | 
				
			||||||
 | 
					    ARGPARSE_OPT_BOOLEAN,
 | 
				
			||||||
 | 
					    ARGPARSE_OPT_BIT,
 | 
				
			||||||
 | 
					    /* options with arguments (optional or required) */
 | 
				
			||||||
 | 
					    ARGPARSE_OPT_INTEGER,
 | 
				
			||||||
 | 
					    ARGPARSE_OPT_FLOAT,
 | 
				
			||||||
 | 
					    ARGPARSE_OPT_STRING,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum argparse_option_flags {
 | 
				
			||||||
 | 
					    OPT_NONEG = 1,              /* disable negation */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *  argparse option
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `type`:
 | 
				
			||||||
 | 
					 *    holds the type of the option, you must have an ARGPARSE_OPT_END last in your
 | 
				
			||||||
 | 
					 *    array.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `short_name`:
 | 
				
			||||||
 | 
					 *    the character to use as a short option name, '\0' if none.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `long_name`:
 | 
				
			||||||
 | 
					 *    the long option name, without the leading dash, NULL if none.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `value`:
 | 
				
			||||||
 | 
					 *    stores pointer to the value to be filled.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `help`:
 | 
				
			||||||
 | 
					 *    the short help message associated to what the option does.
 | 
				
			||||||
 | 
					 *    Must never be NULL (except for ARGPARSE_OPT_END).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `callback`:
 | 
				
			||||||
 | 
					 *    function is called when corresponding argument is parsed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `data`:
 | 
				
			||||||
 | 
					 *    associated data. Callbacks can use it like they want.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  `flags`:
 | 
				
			||||||
 | 
					 *    option flags.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct argparse_option {
 | 
				
			||||||
 | 
					    enum argparse_option_type type;
 | 
				
			||||||
 | 
					    const char short_name;
 | 
				
			||||||
 | 
					    const char *long_name;
 | 
				
			||||||
 | 
					    void *value;
 | 
				
			||||||
 | 
					    const char *help;
 | 
				
			||||||
 | 
					    argparse_callback *callback;
 | 
				
			||||||
 | 
					    intptr_t data;
 | 
				
			||||||
 | 
					    int flags;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * argpparse
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct argparse {
 | 
				
			||||||
 | 
					    // user supplied
 | 
				
			||||||
 | 
					    const struct argparse_option *options;
 | 
				
			||||||
 | 
					    const char *const *usages;
 | 
				
			||||||
 | 
					    int flags;
 | 
				
			||||||
 | 
					    const char *description;    // a description after usage
 | 
				
			||||||
 | 
					    const char *epilog;         // a description at the end
 | 
				
			||||||
 | 
					    // internal context
 | 
				
			||||||
 | 
					    int argc;
 | 
				
			||||||
 | 
					    const char **argv;
 | 
				
			||||||
 | 
					    const char **out;
 | 
				
			||||||
 | 
					    int cpidx;
 | 
				
			||||||
 | 
					    const char *optvalue;       // current option value
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// built-in callbacks
 | 
				
			||||||
 | 
					int argparse_help_cb(struct argparse *self,
 | 
				
			||||||
 | 
					                     const struct argparse_option *option);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// built-in option macros
 | 
				
			||||||
 | 
					#define OPT_END()        { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 }
 | 
				
			||||||
 | 
					#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ }
 | 
				
			||||||
 | 
					#define OPT_BIT(...)     { ARGPARSE_OPT_BIT, __VA_ARGS__ }
 | 
				
			||||||
 | 
					#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ }
 | 
				
			||||||
 | 
					#define OPT_FLOAT(...)   { ARGPARSE_OPT_FLOAT, __VA_ARGS__ }
 | 
				
			||||||
 | 
					#define OPT_STRING(...)  { ARGPARSE_OPT_STRING, __VA_ARGS__ }
 | 
				
			||||||
 | 
					#define OPT_GROUP(h)     { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 }
 | 
				
			||||||
 | 
					#define OPT_HELP()       OPT_BOOLEAN('h', "help", NULL,                 \
 | 
				
			||||||
 | 
					                                     "show this help message and exit", \
 | 
				
			||||||
 | 
					                                     argparse_help_cb, 0, OPT_NONEG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int argparse_init(struct argparse *self, struct argparse_option *options,
 | 
				
			||||||
 | 
					                  const char *const *usages, int flags);
 | 
				
			||||||
 | 
					void argparse_describe(struct argparse *self, const char *description,
 | 
				
			||||||
 | 
					                       const char *epilog);
 | 
				
			||||||
 | 
					int argparse_parse(struct argparse *self, int argc, const char **argv);
 | 
				
			||||||
 | 
					void argparse_usage(struct argparse *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										3074
									
								
								vendor/cJSON.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3074
									
								
								vendor/cJSON.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										293
									
								
								vendor/cJSON.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								vendor/cJSON.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,293 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  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 13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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(cJSON *item);
 | 
				
			||||||
 | 
					CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *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 adress 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
							
								
								
									
										5016
									
								
								vendor/confini.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5016
									
								
								vendor/confini.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										547
									
								
								vendor/confini.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										547
									
								
								vendor/confini.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,547 @@
 | 
				
			||||||
 | 
					/*  -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @file       confini.h
 | 
				
			||||||
 | 
					    @brief      libconfini header
 | 
				
			||||||
 | 
					    @author     Stefano Gioffré
 | 
				
			||||||
 | 
					    @copyright  GNU General Public License, version 3 or any later version
 | 
				
			||||||
 | 
					    @version    1.14.0
 | 
				
			||||||
 | 
					    @date       2016-2020
 | 
				
			||||||
 | 
					    @see        https://madmurphy.github.io/libconfini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _LIBCONFINI_HEADER_
 | 
				
			||||||
 | 
					#define _LIBCONFINI_HEADER_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  PRIVATE (HEADER-SCOPED) MACROS  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __INIFORMAT_TABLE_CB_FIELDS__(NAME, OFFSET, SIZE, DEFVAL) \
 | 
				
			||||||
 | 
					    unsigned char NAME:SIZE;
 | 
				
			||||||
 | 
					#define __INIFORMAT_TABLE_CB_DEFAULT__(NAME, OFFSET, SIZE, DEFVAL) DEFVAL,
 | 
				
			||||||
 | 
					#define __INIFORMAT_TABLE_CB_ZERO__(NAME, OFFSET, SIZE, DEFVAL) 0,
 | 
				
			||||||
 | 
					#define _LIBCONFINI_INIFORMAT_TYPE_ \
 | 
				
			||||||
 | 
					    struct IniFormat { INIFORMAT_TABLE_AS(__INIFORMAT_TABLE_CB_FIELDS__) }
 | 
				
			||||||
 | 
					#define _LIBCONFINI_DEFAULT_FORMAT_ \
 | 
				
			||||||
 | 
					    { INIFORMAT_TABLE_AS(__INIFORMAT_TABLE_CB_DEFAULT__) }
 | 
				
			||||||
 | 
					#define _LIBCONFINI_UNIXLIKE_FORMAT_ \
 | 
				
			||||||
 | 
					    { INIFORMAT_TABLE_AS(__INIFORMAT_TABLE_CB_ZERO__) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  PUBLIC MACROS  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Calls a user-given macro (that accepts four arguments) for each row
 | 
				
			||||||
 | 
					            of the table
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    NOTE: The following table and the order of its rows **define** (and link
 | 
				
			||||||
 | 
					    together) both the #IniFormat and #IniFormatNum data types declared in this
 | 
				
			||||||
 | 
					    header
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#define INIFORMAT_TABLE_AS(_____)                 /*  IniFormat table  *\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NAME                      BIT  SIZE DEFAULT
 | 
				
			||||||
 | 
					                                                                      */\
 | 
				
			||||||
 | 
					 _____( delimiter_symbol,         0,   7,   INI_EQUALS                ) \
 | 
				
			||||||
 | 
					 _____( case_sensitive,           7,   1,   false                     )/*
 | 
				
			||||||
 | 
					                                                                      */\
 | 
				
			||||||
 | 
					 _____( semicolon_marker,         8,   2,   INI_DISABLED_OR_COMMENT   ) \
 | 
				
			||||||
 | 
					 _____( hash_marker,              10,  2,   INI_DISABLED_OR_COMMENT   ) \
 | 
				
			||||||
 | 
					 _____( section_paths,            12,  2,   INI_ABSOLUTE_AND_RELATIVE ) \
 | 
				
			||||||
 | 
					 _____( multiline_nodes,          14,  2,   INI_MULTILINE_EVERYWHERE  )/*
 | 
				
			||||||
 | 
					                                                                      */\
 | 
				
			||||||
 | 
					 _____( no_single_quotes,         16,  1,   false                     ) \
 | 
				
			||||||
 | 
					 _____( no_double_quotes,         17,  1,   false                     ) \
 | 
				
			||||||
 | 
					 _____( no_spaces_in_names,       18,  1,   false                     ) \
 | 
				
			||||||
 | 
					 _____( implicit_is_not_empty,    19,  1,   false                     ) \
 | 
				
			||||||
 | 
					 _____( do_not_collapse_values,   20,  1,   false                     ) \
 | 
				
			||||||
 | 
					 _____( preserve_empty_quotes,    21,  1,   false                     ) \
 | 
				
			||||||
 | 
					 _____( disabled_after_space,     22,  1,   false                     ) \
 | 
				
			||||||
 | 
					 _____( disabled_can_be_implicit, 23,  1,   false                     )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Checks whether a format does **not** support escape sequences
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					#define INIFORMAT_HAS_NO_ESC(FORMAT) \
 | 
				
			||||||
 | 
					    (FORMAT.multiline_nodes == INI_NO_MULTILINE && \
 | 
				
			||||||
 | 
					    FORMAT.no_double_quotes && FORMAT.no_single_quotes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  PUBLIC TYPEDEFS  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  24-bit bitfield representing the format of an INI file (INI
 | 
				
			||||||
 | 
					            dialect)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef _LIBCONFINI_INIFORMAT_TYPE_ IniFormat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Global statistics about an INI file
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef struct IniStatistics {
 | 
				
			||||||
 | 
					    const IniFormat format;
 | 
				
			||||||
 | 
					    const size_t bytes;
 | 
				
			||||||
 | 
					    const size_t members;
 | 
				
			||||||
 | 
					} IniStatistics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Dispatch of a single INI node
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef struct IniDispatch {
 | 
				
			||||||
 | 
					    const IniFormat format;
 | 
				
			||||||
 | 
					    uint8_t type;
 | 
				
			||||||
 | 
					    char * data;
 | 
				
			||||||
 | 
					    char * value;
 | 
				
			||||||
 | 
					    const char * append_to;
 | 
				
			||||||
 | 
					    size_t d_len;
 | 
				
			||||||
 | 
					    size_t v_len;
 | 
				
			||||||
 | 
					    size_t at_len;
 | 
				
			||||||
 | 
					    size_t dispatch_id;
 | 
				
			||||||
 | 
					} IniDispatch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  The unique ID of an INI format (24-bit maximum)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef uint32_t IniFormatNum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Callback function for handling an #IniStatistics structure
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef int (* IniStatsHandler) (
 | 
				
			||||||
 | 
					    IniStatistics * statistics,
 | 
				
			||||||
 | 
					    void * user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Callback function for handling an #IniDispatch structure
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef int (* IniDispHandler) (
 | 
				
			||||||
 | 
					    IniDispatch * dispatch,
 | 
				
			||||||
 | 
					    void * user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Callback function for handling an INI string belonging to a
 | 
				
			||||||
 | 
					            sequence of INI strings
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef int (* IniStrHandler) (
 | 
				
			||||||
 | 
					    char * ini_string,
 | 
				
			||||||
 | 
					    size_t string_length,
 | 
				
			||||||
 | 
					    size_t string_num,
 | 
				
			||||||
 | 
					    IniFormat format,
 | 
				
			||||||
 | 
					    void * user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Callback function for handling a selected fragment of an INI string
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					typedef int (* IniSubstrHandler) (
 | 
				
			||||||
 | 
					    const char * ini_string,
 | 
				
			||||||
 | 
					    size_t fragm_offset,
 | 
				
			||||||
 | 
					    size_t fragm_length,
 | 
				
			||||||
 | 
					    size_t fragm_num,
 | 
				
			||||||
 | 
					    IniFormat format,
 | 
				
			||||||
 | 
					    void * user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  PUBLIC FUNCTIONS  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int strip_ini_cache (
 | 
				
			||||||
 | 
					    register char * const ini_source,
 | 
				
			||||||
 | 
					    const size_t ini_length,
 | 
				
			||||||
 | 
					    const IniFormat format,
 | 
				
			||||||
 | 
					    const IniStatsHandler f_init,
 | 
				
			||||||
 | 
					    const IniDispHandler f_foreach,
 | 
				
			||||||
 | 
					    void * const user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int load_ini_file (
 | 
				
			||||||
 | 
					    FILE * const ini_file,
 | 
				
			||||||
 | 
					    const IniFormat format,
 | 
				
			||||||
 | 
					    const IniStatsHandler f_init,
 | 
				
			||||||
 | 
					    const IniDispHandler f_foreach,
 | 
				
			||||||
 | 
					    void * const user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int load_ini_path (
 | 
				
			||||||
 | 
					    const char * const path,
 | 
				
			||||||
 | 
					    const IniFormat format,
 | 
				
			||||||
 | 
					    const IniStatsHandler f_init,
 | 
				
			||||||
 | 
					    const IniDispHandler f_foreach,
 | 
				
			||||||
 | 
					    void * const user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern bool ini_string_match_ss (
 | 
				
			||||||
 | 
					    const char * const simple_string_a,
 | 
				
			||||||
 | 
					    const char * const simple_string_b,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern bool ini_string_match_si (
 | 
				
			||||||
 | 
					    const char * const simple_string,
 | 
				
			||||||
 | 
					    const char * const ini_string,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern bool ini_string_match_ii (
 | 
				
			||||||
 | 
					    const char * const ini_string_a,
 | 
				
			||||||
 | 
					    const char * const ini_string_b,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern bool ini_array_match (
 | 
				
			||||||
 | 
					    const char * const ini_string_a,
 | 
				
			||||||
 | 
					    const char * const ini_string_b,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern size_t ini_unquote (
 | 
				
			||||||
 | 
					    char * const ini_string,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern size_t ini_string_parse (
 | 
				
			||||||
 | 
					    char * const ini_string,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern size_t ini_array_get_length (
 | 
				
			||||||
 | 
					    const char * const ini_string,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int ini_array_foreach (
 | 
				
			||||||
 | 
					    const char * const ini_string,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format,
 | 
				
			||||||
 | 
					    const IniSubstrHandler f_foreach,
 | 
				
			||||||
 | 
					    void * const user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern size_t ini_array_shift (
 | 
				
			||||||
 | 
					    const char ** const ini_strptr,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern size_t ini_array_collapse (
 | 
				
			||||||
 | 
					    char * const ini_string,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern char * ini_array_break (
 | 
				
			||||||
 | 
					    char * const ini_string,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern char * ini_array_release (
 | 
				
			||||||
 | 
					    char ** const ini_strptr,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int ini_array_split (
 | 
				
			||||||
 | 
					    char * const ini_string,
 | 
				
			||||||
 | 
					    const char delimiter,
 | 
				
			||||||
 | 
					    const IniFormat format,
 | 
				
			||||||
 | 
					    const IniStrHandler f_foreach,
 | 
				
			||||||
 | 
					    void * const user_data
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void ini_global_set_lowercase_mode (
 | 
				
			||||||
 | 
					    const bool lowercase
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void ini_global_set_implicit_value (
 | 
				
			||||||
 | 
					    char * const implicit_value,
 | 
				
			||||||
 | 
					    const size_t implicit_v_len
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern IniFormatNum ini_fton (
 | 
				
			||||||
 | 
					    const IniFormat format
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern IniFormat ini_ntof (
 | 
				
			||||||
 | 
					    const IniFormatNum format_id
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int ini_get_bool (
 | 
				
			||||||
 | 
					    const char * const ini_string,
 | 
				
			||||||
 | 
					    const int when_fail
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  PUBLIC LINKS  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int (* const ini_get_int) (
 | 
				
			||||||
 | 
					    const char * ini_string
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern long int (* const ini_get_lint) (
 | 
				
			||||||
 | 
					    const char * ini_string
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern long long int (* const ini_get_llint) (
 | 
				
			||||||
 | 
					    const char * ini_string
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern double (* const ini_get_double) (
 | 
				
			||||||
 | 
					    const char * ini_string
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Legacy support, soon to be replaced with a `float` data type --
 | 
				
			||||||
 | 
					            please **do not use `ini_get_float()`!**
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					#define ini_get_float \
 | 
				
			||||||
 | 
					    _Pragma("GCC warning \"function `ini_get_float()` is deprecated for parsing a `double` data type; use `ini_get_double()` instead\"") \
 | 
				
			||||||
 | 
					    ini_get_double
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  PUBLIC CONSTANTS AND VARIABLES  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Error mask (flags not present in user-generated interruptions)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					#define CONFINI_ERROR 252
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Error codes
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					enum ConfiniInterruptNo {
 | 
				
			||||||
 | 
					    CONFINI_SUCCESS = 0,    /**< There have been no interruptions, everything
 | 
				
			||||||
 | 
					                                 went well [value=0] **/
 | 
				
			||||||
 | 
					    CONFINI_IINTR = 1,      /**< Interrupted by the user during `f_init()`
 | 
				
			||||||
 | 
					                                 [value=1] **/
 | 
				
			||||||
 | 
					    CONFINI_FEINTR = 2,     /**< Interrupted by the user during `f_foreach()`
 | 
				
			||||||
 | 
					                                 [value=2] **/
 | 
				
			||||||
 | 
					    CONFINI_ENOENT = 4,     /**< File inaccessible [value=4] **/
 | 
				
			||||||
 | 
					    CONFINI_ENOMEM = 5,     /**< Error allocating virtual memory [value=5] **/
 | 
				
			||||||
 | 
					    CONFINI_EIO = 6,        /**< Error reading the file [value=6] **/
 | 
				
			||||||
 | 
					    CONFINI_EOOR = 7,       /**< Out-of-range error: callbacks are more than
 | 
				
			||||||
 | 
					                                 expected [value=7] **/
 | 
				
			||||||
 | 
					    CONFINI_EBADF = 8,      /**< The stream specified is not a seekable stream
 | 
				
			||||||
 | 
					                                 [value=8] **/
 | 
				
			||||||
 | 
					    CONFINI_EFBIG = 9,      /**< File too large [value=9] **/
 | 
				
			||||||
 | 
					    CONFINI_EROADDR = 10    /**< Address is read-only [value=10] **/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  INI node types
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					enum IniNodeType {
 | 
				
			||||||
 | 
					    INI_UNKNOWN = 0,            /**< This is a node impossible to categorize
 | 
				
			||||||
 | 
					                                     [value=0] **/
 | 
				
			||||||
 | 
					    INI_VALUE = 1,              /**< Not used by **libconfini** (values are
 | 
				
			||||||
 | 
					                                     dispatched together with keys) -- but
 | 
				
			||||||
 | 
					                                     available for user's implementations
 | 
				
			||||||
 | 
					                                     [value=1] **/
 | 
				
			||||||
 | 
					    INI_KEY = 2,                /**< This is a key [value=2] **/
 | 
				
			||||||
 | 
					    INI_SECTION = 3,            /**< This is a section or a section path
 | 
				
			||||||
 | 
					                                     [value=3] **/
 | 
				
			||||||
 | 
					    INI_COMMENT = 4,            /**< This is a comment [value=4] **/
 | 
				
			||||||
 | 
					    INI_INLINE_COMMENT = 5,     /**< This is an inline comment [value=5] **/
 | 
				
			||||||
 | 
					    INI_DISABLED_KEY = 6,       /**< This is a disabled key [value=6] **/
 | 
				
			||||||
 | 
					    INI_DISABLED_SECTION = 7    /**< This is a disabled section path
 | 
				
			||||||
 | 
					                                     [value=7] **/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Common array and key-value delimiters (but a delimiter may also be
 | 
				
			||||||
 | 
					            any other ASCII character not present in this list)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					enum IniDelimiters {
 | 
				
			||||||
 | 
					    INI_ANY_SPACE = 0,  /**< In multi-line INIs:
 | 
				
			||||||
 | 
					                             `/(?:\\(?:\n\r?|\r\n?)|[\t \v\f])+/`, in
 | 
				
			||||||
 | 
					                             non-multi-line INIs: `/[\t \v\f])+/` **/
 | 
				
			||||||
 | 
					    INI_EQUALS = '=',   /**< Equals character (`=`) **/
 | 
				
			||||||
 | 
					    INI_COLON = ':',    /**< Colon character (`:`) **/
 | 
				
			||||||
 | 
					    INI_DOT = '.',      /**< Dot character (`.`) **/
 | 
				
			||||||
 | 
					    INI_COMMA = ','     /**< Comma character (`,`) **/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Possible values of #IniFormat::semicolon_marker and
 | 
				
			||||||
 | 
					            #IniFormat::hash_marker (i.e., meaning of `/\s+;/` and `/\s+#/` in
 | 
				
			||||||
 | 
					            respect to a format)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					enum IniCommentMarker {
 | 
				
			||||||
 | 
					    INI_DISABLED_OR_COMMENT = 0,    /**< This marker opens a comment or a
 | 
				
			||||||
 | 
					                                         disabled entry **/
 | 
				
			||||||
 | 
					    INI_ONLY_COMMENT = 1,           /**< This marker opens a comment **/
 | 
				
			||||||
 | 
					    INI_IGNORE = 2,                 /**< This marker opens a comment that has
 | 
				
			||||||
 | 
					                                         been marked for deletion and must not
 | 
				
			||||||
 | 
					                                         be dispatched or counted **/
 | 
				
			||||||
 | 
					    INI_IS_NOT_A_MARKER = 3         /**< This is not a marker at all, but a
 | 
				
			||||||
 | 
					                                         normal character instead **/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Possible values of #IniFormat::section_paths
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					enum IniSectionPaths {
 | 
				
			||||||
 | 
					    INI_ABSOLUTE_AND_RELATIVE = 0,  /**< Section paths starting with a dot
 | 
				
			||||||
 | 
					                                         express nesting to the current parent,
 | 
				
			||||||
 | 
					                                         to root otherwise **/
 | 
				
			||||||
 | 
					    INI_ABSOLUTE_ONLY = 1,          /**< Section paths starting with a dot will
 | 
				
			||||||
 | 
					                                         be cleaned of their leading dot and
 | 
				
			||||||
 | 
					                                         appended to root **/
 | 
				
			||||||
 | 
					    INI_ONE_LEVEL_ONLY = 2,         /**< Format supports sections, but the dot
 | 
				
			||||||
 | 
					                                         does not express nesting and is not a
 | 
				
			||||||
 | 
					                                         meta-character **/
 | 
				
			||||||
 | 
					    INI_NO_SECTIONS = 3             /**< Format does *not* support sections --
 | 
				
			||||||
 | 
					                                         `/\[[^\]]*\]/g`, if any, will be
 | 
				
			||||||
 | 
					                                         treated as keys! **/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Possible values of #IniFormat::multiline_nodes
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					enum IniMultiline {
 | 
				
			||||||
 | 
					    INI_MULTILINE_EVERYWHERE = 0,       /**< Comments, section paths and keys
 | 
				
			||||||
 | 
					                                             -- disabled or not -- are allowed
 | 
				
			||||||
 | 
					                                             to be multi-line **/
 | 
				
			||||||
 | 
					    INI_BUT_COMMENTS = 1,               /**< Only section paths and keys --
 | 
				
			||||||
 | 
					                                             disabled or not -- are allowed to
 | 
				
			||||||
 | 
					                                             be multi-line **/
 | 
				
			||||||
 | 
					    INI_BUT_DISABLED_AND_COMMENTS = 2,  /**< Only active section paths and
 | 
				
			||||||
 | 
					                                             active keys are allowed to be
 | 
				
			||||||
 | 
					                                             multi-line **/
 | 
				
			||||||
 | 
					    INI_NO_MULTILINE = 3                /**< Multi-line escape sequences are
 | 
				
			||||||
 | 
					                                             disabled **/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  A model format for standard INI files
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					static const IniFormat INI_DEFAULT_FORMAT = _LIBCONFINI_DEFAULT_FORMAT_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  A model format for Unix-like .conf files (where space characters
 | 
				
			||||||
 | 
					            are delimiters between keys and values)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					/*  All fields are set to `0` here.  */
 | 
				
			||||||
 | 
					static const IniFormat INI_UNIXLIKE_FORMAT = _LIBCONFINI_UNIXLIKE_FORMAT_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  If set to `true`, key and section names in case-insensitive INI
 | 
				
			||||||
 | 
					            formats will be dispatched lowercase, verbatim otherwise (default
 | 
				
			||||||
 | 
					            value: `false`)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					extern bool INI_GLOBAL_LOWERCASE_MODE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Value to be assigned to implicit keys (default value: `NULL`)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					extern char * INI_GLOBAL_IMPLICIT_VALUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					    @brief  Length of the value assigned to implicit keys (default value: `0`)
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					extern size_t INI_GLOBAL_IMPLICIT_V_LEN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  CLEAN THE PRIVATE ENVIRONMENT  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef _LIBCONFINI_UNIXLIKE_FORMAT_
 | 
				
			||||||
 | 
					#undef _LIBCONFINI_DEFAULT_FORMAT_
 | 
				
			||||||
 | 
					#undef _LIBCONFINI_INIFORMAT_TYPE_
 | 
				
			||||||
 | 
					#undef __INIFORMAT_TABLE_CB_ZERO__
 | 
				
			||||||
 | 
					#undef __INIFORMAT_TABLE_CB_DEFAULT__
 | 
				
			||||||
 | 
					#undef __INIFORMAT_TABLE_CB_FIELDS__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  END OF `_LIBCONFINI_HEADER_`  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  EOF  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										16123
									
								
								vendor/mongoose.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16123
									
								
								vendor/mongoose.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										6277
									
								
								vendor/mongoose.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6277
									
								
								vendor/mongoose.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										6440
									
								
								vendor/mpack.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6440
									
								
								vendor/mpack.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										7151
									
								
								vendor/mpack.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7151
									
								
								vendor/mpack.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue