Merge branch 'rewrite' into dev
This commit is contained in:
		
						commit
						b68cdd224e
					
				
					 129 changed files with 40046 additions and 3787 deletions
				
			
		
							
								
								
									
										10
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
build
 | 
					build/
 | 
				
			||||||
cmake-build-debug
 | 
					docs/
 | 
				
			||||||
.idea
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
sql/*.h
 | 
					tests/testing_tmp/
 | 
				
			||||||
 | 
					tests/testing_bak/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,71 +1,28 @@
 | 
				
			||||||
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)
 | 
					SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wpedantic -Werror -Wall -Wextra -luuid -lsqlite3 -g -fprofile-arcs -ftest-coverage")
 | 
				
			||||||
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)
 | 
					string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
 | 
				
			||||||
set(CMAKE_CXX_EXTENSIONS OFF)
 | 
					add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -Wall -Wextra -Werror -g -latomic")
 | 
					add_definitions("-DMG_ENABLE_EXTRA_ERRORS_DESC")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS_DEBUG "-g")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########
 | 
					aux_source_directory(vendor VENDOR_SRC) # vendor first to put their warnings on top
 | 
				
			||||||
# If you include the drogon source code locally in your project, use this method to add drogon
 | 
					aux_source_directory(. SRC_DIR)
 | 
				
			||||||
# add_subdirectory(drogon)
 | 
					aux_source_directory(models MODELS_SRC)
 | 
				
			||||||
# set(Drogon_DIR ${PROJECT_BINARY_DIR}/drogon)
 | 
					aux_source_directory(helpers HELPERS_SRC)
 | 
				
			||||||
# find_package(Drogon CONFIG REQUIRED NO_DEFAULT_PATH)
 | 
					aux_source_directory(handlers HANDLERS_SRC)
 | 
				
			||||||
# include_directories(${DROGON_INCLUDE_DIRS})
 | 
					aux_source_directory(endpoints ENDPOINTS_SRC)
 | 
				
			||||||
# link_libraries(${DROGON_LIBRARIES})
 | 
					 | 
				
			||||||
##########
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# find_package(Drogon CONFIG REQUIRED)
 | 
					configure_file("core.ini" "core.ini" COPYONLY)
 | 
				
			||||||
# include_directories(${DROGON_INCLUDE_DIRS})
 | 
					 | 
				
			||||||
# link_libraries(${DROGON_LIBRARIES})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(CMAKE_CXX_STANDARD LESS 17)
 | 
					target_sources(core PRIVATE ${VENDOR_SRC} ${SRC_DIR} ${HANDLERS_SRC} ${HELPERS_SRC} ${MODELS_SRC} ${ENDPOINTS_SRC})
 | 
				
			||||||
    #With C++14, use boost to support any and string_view
 | 
					target_include_directories(core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
 | 
				
			||||||
    message(STATUS "use c++14")
 | 
					target_include_directories(core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor)
 | 
				
			||||||
    find_package(Boost 1.61.0 REQUIRED)
 | 
					 | 
				
			||||||
    include_directories(${Boost_INCLUDE_DIRS})
 | 
					 | 
				
			||||||
else()
 | 
					 | 
				
			||||||
    message(STATUS "use c++17")
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
aux_source_directory(./ SRC_DIR)
 | 
					 | 
				
			||||||
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)
 | 
					 | 
				
			||||||
foreach(cspFile ${SCP_LIST})
 | 
					 | 
				
			||||||
    message(STATUS "cspFile:" ${cspFile})
 | 
					 | 
				
			||||||
    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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 | 
					 | 
				
			||||||
add_executable(core ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC} ${HELPER_SRC})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
add_subdirectory(drogon)
 | 
					 | 
				
			||||||
target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_custom_target(migrations
 | 
					add_custom_target(migrations
 | 
				
			||||||
    COMMAND ./compile_migrations.sh
 | 
					    COMMAND ./compile_migrations.sh
 | 
				
			||||||
| 
						 | 
					@ -73,23 +30,32 @@ add_custom_target(migrations
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_custom_target(run
 | 
					add_custom_target(run
 | 
				
			||||||
    COMMAND core
 | 
					    COMMAND ./core start
 | 
				
			||||||
    DEPENDS core
 | 
					    DEPENDS core
 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
					    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
add_custom_target(debug
 | 
					add_custom_target(debug
 | 
				
			||||||
    COMMAND valgrind ./core
 | 
					    COMMAND valgrind ./core start
 | 
				
			||||||
    DEPENDS core
 | 
					    DEPENDS core
 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
					    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
add_custom_target(debug-full
 | 
					add_custom_target(debug-full
 | 
				
			||||||
    COMMAND valgrind --leak-check=full --show-leak-kinds=all ./core
 | 
					    COMMAND valgrind --leak-check=full --show-leak-kinds=all ./core start
 | 
				
			||||||
    DEPENDS core
 | 
					    DEPENDS core
 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
					    WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					add_custom_target(docs
 | 
				
			||||||
 | 
					    COMMAND doxygen
 | 
				
			||||||
 | 
					    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_custom_target(test
 | 
					add_custom_target(test
 | 
				
			||||||
    COMMAND ./run_tests.sh ${CMAKE_BINARY_DIR}/core ${CMAKE_SOURCE_DIR}/config.testing.json
 | 
					    COMMAND ./run_tests.sh ${CMAKE_BINARY_DIR}/core "dev"
 | 
				
			||||||
    DEPENDS core
 | 
					    DEPENDS core
 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tavern_tests
 | 
					    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					add_custom_target(coverage
 | 
				
			||||||
 | 
					    COMMAND gcovr -s --root ${CMAKE_SOURCE_DIR} -e ${CMAKE_SOURCE_DIR}/vendor --html-details ${CMAKE_BINARY_DIR}/coverage.html --html-title "Emgauwa Core Coverage" ${CMAKE_BINARY_DIR}/CMakeFiles/core.dir
 | 
				
			||||||
 | 
					    DEPENDS test
 | 
				
			||||||
 | 
					    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										141
									
								
								command.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								command.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,141 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <command.h>
 | 
				
			||||||
 | 
					#include <mpack.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					#include <enums.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					command_set_relay_schedule(relay_t *relay)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    controller_t *controller = controller_get_by_id(relay->controller_id);
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("couldn't find controller\n");
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char* payload;
 | 
				
			||||||
 | 
					    size_t payload_size;
 | 
				
			||||||
 | 
					    mpack_writer_t writer;
 | 
				
			||||||
 | 
					    mpack_writer_init_growable(&writer, &payload, &payload_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 3 = code, relay num, relay name, schedules(array)
 | 
				
			||||||
 | 
					    mpack_start_map(&writer, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
 | 
				
			||||||
 | 
					    mpack_write_u8(&writer, COMMAND_CODE_SET_SCHEDULE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mpack_write_uint(&writer, COMMAND_MAPPING_RELAY_NUM);
 | 
				
			||||||
 | 
					    mpack_write_u8(&writer, relay->number);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULES_ARRAY);
 | 
				
			||||||
 | 
					    // 7 = days of week
 | 
				
			||||||
 | 
					    mpack_start_array(&writer, 7);
 | 
				
			||||||
 | 
					    for(int i = 0; i < 7; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uint16_t *periods_blob = schedule_periods_to_blob(relay->schedules[i]);
 | 
				
			||||||
 | 
					        uint16_t periods_count = periods_blob[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 3 = code, relaynum, schedules(array)
 | 
				
			||||||
 | 
					        mpack_start_map(&writer, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_COUNT);
 | 
				
			||||||
 | 
					        mpack_write_u16(&writer, periods_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULE_ID);
 | 
				
			||||||
 | 
					        mpack_write_bin(&writer, (char*)relay->schedules[0]->uid, sizeof(uuid_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_BLOB);
 | 
				
			||||||
 | 
					        // periods + 1 to skip length in periods[0]
 | 
				
			||||||
 | 
					        // periods_count * 2 because each uint16_t is a timestamp. 2 are start and end
 | 
				
			||||||
 | 
					        mpack_write_bin(&writer, (char*)(periods_blob + 1), sizeof(uint16_t) * periods_count * 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mpack_finish_map(&writer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        free(periods_blob);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mpack_finish_array(&writer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mpack_finish_map(&writer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // finish writing
 | 
				
			||||||
 | 
					    if (mpack_writer_destroy(&writer) != mpack_ok)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("an error occurred encoding the data");
 | 
				
			||||||
 | 
					        controller_free(controller);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int result = command_send(controller, COMMAND_CODE_SET_SCHEDULE, payload, payload_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					    free(payload);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					command_set_controller_name(controller_t *controller)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char* payload;
 | 
				
			||||||
 | 
					    size_t payload_size;
 | 
				
			||||||
 | 
					    mpack_writer_t writer;
 | 
				
			||||||
 | 
					    mpack_writer_init_growable(&writer, &payload, &payload_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // write the example on the msgpack homepage
 | 
				
			||||||
 | 
					    mpack_start_map(&writer, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
 | 
				
			||||||
 | 
					    mpack_write_u8(&writer, COMMAND_CODE_SET_NAME);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mpack_write_uint(&writer, COMMAND_MAPPING_NAME);
 | 
				
			||||||
 | 
					    mpack_write_cstr(&writer, controller->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mpack_finish_map(&writer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // finish writing
 | 
				
			||||||
 | 
					    if (mpack_writer_destroy(&writer) != mpack_ok)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("an error occurred encoding the data");
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int result = command_send(controller, COMMAND_CODE_SET_NAME, payload, payload_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(payload);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					command_send(controller_t *controller, int command_code, char *payload, uint32_t payload_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LOG_DEBUG("commanding %d\n", command_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int bytes_transferred;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int fd_controller = helper_connect_tcp_server(controller->ip, controller->port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(fd_controller == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("can't open command socket %s:%d\n", controller->ip, controller->port);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if((bytes_transferred = send(fd_controller, &payload_size, sizeof(payload_size), 0)) <= 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error during sending size\n");
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if((bytes_transferred = send(fd_controller, payload, payload_size, 0)) <= 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error during sending\n");
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    close(fd_controller);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								config.cc
									
										
									
									
									
								
							
							
						
						
									
										23
									
								
								config.cc
									
										
									
									
									
								
							| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace config
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    char version[] = "0.0.1";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint16_t discover_max_client_backlog = 20;
 | 
					 | 
				
			||||||
    uint16_t discover_port_dev = 4421;
 | 
					 | 
				
			||||||
    uint16_t discover_port_test = 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
 | 
					 | 
				
			||||||
							
								
								
									
										12
									
								
								config.json
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								config.json
									
										
									
									
									
								
							| 
						 | 
					@ -1,12 +0,0 @@
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    "listeners": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "address": "0.0.0.0",
 | 
					 | 
				
			||||||
            "port": 5000,
 | 
					 | 
				
			||||||
            "https": false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "custom_config": {
 | 
					 | 
				
			||||||
        "db_name": "core.sqlite"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										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,12 +0,0 @@
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    "listeners": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "address": "0.0.0.0",
 | 
					 | 
				
			||||||
            "port": 5000,
 | 
					 | 
				
			||||||
            "https": false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "custom_config": {
 | 
					 | 
				
			||||||
        "db_name": "core.testing.sqlite"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,180 +0,0 @@
 | 
				
			||||||
#include <models/controller_dbo.h>
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#include <enums.h>
 | 
					 | 
				
			||||||
#include <mpack.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_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uuid_t controller_id;
 | 
					 | 
				
			||||||
    if(uuid_parse(controller_id_str.c_str(), controller_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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::get_one_by_tag(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
 | 
					 | 
				
			||||||
                            const std::string &controller_tag)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("tag", controller_tag.c_str(), (intptr_t) &sqlite3_bind_text, -1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uuid_t controller_id;
 | 
					 | 
				
			||||||
    if(uuid_parse(controller_id_str.c_str(), controller_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value body = *req->getJsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uuid_t controller_id;
 | 
					 | 
				
			||||||
    if(uuid_parse(controller_id_str.c_str(), controller_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            char* data;
 | 
					 | 
				
			||||||
            size_t size;
 | 
					 | 
				
			||||||
            mpack_writer_t writer;
 | 
					 | 
				
			||||||
            mpack_writer_init_growable(&writer, &data, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // write the example on the msgpack homepage
 | 
					 | 
				
			||||||
            mpack_start_map(&writer, 2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
 | 
					 | 
				
			||||||
            mpack_write_u8(&writer, config::command_code_set_name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_write_uint(&writer, COMMAND_MAPPING_NAME);
 | 
					 | 
				
			||||||
            mpack_write_cstr(&writer, controllers[0]->name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_finish_map(&writer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // finish writing
 | 
					 | 
				
			||||||
            if (mpack_writer_destroy(&writer) != mpack_ok) {
 | 
					 | 
				
			||||||
                LOG_ERROR << "an error occurred encoding the data";
 | 
					 | 
				
			||||||
                auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
                resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
                callback(resp);
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            controllers[0]->command(config::command_code_set_name, data, size);
 | 
					 | 
				
			||||||
            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,33 +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::get_one_by_tag, "/tag/{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_str);
 | 
					 | 
				
			||||||
            static void get_one_by_tag(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_tag);
 | 
					 | 
				
			||||||
            static void delete_one_by_id(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id_str);
 | 
					 | 
				
			||||||
            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_str);
 | 
					 | 
				
			||||||
            static void get_relays_one_by_id_and_num(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& controller_id_str, 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_str, int relay_num);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,187 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <cmath>
 | 
					 | 
				
			||||||
#include <uuid/uuid.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <mpack.h>
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <models/controller_dbo.h>
 | 
					 | 
				
			||||||
#include "api_v1_controllers.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace api::v1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum DISCOVERY_MAPPING
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    DISCOVERY_MAPPING_ID = 0,
 | 
					 | 
				
			||||||
    DISCOVERY_MAPPING_NAME = 1,
 | 
					 | 
				
			||||||
    DISCOVERY_MAPPING_COMMAND_PORT = 2,
 | 
					 | 
				
			||||||
    DISCOVERY_MAPPING_RELAY_COUNT = 3,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int16_t payload[1];
 | 
					 | 
				
			||||||
    payload[0] = discover_server_port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(helpers::send_udp_broadcast("255.255.255.255", config::discover_port_dev, payload, sizeof(payload)) < 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];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            size_t payload_length;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(recv(client_fd, &payload_length, sizeof(payload_length), 0) <= 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_ERROR << "Error Receiving header from client";
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            char *answer_payload = (char*)malloc((payload_length));
 | 
					 | 
				
			||||||
            ssize_t bytes_transferred;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if((bytes_transferred = 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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            uuid_t discovered_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_tree_t tree;
 | 
					 | 
				
			||||||
            mpack_tree_init_data(&tree, answer_payload, payload_length);
 | 
					 | 
				
			||||||
            mpack_tree_parse(&tree);
 | 
					 | 
				
			||||||
            mpack_node_t root = mpack_tree_root(&tree);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            memcpy(discovered_id, mpack_node_data(mpack_node_map_uint(root, DISCOVERY_MAPPING_ID)), sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            uint16_t discovered_command_port = mpack_node_u16(mpack_node_map_uint(root, DISCOVERY_MAPPING_COMMAND_PORT));
 | 
					 | 
				
			||||||
            uint8_t discovered_relay_count = mpack_node_u8(mpack_node_map_uint(root, DISCOVERY_MAPPING_RELAY_COUNT));
 | 
					 | 
				
			||||||
            const char *discovered_name = mpack_node_str(mpack_node_map_uint(root, DISCOVERY_MAPPING_NAME));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            bool found_discovered_in_list = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for(int i = 0; known_controllers[i] != nullptr; i++)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if(!found_discovered_in_list)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if(uuid_compare(known_controllers[i]->id, discovered_id) == 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        known_controllers[i]->active = true;
 | 
					 | 
				
			||||||
                        strncpy(known_controllers[i]->name, discovered_name, 128);
 | 
					 | 
				
			||||||
                        known_controllers[i]->name[127] = '\0';
 | 
					 | 
				
			||||||
                        known_controllers[i]->port = discovered_command_port;
 | 
					 | 
				
			||||||
                        known_controllers[i]->relay_count = discovered_relay_count;
 | 
					 | 
				
			||||||
                        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));
 | 
					 | 
				
			||||||
                memcpy(discovered_controller.id, discovered_id, sizeof(uuid_t));
 | 
					 | 
				
			||||||
                strcpy(discovered_controller.name, discovered_name);
 | 
					 | 
				
			||||||
                discovered_controller.relay_count = discovered_relay_count;
 | 
					 | 
				
			||||||
                discovered_controller.port = discovered_command_port;
 | 
					 | 
				
			||||||
                discovered_controller.active = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                discovered_controller.insert();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            mpack_tree_destroy(&tree);
 | 
					 | 
				
			||||||
            free(answer_payload);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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,268 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <models/relay_dbo.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <mpack.h>
 | 
					 | 
				
			||||||
#include <models/controller_dbo.h>
 | 
					 | 
				
			||||||
#include <models/schedule_dbo.h>
 | 
					 | 
				
			||||||
#include <models/junction_tag_dbo.h>
 | 
					 | 
				
			||||||
#include <models/tag_dbo.h>
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#include <enums.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_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uuid_t controller_id;
 | 
					 | 
				
			||||||
    if(uuid_parse(controller_id_str.c_str(), controller_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    relay_dbo **all_controller_relays = relay_dbo::get_by_simple("controller_id", (void *) controller_id, (intptr_t) sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
    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_str,
 | 
					 | 
				
			||||||
                                      int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uuid_t controller_id;
 | 
					 | 
				
			||||||
    if(uuid_parse(controller_id_str.c_str(), controller_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id, 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_str,
 | 
					 | 
				
			||||||
                                      int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uuid_t controller_id;
 | 
					 | 
				
			||||||
    if(uuid_parse(controller_id_str.c_str(), controller_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_DEBUG << "bad uuid";
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if(!relay_dbo::valid_num_for_controller(controller_id, relay_num))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_DEBUG << "invalid num for controller";
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value body = *req->getJsonObject();
 | 
					 | 
				
			||||||
    bool set_name = body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    bool set_tags = body["tags"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
    bool set_schedules = body["schedules"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
    bool set_active_schedule = body["active_schedule"].type() == Json::ValueType::objectValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id, relay_num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo **schedule_list;
 | 
					 | 
				
			||||||
    schedule_dbo *active_schedule;
 | 
					 | 
				
			||||||
    schedule_dbo *schedules[7];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_schedules)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        uuid_t schedules_ids[7];
 | 
					 | 
				
			||||||
        for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(schedule_dbo::parse_uid(body["schedules"][i]["id"].asCString(), schedules_ids[i]))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_DEBUG << "parse_uid failed for schedule " << i;
 | 
					 | 
				
			||||||
                auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
                res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
                callback(res);
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            schedule_list = schedule_dbo::get_by_simple("uid", schedules_ids[i], (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
            schedules[i] = schedule_list[0];
 | 
					 | 
				
			||||||
            free(schedule_list);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_active_schedule)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        uuid_t active_schedule_id;
 | 
					 | 
				
			||||||
        if(schedule_dbo::parse_uid(body["active_schedule"]["id"].asCString(), active_schedule_id))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            LOG_DEBUG << "bad active_schedule uuid";
 | 
					 | 
				
			||||||
            auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
            resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
            callback(resp);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        schedule_list = schedule_dbo::get_by_simple("uid", active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
        active_schedule = schedule_list[0];
 | 
					 | 
				
			||||||
        free(schedule_list);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!relay)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        relay = new relay_dbo();
 | 
					 | 
				
			||||||
        relay->number = relay_num;
 | 
					 | 
				
			||||||
        uuid_copy(relay->controller_id, controller_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            relay->schedules[i] = schedule_dbo::get_by_id_or_off(0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_name)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        strncpy(relay->name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_tags)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        junction_tag_dbo::remove_for_relay(relay->id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(int i = 0; i < body["tags"].size(); ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            const char *tag = body["tags"][i].asCString();
 | 
					 | 
				
			||||||
            int tag_id = tag_dbo::get_id(tag);
 | 
					 | 
				
			||||||
            if(tag_id == 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                tag_dbo::save(tag_id, tag);
 | 
					 | 
				
			||||||
                tag_id = tag_dbo::get_id(tag);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            junction_tag_dbo::insert(tag_id, relay->id, 0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_schedules)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            relay->schedules[i] = schedules[i];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        relay->active_schedule = schedules[helpers::get_day_of_week()];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_active_schedule)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        relay->schedules[helpers::get_day_of_week()] = active_schedule;
 | 
					 | 
				
			||||||
        relay->active_schedule = active_schedule;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!relay->save())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        char* data;
 | 
					 | 
				
			||||||
        size_t size;
 | 
					 | 
				
			||||||
        mpack_writer_t writer;
 | 
					 | 
				
			||||||
        mpack_writer_init_growable(&writer, &data, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 3 = code, relay num, relay name, schedules(array)
 | 
					 | 
				
			||||||
        mpack_start_map(&writer, 3);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
 | 
					 | 
				
			||||||
        mpack_write_u8(&writer, config::command_code_set_schedule);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mpack_write_uint(&writer, COMMAND_MAPPING_RELAY_NUM);
 | 
					 | 
				
			||||||
        mpack_write_u8(&writer, relay->number);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULES_ARRAY);
 | 
					 | 
				
			||||||
        // 7 = days of week
 | 
					 | 
				
			||||||
        mpack_start_array(&writer, 7);
 | 
					 | 
				
			||||||
        for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            uint16_t *periods = relay->schedules[i]->periods->to_blob();
 | 
					 | 
				
			||||||
            uint16_t periods_count = periods[0];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // 3 = code, relaynum, schedules(array)
 | 
					 | 
				
			||||||
            mpack_start_map(&writer, 3);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_COUNT);
 | 
					 | 
				
			||||||
            mpack_write_u16(&writer, periods_count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULE_ID);
 | 
					 | 
				
			||||||
            mpack_write_bin(&writer, (char*)relay->schedules[0]->uid, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_BLOB);
 | 
					 | 
				
			||||||
            // periods + 1 to skip length in periods[0]
 | 
					 | 
				
			||||||
            // periods_count * 2 because each uint16_t is a timestamp. 2 are start and end
 | 
					 | 
				
			||||||
            mpack_write_bin(&writer, (char*)(periods + 1), sizeof(uint16_t) * periods_count * 2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mpack_finish_map(&writer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            free(periods);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        mpack_finish_array(&writer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mpack_finish_map(&writer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // finish writing
 | 
					 | 
				
			||||||
        if (mpack_writer_destroy(&writer) != mpack_ok) {
 | 
					 | 
				
			||||||
            LOG_ERROR << "an error occurred encoding the data";
 | 
					 | 
				
			||||||
            auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
            resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
            callback(resp);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        controllers[0]->command(config::command_code_set_name, data, size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpJsonResponse(relay->to_json());
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        controller_dbo::free_list(controllers);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    delete relay;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,54 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <models/relay_dbo.h>
 | 
					 | 
				
			||||||
#include <models/tag_dbo.h>
 | 
					 | 
				
			||||||
#include <models/junction_tag_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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
relays::get_by_tag(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
 | 
					 | 
				
			||||||
                       const std::string &tag)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int tag_id = tag_dbo::get_id(tag.c_str());
 | 
					 | 
				
			||||||
    int *relays_ids = junction_tag_dbo::get_relays_for_tag_id(tag_id);
 | 
					 | 
				
			||||||
    if(relays_ids == nullptr)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value relays_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; relays_ids[i] != 0; ++i)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        relay_dbo *relay = relay_dbo::get_by_id(relays_ids[i]);
 | 
					 | 
				
			||||||
        if(relay)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            relays_json.append(relay->to_json());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(relays_json);
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
    free(relays_ids);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +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_ADD(relays::get_by_tag, "/tag/{1}", Get, Options);
 | 
					 | 
				
			||||||
            METHOD_LIST_END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            static void get_all(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback);
 | 
					 | 
				
			||||||
            static void get_by_tag(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& tag);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,277 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <models/schedule_dbo.h>
 | 
					 | 
				
			||||||
#include <models/tag_dbo.h>
 | 
					 | 
				
			||||||
#include <models/junction_tag_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_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uuid_t schedule_id;
 | 
					 | 
				
			||||||
    if(schedule_dbo::parse_uid(schedule_id_str.c_str(), schedule_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo **schedules = schedule_dbo::get_by_simple("uid", schedule_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(strcmp(schedule_id_str.c_str(), "off") == 0 || strcmp(schedule_id_str.c_str(), "on") == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k403Forbidden);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uuid_t schedule_id;
 | 
					 | 
				
			||||||
    if(schedule_dbo::parse_uid(schedule_id_str.c_str(), schedule_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    schedule_dbo **schedules = schedule_dbo::get_by_simple("uid", schedule_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool set_name = body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    bool set_tags = body["tags"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
    //bool set_periods = body["periods"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!set_name || !set_name)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo new_schedule{};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    strncpy(new_schedule.name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
    new_schedule.name[127] = '\0';
 | 
					 | 
				
			||||||
    uuid_generate(new_schedule.uid);
 | 
					 | 
				
			||||||
    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::post_list(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Json::Value body = *req->jsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value schedules_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; i < body.size(); ++i)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        bool set_name = body[i]["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
        bool set_tags = body[i]["tags"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
        //bool set_periods = body[i]["periods"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(!set_name || !set_name)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
            resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
            callback(resp);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        schedule_dbo new_schedule{};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        strncpy(new_schedule.name, body[i]["name"].asCString(), 127);
 | 
					 | 
				
			||||||
        new_schedule.name[127] = '\0';
 | 
					 | 
				
			||||||
        uuid_generate(new_schedule.uid);
 | 
					 | 
				
			||||||
        new_schedule.periods = helpers::parse_periods(body[i]["periods"]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(new_schedule.insert())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            schedules_json.append(new_schedule.to_json());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(schedules_json);
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedules::put_one_by_id(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
 | 
					 | 
				
			||||||
                         const std::string &schedule_id_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uuid_t schedule_id;
 | 
					 | 
				
			||||||
    if(schedule_dbo::parse_uid(schedule_id_str.c_str(), schedule_id))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    schedule_dbo **schedules = schedule_dbo::get_by_simple("uid", schedule_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(schedules[0] == nullptr)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k404NotFound);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value body = *req->jsonObject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool set_name = body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    bool set_tags = body["tags"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
    bool set_periods = body["periods"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_name)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        strncpy(schedules[0]->name, body["name"].asCString(), 127);
 | 
					 | 
				
			||||||
        schedules[0]->name[127] = '\0';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_periods)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // if neither "off" nor "on" allow overwrite of periods
 | 
					 | 
				
			||||||
        if(strcmp(schedule_id_str.c_str(), "off") && strcmp(schedule_id_str.c_str(), "on"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            delete schedules[0]->periods;
 | 
					 | 
				
			||||||
            schedules[0]->periods = helpers::parse_periods(body["periods"]);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_tags)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        junction_tag_dbo::remove_for_schedule(schedules[0]->id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(int i = 0; i < body["tags"].size(); ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            const char *tag = body["tags"][i].asCString();
 | 
					 | 
				
			||||||
            int tag_id = tag_dbo::get_id(tag);
 | 
					 | 
				
			||||||
            if(tag_id == 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                tag_dbo::save(tag_id, tag);
 | 
					 | 
				
			||||||
                tag_id = tag_dbo::get_id(tag);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            junction_tag_dbo::insert(tag_id, 0, schedules[0]->id);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!schedules[0]->update())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpJsonResponse(schedules[0]->to_json());
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
schedules::get_by_tag(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
 | 
					 | 
				
			||||||
                       const std::string &tag)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int tag_id = tag_dbo::get_id(tag.c_str());
 | 
					 | 
				
			||||||
    int *schedules_ids = junction_tag_dbo::get_schedules_for_tag_id(tag_id);
 | 
					 | 
				
			||||||
    if(schedules_ids == nullptr)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto resp = HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        resp->setStatusCode(k500InternalServerError);
 | 
					 | 
				
			||||||
        callback(resp);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value schedules_json(Json::arrayValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(int i = 0; schedules_ids[i] != 0; ++i)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        schedule_dbo *schedule = schedule_dbo::get_by_id(schedules_ids[i]);
 | 
					 | 
				
			||||||
        if(schedule)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            schedules_json.append(schedule->to_json());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto resp = HttpResponse::newHttpJsonResponse(schedules_json);
 | 
					 | 
				
			||||||
    callback(resp);
 | 
					 | 
				
			||||||
    free(schedules_ids);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,31 +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::post_list, "/list", Post, Options, "filters::json_required");
 | 
					 | 
				
			||||||
            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(schedules::get_by_tag, "/tag/{1}", Get, Options);
 | 
					 | 
				
			||||||
            //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 post_list(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);
 | 
					 | 
				
			||||||
            static void get_by_tag(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, const std::string& tag);
 | 
					 | 
				
			||||||
            //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);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
							
								
								
									
										7
									
								
								core.ini
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								core.ini
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					[core]
 | 
				
			||||||
 | 
					server-port = 5000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					: 4421 for dev-env; 4420 for testing-env; 4419 for prod-env; 4422 for testing
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								drogon
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								drogon
									
										
									
									
									
								
							| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
Subproject commit 543d1a8c8062b3873ef89c64ffd7394c6dd7c7e8
 | 
					 | 
				
			||||||
							
								
								
									
										48
									
								
								endpoints/api_v1_controllers.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								endpoints/api_v1_controllers.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_controllers.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)args;
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					    controller_t** all_controllers = controller_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; all_controllers[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_controller = controller_to_json(all_controllers[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json, json_controller);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print controllers json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for controllers";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    controller_free_list(all_controllers);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										240
									
								
								endpoints/api_v1_controllers_STR.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								endpoints/api_v1_controllers_STR.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,240 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <command.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_controllers.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(uuid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t* controller = controller_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a controller for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no controller for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = controller_to_json(controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print controller json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for controller";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_PUT(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(uuid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t* controller = controller_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a controller for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no controller for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_ParseWithLength(hm->body.p, hm->body.len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(json == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const char *error_ptr = cJSON_GetErrorPtr();
 | 
				
			||||||
 | 
					        if (error_ptr != NULL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("error before: %s\n", error_ptr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no valid json was supplied";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name");
 | 
				
			||||||
 | 
					    if(cJSON_IsString(json_name) && json_name->valuestring)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        strncpy(controller->name, json_name->valuestring, MAX_NAME_LENGTH);
 | 
				
			||||||
 | 
					        controller->name[MAX_NAME_LENGTH] = '\0';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_ip = cJSON_GetObjectItemCaseSensitive(json, "ip");
 | 
				
			||||||
 | 
					    if(cJSON_IsString(json_ip) && json_ip->valuestring)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        strncpy(controller->ip, json_ip->valuestring, IP_LENGTH);
 | 
				
			||||||
 | 
					        controller->ip[IP_LENGTH] = '\0';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(controller_save(controller))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to save controller\n");
 | 
				
			||||||
 | 
					        free(controller);
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to save controller to database";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    json = controller_to_json(controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    command_set_controller_name(controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print controller json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for controller";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_DELETE(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *target_uid_str = args[0].value.v_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(uuid_parse(target_uid_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t* controller = controller_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a controller for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no controller for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(controller_remove(controller))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to remove controller from database\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to remove controller from database";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = 0;
 | 
				
			||||||
 | 
					        response->content = "";
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										77
									
								
								endpoints/api_v1_controllers_STR_relays.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								endpoints/api_v1_controllers_STR_relays.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,77 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_controllers.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_relays_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(uuid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t* controller = controller_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a controller for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no controller for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    relay_t** all_relays = relay_get_by_controller_id(controller->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; all_relays[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_relay = relay_to_json(all_relays[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json, json_relay);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print relays json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for relays";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    relay_free_list(all_relays);
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										315
									
								
								endpoints/api_v1_controllers_STR_relays_INT.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								endpoints/api_v1_controllers_STR_relays_INT.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,315 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <command.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_controllers.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_relays_INT_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(uuid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t* controller = controller_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a controller for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no controller for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t* relay = relay_get_for_controller(controller->id, args[1].value.v_int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!relay)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a relay with num %d for controller '%s'\n", args[1].value.v_int, args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no relay for this controller found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = relay_to_json(relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print relay json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for relay";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    relay_free(relay);
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_relays_INT_PUT(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(uuid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t* controller = controller_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a controller for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no controller for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t* relay = relay_get_for_controller(controller->id, args[1].value.v_int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!relay)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        relay = malloc(sizeof(relay_t));
 | 
				
			||||||
 | 
					        relay->id = 0;
 | 
				
			||||||
 | 
					        relay->number = args[1].value.v_int;
 | 
				
			||||||
 | 
					        snprintf(relay->name, MAX_NAME_LENGTH, "Relay %d", relay->number);
 | 
				
			||||||
 | 
					        relay->name[MAX_NAME_LENGTH] = '\0';
 | 
				
			||||||
 | 
					        relay->controller_id = controller->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uuid_t tmp_uuid;
 | 
				
			||||||
 | 
					        memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					        memcpy(tmp_uuid, "off", 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(int i = 0; i < 7; ++i)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            relay->schedules[i] = schedule_get_by_uid(tmp_uuid);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        time_t timestamp = time(NULL);
 | 
				
			||||||
 | 
					        struct tm *time_struct = localtime(×tamp);
 | 
				
			||||||
 | 
					        relay->active_schedule = relay->schedules[helper_get_weekday(time_struct)];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no valid json was supplied";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name");
 | 
				
			||||||
 | 
					    if(cJSON_IsString(json_name) && json_name->valuestring)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        strncpy(relay->name, json_name->valuestring, MAX_NAME_LENGTH);
 | 
				
			||||||
 | 
					        relay->name[MAX_NAME_LENGTH] = '\0';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_schedule;
 | 
				
			||||||
 | 
					    cJSON *json_schedules = cJSON_GetObjectItemCaseSensitive(json, "schedules");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(cJSON_GetArraySize(json_schedules) == 7)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int schedule_position = 0;
 | 
				
			||||||
 | 
					        cJSON_ArrayForEach(json_schedule, json_schedules)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            cJSON *json_schedule_uid = cJSON_GetObjectItemCaseSensitive(json_schedule, "id");
 | 
				
			||||||
 | 
					            if(!cJSON_IsString(json_schedule_uid) || (json_schedule_uid->valuestring == NULL))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_DEBUG("schedules[%d] is missing uid\n", schedule_position);
 | 
				
			||||||
 | 
					                cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                static const char content[] = "at least one schedule is missing an id";
 | 
				
			||||||
 | 
					                response->status_code = 400;
 | 
				
			||||||
 | 
					                response->content_type = "text/plain";
 | 
				
			||||||
 | 
					                response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					                response->content = content;
 | 
				
			||||||
 | 
					                response->alloced_content = false;
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            uuid_t target_uid;
 | 
				
			||||||
 | 
					            if(schedule_uid_parse(json_schedule_uid->valuestring, target_uid))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_DEBUG("schedules[%d] has bad uid\n", schedule_position);
 | 
				
			||||||
 | 
					                cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                static const char content[] = "at least one schedule has a bad id";
 | 
				
			||||||
 | 
					                response->status_code = 400;
 | 
				
			||||||
 | 
					                response->content_type = "text/plain";
 | 
				
			||||||
 | 
					                response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					                response->content = content;
 | 
				
			||||||
 | 
					                response->alloced_content = false;
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            schedule_free(relay->schedules[schedule_position]);
 | 
				
			||||||
 | 
					            relay->schedules[schedule_position] = schedule_get_by_uid_or_off(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ++schedule_position;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_active_schedule = cJSON_GetObjectItemCaseSensitive(json, "active_schedule");
 | 
				
			||||||
 | 
					    if(cJSON_IsObject(json_active_schedule))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_active_schedule_uid = cJSON_GetObjectItemCaseSensitive(json_active_schedule, "id");
 | 
				
			||||||
 | 
					        if(cJSON_IsString(json_active_schedule_uid) && json_active_schedule_uid->valuestring)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            time_t timestamp = time(NULL);
 | 
				
			||||||
 | 
					            struct tm *time_struct = localtime(×tamp);
 | 
				
			||||||
 | 
					            int day_of_week = helper_get_weekday(time_struct);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            schedule_free(relay->schedules[day_of_week]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uuid_t target_uid;
 | 
				
			||||||
 | 
					            if(schedule_uid_parse(json_active_schedule_uid->valuestring, target_uid))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_DEBUG("active_schedule has bad uid\n");
 | 
				
			||||||
 | 
					                cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                static const char content[] = "active_schedule has a bad id";
 | 
				
			||||||
 | 
					                response->status_code = 400;
 | 
				
			||||||
 | 
					                response->content_type = "text/plain";
 | 
				
			||||||
 | 
					                response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					                response->content = content;
 | 
				
			||||||
 | 
					                response->alloced_content = false;
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            relay->schedules[day_of_week] = schedule_get_by_uid_or_off(target_uid);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(relay_save(relay))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to save relay\n");
 | 
				
			||||||
 | 
					        free(controller);
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to save relay to database";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_tag;
 | 
				
			||||||
 | 
					    cJSON *json_tags = cJSON_GetObjectItemCaseSensitive(json, "tags");
 | 
				
			||||||
 | 
					    if(cJSON_IsArray(json_tags))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        junction_tag_remove_for_relay(relay->id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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, relay->id, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    json = relay_to_json(relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    command_set_relay_schedule(relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print relay json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for relay";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    relay_free(relay);
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										307
									
								
								endpoints/api_v1_controllers_discover.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								endpoints/api_v1_controllers_discover.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,307 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_controllers.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <mpack.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DISCOVERY_TIMEOUT_MS 2000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_ID = 0,
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_NAME = 1,
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_COMMAND_PORT = 2,
 | 
				
			||||||
 | 
					    DISCOVERY_MAPPING_RELAY_COUNT = 3,
 | 
				
			||||||
 | 
					} discovery_mapping_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					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: %s\n", 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: %s\n", status);
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((status = listen(fd, max_client_backlog)) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error setting up listener: %s\n", status);
 | 
				
			||||||
 | 
					        freeaddrinfo(res);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    freeaddrinfo(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					send_udp_broadcast(const char *addr, uint16_t port, void *message, size_t length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct sockaddr_in their_addr;
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error creating socket\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int broadcast = 1;
 | 
				
			||||||
 | 
					    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error setting broadcast\n");
 | 
				
			||||||
 | 
					        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, length, 0, (struct sockaddr *)&their_addr, sizeof(their_addr)) < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("error sending broadcast (%d): '%s'\n", errno, strerror(errno));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_discover_POST(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int discover_server_socket = bind_tcp_server("0.0.0.0", "0", 20);
 | 
				
			||||||
 | 
					    int discover_server_port = get_server_port(discover_server_socket);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(discover_server_port == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to get server port for discovery\n");
 | 
				
			||||||
 | 
					        static const char content[] = "";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int16_t payload[1];
 | 
				
			||||||
 | 
					    payload[0] = discover_server_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(send_udp_broadcast("255.255.255.255", global_config.discovery_port, payload, sizeof(payload)) < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to send UDP broadcast\n");
 | 
				
			||||||
 | 
					        static const char content[] = "";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        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];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t **known_controllers = controller_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 = DISCOVERY_TIMEOUT_MS / 1000;
 | 
				
			||||||
 | 
					        timeout.tv_usec = (DISCOVERY_TIMEOUT_MS % 1000) * 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s_ret = select(discover_server_socket + 1, &accept_fds, NULL, NULL, &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 %s\n", strerror(errno));
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            size_t payload_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(recv(client_fd, &payload_length, sizeof(payload_length), 0) <= 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error receiving header from client\n");
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            char *answer_payload = (char*)malloc((payload_length));
 | 
				
			||||||
 | 
					            ssize_t bytes_transferred;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if((bytes_transferred = recv(client_fd, answer_payload, payload_length, 0)) <= 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error receiving payload from client\n");
 | 
				
			||||||
 | 
					                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\n");
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uuid_t discovered_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mpack_tree_t tree;
 | 
				
			||||||
 | 
					            mpack_tree_init_data(&tree, answer_payload, payload_length);
 | 
				
			||||||
 | 
					            mpack_tree_parse(&tree);
 | 
				
			||||||
 | 
					            mpack_node_t root = mpack_tree_root(&tree);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            memcpy(discovered_id, mpack_node_data(mpack_node_map_uint(root, DISCOVERY_MAPPING_ID)), sizeof(uuid_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint16_t discovered_command_port = mpack_node_u16(mpack_node_map_uint(root, DISCOVERY_MAPPING_COMMAND_PORT));
 | 
				
			||||||
 | 
					            uint8_t discovered_relay_count = mpack_node_u8(mpack_node_map_uint(root, DISCOVERY_MAPPING_RELAY_COUNT));
 | 
				
			||||||
 | 
					            const char *discovered_name = mpack_node_str(mpack_node_map_uint(root, DISCOVERY_MAPPING_NAME));
 | 
				
			||||||
 | 
					            size_t discovered_name_len = mpack_node_strlen(mpack_node_map_uint(root, DISCOVERY_MAPPING_NAME));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(discovered_name_len > MAX_NAME_LENGTH)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                discovered_name_len = MAX_NAME_LENGTH;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bool found_discovered_in_list = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for(int i = 0; known_controllers[i] != NULL; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if(!found_discovered_in_list)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if(uuid_compare(known_controllers[i]->uid, discovered_id) == 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        known_controllers[i]->active = 1;
 | 
				
			||||||
 | 
					                        strncpy(known_controllers[i]->name, discovered_name, discovered_name_len);
 | 
				
			||||||
 | 
					                        known_controllers[i]->name[discovered_name_len] = '\0';
 | 
				
			||||||
 | 
					                        known_controllers[i]->port = discovered_command_port;
 | 
				
			||||||
 | 
					                        known_controllers[i]->relay_count = discovered_relay_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        controller_save(known_controllers[i]);
 | 
				
			||||||
 | 
					                        controller_free(known_controllers[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        found_discovered_in_list = 1;
 | 
				
			||||||
 | 
					                        known_controllers[i] = known_controllers[i + 1];
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    known_controllers[i] = known_controllers[i + 1];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!found_discovered_in_list)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                controller_t *discovered_controller = malloc(sizeof(controller_t));
 | 
				
			||||||
 | 
					                discovered_controller->id = 0;
 | 
				
			||||||
 | 
					                strcpy(discovered_controller->ip, inet_ntoa(addr.sin_addr));
 | 
				
			||||||
 | 
					                memcpy(discovered_controller->uid, discovered_id, sizeof(uuid_t));
 | 
				
			||||||
 | 
					                strncpy(discovered_controller->name, discovered_name, discovered_name_len);
 | 
				
			||||||
 | 
					                discovered_controller->name[discovered_name_len] = '\0';
 | 
				
			||||||
 | 
					                discovered_controller->relay_count = discovered_relay_count;
 | 
				
			||||||
 | 
					                discovered_controller->port = discovered_command_port;
 | 
				
			||||||
 | 
					                discovered_controller->active = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                controller_save(discovered_controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // TODO get relays during discovery and don't create empty ones
 | 
				
			||||||
 | 
					                relay_t **discovered_relays = malloc(sizeof(relay_t*) * (discovered_controller->relay_count + 1));
 | 
				
			||||||
 | 
					                for(int i = 0; i < discovered_controller->relay_count; ++i)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    relay_t *new_relay = malloc(sizeof(relay_t));
 | 
				
			||||||
 | 
					                    new_relay->id = 0;
 | 
				
			||||||
 | 
					                    sprintf(new_relay->name, "Relay %d", i + 1);
 | 
				
			||||||
 | 
					                    new_relay->number = i;
 | 
				
			||||||
 | 
					                    new_relay->controller_id = discovered_controller->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    uuid_t tmp_uuid;
 | 
				
			||||||
 | 
					                    memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					                    memcpy(tmp_uuid, "off", 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for(int i = 0; i < 7; ++i)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new_relay->schedules[i] = schedule_get_by_uid(tmp_uuid);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    time_t timestamp = time(NULL);
 | 
				
			||||||
 | 
					                    struct tm *time_struct = localtime(×tamp);
 | 
				
			||||||
 | 
					                    new_relay->active_schedule = new_relay->schedules[helper_get_weekday(time_struct)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    relay_save(new_relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    discovered_relays[i] = new_relay;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                discovered_relays[discovered_controller->relay_count] = NULL;
 | 
				
			||||||
 | 
					                discovered_controller->relays = discovered_relays;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                controller_free(discovered_controller);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            mpack_tree_destroy(&tree);
 | 
				
			||||||
 | 
					            free(answer_payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            discover_answer_buf[0] = 0; // TODO add discovery return codes
 | 
				
			||||||
 | 
					            send(client_fd, discover_answer_buf, sizeof(uint8_t), 0);
 | 
				
			||||||
 | 
					            close(client_fd);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for(int i = 0; known_controllers[i] != NULL; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        known_controllers[i]->active = false;
 | 
				
			||||||
 | 
					        controller_save(known_controllers[i]);
 | 
				
			||||||
 | 
					        LOG_DEBUG("lost: %s\n", known_controllers[i]->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    controller_free_list(known_controllers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    api_v1_controllers_GET(hm, args, response);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								endpoints/api_v1_relays.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								endpoints/api_v1_relays.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_relays.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_relays_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)args;
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					    relay_t** all_relays = relay_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; all_relays[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_relay = relay_to_json(all_relays[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json, json_relay);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print relays json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for relays";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    relay_free_list(all_relays);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								endpoints/api_v1_relays_tag_STR.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								endpoints/api_v1_relays_tag_STR.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_relays.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_relays_tag_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int tag_id = tag_get_id(args[0].value.v_str);
 | 
				
			||||||
 | 
					    int *relays_ids = junction_tag_get_relays_for_tag_id(tag_id);
 | 
				
			||||||
 | 
					    if(relays_ids == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to load relays for tag from database\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to load relays for tag from database";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; relays_ids[i] != 0; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        relay_t* relay = relay_get_by_id(relays_ids[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!relay)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cJSON *json_relay = relay_to_json(relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json, json_relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        relay_free(relay);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print relays json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for relays";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    free(relays_ids);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										187
									
								
								endpoints/api_v1_schedules.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								endpoints/api_v1_schedules.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,187 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.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 http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no valid json was supplied";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name");
 | 
				
			||||||
 | 
					    if(!cJSON_IsString(json_name) || (json_name->valuestring == NULL))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("no name for schedule provided\n");
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no name for schedule provided";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        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");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for schedule";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 201;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    schedule_free(new_schedule);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (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");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for schedules";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    schedule_free_list(all_schedules);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										324
									
								
								endpoints/api_v1_schedules_STR.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								endpoints/api_v1_schedules_STR.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,324 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <endpoints/api_v1_schedules.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <command.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/junction_relay_schedule.h>
 | 
				
			||||||
 | 
					#include <models/schedule.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(schedule_uid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t* schedule = schedule_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!schedule)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a schedule for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no schedule for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json =  schedule_to_json(schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print schedules json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for schedules";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    schedule_free(schedule);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_PUT(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(schedule_uid_parse(args[0].value.v_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t* schedule = schedule_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!schedule)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a schedule for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no schedule for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_ParseWithLength(hm->body.p, hm->body.len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(json == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const char *error_ptr = cJSON_GetErrorPtr();
 | 
				
			||||||
 | 
					        if (error_ptr != NULL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_DEBUG("error before: %s\n", error_ptr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no valid json was supplied";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name");
 | 
				
			||||||
 | 
					    if(cJSON_IsString(json_name) && json_name->valuestring)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        strncpy(schedule->name, json_name->valuestring, MAX_NAME_LENGTH);
 | 
				
			||||||
 | 
					        schedule->name[MAX_NAME_LENGTH] = '\0';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!schedule_is_protected(schedule))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON *json_period;
 | 
				
			||||||
 | 
					        cJSON *json_periods = cJSON_GetObjectItemCaseSensitive(json, "periods");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int periods_count = cJSON_GetArraySize(json_periods);
 | 
				
			||||||
 | 
					        free(schedule->periods);
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            schedule->periods[periods_valid].start = start;
 | 
				
			||||||
 | 
					            schedule->periods[periods_valid].end = end;
 | 
				
			||||||
 | 
					            ++periods_valid;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        schedule->periods_count = periods_valid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(schedule_save(schedule))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to save schedule\n");
 | 
				
			||||||
 | 
					        free(schedule);
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to save schedule to database";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t **relays = relay_get_with_schedule(schedule->id);
 | 
				
			||||||
 | 
					    for(int i = 0; relays[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        command_set_relay_schedule(relays[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_tag;
 | 
				
			||||||
 | 
					    cJSON *json_tags = cJSON_GetObjectItemCaseSensitive(json, "tags");
 | 
				
			||||||
 | 
					    if(cJSON_IsArray(json_tags))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        junction_tag_remove_for_schedule(schedule->id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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, schedule->id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    json = schedule_to_json(schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print schedule json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for schedule";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    relay_free_list(relays);
 | 
				
			||||||
 | 
					    schedule_free(schedule);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_DELETE(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *target_uid_str = args[0].value.v_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uuid_t target_uid;
 | 
				
			||||||
 | 
					    if(schedule_uid_parse(target_uid_str, target_uid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to unparse uid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "given id was invalid";
 | 
				
			||||||
 | 
					        response->status_code = 400;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t* schedule = schedule_get_by_uid(target_uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!schedule)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("could not find a schedule for uid '%s'\n", args[0].value.v_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "no schedule for id found";
 | 
				
			||||||
 | 
					        response->status_code = 404;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(schedule_is_protected(schedule))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        static const char content[] = "target schedule is protected";
 | 
				
			||||||
 | 
					        response->status_code = 403;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        schedule_free(schedule);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(schedule_remove(schedule))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to remove schedule from database\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to remove schedule from database";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = 0;
 | 
				
			||||||
 | 
					        response->content = "";
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    schedule_free(schedule);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								endpoints/api_v1_schedules_tag_STR.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								endpoints/api_v1_schedules_tag_STR.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <macros.h>
 | 
				
			||||||
 | 
					#include <constants.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_tag_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)hm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int tag_id = tag_get_id(args[0].value.v_str);
 | 
				
			||||||
 | 
					    int *schedules_ids = junction_tag_get_schedules_for_tag_id(tag_id);
 | 
				
			||||||
 | 
					    if(schedules_ids == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to load schedules for tag from database\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to load schedules for tag from database";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; schedules_ids[i] != 0; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        schedule_t* schedule = schedule_get_by_id(schedules_ids[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!schedule)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cJSON *json_schedule = schedule_to_json(schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json, json_schedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        schedule_free(schedule);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *json_str = cJSON_Print(json);
 | 
				
			||||||
 | 
					    if (json_str == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_ERROR("failed to print schedules json\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static const char content[] = "failed to print json for schedules";
 | 
				
			||||||
 | 
					        response->status_code = 500;
 | 
				
			||||||
 | 
					        response->content_type = "text/plain";
 | 
				
			||||||
 | 
					        response->content_length = STRLEN(content);;
 | 
				
			||||||
 | 
					        response->content = content;
 | 
				
			||||||
 | 
					        response->alloced_content = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        response->status_code = 200;
 | 
				
			||||||
 | 
					        response->content_type = "application/json";
 | 
				
			||||||
 | 
					        response->content_length = strlen(json_str);
 | 
				
			||||||
 | 
					        response->content = json_str;
 | 
				
			||||||
 | 
					        response->alloced_content = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_Delete(json);
 | 
				
			||||||
 | 
					    free(schedules_ids);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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,126 +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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // level 1
 | 
					 | 
				
			||||||
    bool set_name = body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    bool set_tags = body["tags"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
    bool set_schedules = body["schedules"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
    bool set_active_schedule = body["active_schedule"].type() == Json::ValueType::objectValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // level 2
 | 
					 | 
				
			||||||
    if(is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(set_tags)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for(int i = 0; i < body["tags"].size(); ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                is_valid &= body["tags"][i].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(set_active_schedule)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            is_valid &= body["active_schedule"]["id"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(set_schedules)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                is_valid &= body["schedules"][i].type() == Json::ValueType::objectValue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // level 3
 | 
					 | 
				
			||||||
    if(is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(set_schedules)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                is_valid &= body["schedules"][i]["id"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_DEBUG << "basic structe is wrong";
 | 
					 | 
				
			||||||
        auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
        res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
        fcb(res);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_active_schedule)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        uuid_t active_schedule_id;
 | 
					 | 
				
			||||||
        if(schedule_dbo::parse_uid(body["active_schedule"]["id"].asCString(), active_schedule_id))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            LOG_DEBUG << "parse_uid failed for active_schedule";
 | 
					 | 
				
			||||||
            auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
            res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
            fcb(res);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        schedule_dbo **schedules = schedule_dbo::get_by_simple("uid", active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
        bool schedule_found = schedules[0] != nullptr;
 | 
					 | 
				
			||||||
        schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
        if(!schedule_found)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            LOG_DEBUG << "could not find active_schedule";
 | 
					 | 
				
			||||||
            auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
            res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
            fcb(res);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(set_schedules)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        uuid_t schedules_ids[7];
 | 
					 | 
				
			||||||
        for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(schedule_dbo::parse_uid(body["schedules"][i]["id"].asCString(), schedules_ids[i]))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_DEBUG << "parse_uid failed for schedule " << i;
 | 
					 | 
				
			||||||
                auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
                res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
                fcb(res);
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            schedule_dbo **schedules = schedule_dbo::get_by_simple("uid", schedules_ids[i], (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
            bool schedule_found = schedules[0] != nullptr;
 | 
					 | 
				
			||||||
            schedule_dbo::free_list(schedules);
 | 
					 | 
				
			||||||
            if(!schedule_found)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                LOG_DEBUG << "could not find schedule " << i;
 | 
					 | 
				
			||||||
                auto res = drogon::HttpResponse::newHttpResponse();
 | 
					 | 
				
			||||||
                res->setStatusCode(k400BadRequest);
 | 
					 | 
				
			||||||
                fcb(res);
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Passed
 | 
					 | 
				
			||||||
    fccb();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,66 +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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool set_name = body["name"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
    bool set_tags = body["tags"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
    bool set_periods = body["periods"].type() == Json::ValueType::arrayValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // level 2
 | 
					 | 
				
			||||||
    if(is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(set_tags)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for(int i = 0; i < body["tags"].size(); ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                is_valid &= body["tags"][i].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(set_periods)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for(int i = 0; i < body["periods"].size(); ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                is_valid &= body["periods"][i].type() == Json::ValueType::objectValue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // level 3
 | 
					 | 
				
			||||||
    if(is_valid)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(set_periods)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for(int i = 0; i < body["periods"].size(); ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                is_valid &= body["periods"][i]["start"].type() == Json::ValueType::stringValue;
 | 
					 | 
				
			||||||
                is_valid &= body["periods"][i]["end"].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::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
 | 
					 | 
				
			||||||
							
								
								
									
										89
									
								
								handlers/connection.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								handlers/connection.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <mongoose.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					#include <handlers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STD_HEADERS "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *\r\n"
 | 
				
			||||||
 | 
					#define HEADERS_FMT STD_HEADERS "Content-Type: %s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -2 for "%s" -1 for \0
 | 
				
			||||||
 | 
					#define HEADERS_FMT_LEN (sizeof(HEADERS_FMT) - 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STD_RESPONSE_CONTENT "the server did not create a response"
 | 
				
			||||||
 | 
					#define STD_RESPONSE_CONTENT_LEN (sizeof(STD_RESPONSE_CONTENT) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					handler_connection(struct mg_connection *c, int ev, void *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (ev == MG_EV_HTTP_REQUEST)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        struct http_message *hm = (struct http_message *) p;
 | 
				
			||||||
 | 
					        LOG_DEBUG("new http %.*s request for %.*s\n", hm->method.len, hm->method.p, hm->uri.len, hm->uri.p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        endpoint_t *endpoint = router_find_endpoint(hm->uri.p, hm->uri.len, &hm->method);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(endpoint)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(endpoint->func)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                endpoint_response_t response;
 | 
				
			||||||
 | 
					                response.status_code = 500;
 | 
				
			||||||
 | 
					                response.content_type = "text/plain";
 | 
				
			||||||
 | 
					                response.content_length = STD_RESPONSE_CONTENT_LEN;
 | 
				
			||||||
 | 
					                response.content = STD_RESPONSE_CONTENT;
 | 
				
			||||||
 | 
					                response.alloced_content = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                endpoint->func(p, endpoint->args, &response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                char *response_headers = malloc(sizeof(char) * (HEADERS_FMT_LEN + strlen(response.content_type) + 1));
 | 
				
			||||||
 | 
					                sprintf(response_headers, HEADERS_FMT, response.content_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                mg_send_head(c, response.status_code, response.content_length, response_headers);
 | 
				
			||||||
 | 
					                mg_printf(c, "%s", response.content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                free(response_headers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(response.alloced_content)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    free((char*)response.content);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for(int i = 0; i < endpoint->args_count; ++i)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if(endpoint->args[i].type == ENDPOINT_ARG_TYPE_STR)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        free((char*)endpoint->args[i].value.v_str);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if(endpoint->method == HTTP_METHOD_OPTIONS)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    char options_header[256]; // TODO make more generic
 | 
				
			||||||
 | 
					                    sprintf(options_header, STD_HEADERS "Allow: OPTIONS%s%s%s%s",
 | 
				
			||||||
 | 
					                            endpoint->options & HTTP_METHOD_GET ? ", GET" : "",
 | 
				
			||||||
 | 
					                            endpoint->options & HTTP_METHOD_POST ? ", POST" : "",
 | 
				
			||||||
 | 
					                            endpoint->options & HTTP_METHOD_PUT ? ", PUT" : "",
 | 
				
			||||||
 | 
					                            endpoint->options & HTTP_METHOD_DELETE ? ", DELETE" : ""
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                    mg_send_head(c, 204, 0, options_header);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    mg_send_head(c, 501, 0, "Content-Type: text/plain");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            mg_send_head(c, 500, 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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								helpers.h
									
										
									
									
									
								
							
							
						
						
									
										47
									
								
								helpers.h
									
										
									
									
									
								
							| 
						 | 
					@ -1,47 +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, void *message, size_t length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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, int bind_func_param, const char *logic);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const char *col_name;
 | 
					 | 
				
			||||||
        const void *value;
 | 
					 | 
				
			||||||
        intptr_t bind_func;
 | 
					 | 
				
			||||||
        int bind_func_param;
 | 
					 | 
				
			||||||
        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();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int
 | 
					 | 
				
			||||||
    get_day_of_week();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_HELPERS_H
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,62 +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*)filter->value));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(filter->bind_func == (intptr_t)&sqlite3_bind_text)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sqlite3_bind_text(stmt, i + 1, (char*)filter->value, filter->bind_func_param, SQLITE_STATIC);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(filter->bind_func == (intptr_t)&sqlite3_bind_blob)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sqlite3_bind_blob(stmt, i + 1, filter->value, filter->bind_func_param, SQLITE_STATIC);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return stmt;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
helpers::sql_filter_builder::sql_filter_builder(const char *col_name, const void *value, intptr_t bind_func, int bind_func_param, const char *logic)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->col_name = col_name;
 | 
					 | 
				
			||||||
    this->value = value;
 | 
					 | 
				
			||||||
    this->bind_func = bind_func;
 | 
					 | 
				
			||||||
    this->bind_func_param = bind_func_param;
 | 
					 | 
				
			||||||
    this->logic = logic;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,12 +0,0 @@
 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
helpers::get_day_of_week()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    time_t t = time(NULL);
 | 
					 | 
				
			||||||
    struct tm *now = localtime(&t);
 | 
					 | 
				
			||||||
    int wday_sun_sat = now->tm_wday;
 | 
					 | 
				
			||||||
    int wday_mon_sun = (wday_sun_sat + 6) % 7;
 | 
					 | 
				
			||||||
    return wday_mon_sun;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										11
									
								
								helpers/get_weekday.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								helpers/get_weekday.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_get_weekday(const struct tm *time_struct)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int wday_sun_sat = time_struct->tm_wday;
 | 
				
			||||||
 | 
					    int wday_mon_sun = (wday_sun_sat + 6) % 7;
 | 
				
			||||||
 | 
					    return wday_mon_sun;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,66 +0,0 @@
 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <globals.h>
 | 
					 | 
				
			||||||
#include <uuid/uuid.h>
 | 
					 | 
				
			||||||
#include <drogon/trantor/trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <drogon/utils/Utilities.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:
 | 
					 | 
				
			||||||
            LOG_INFO << "Migrating LEVEL 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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,35 +0,0 @@
 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <string.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 " << strerror(errno);
 | 
					 | 
				
			||||||
        freeaddrinfo(res);
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    freeaddrinfo(res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return s;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										54
									
								
								helpers/parse_cli.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								helpers/parse_cli.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					#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[] = {
 | 
				
			||||||
 | 
					    "core [options] [[--] args]",
 | 
				
			||||||
 | 
					    "core [options]",
 | 
				
			||||||
 | 
					    NULL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config->run_type = RUN_TYPE_INVALID;
 | 
				
			||||||
 | 
					        if(strcmp(argv[0], "start") == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config->run_type = RUN_TYPE_START;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        LOG_FATAL("bad action '%s' given ('start')\n", argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_FATAL("no action given ('start')\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, void *message, size_t length)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    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, length, 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
 | 
				
			||||||
							
								
								
									
										16
									
								
								include/command.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								include/command.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					#ifndef CORE_COMMAND_H
 | 
				
			||||||
 | 
					#define CORE_COMMAND_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					command_set_relay_schedule(relay_t *relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					command_set_controller_name(controller_t *controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					command_send(controller_t *controller, int command_code, char *payload, uint32_t payload_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_COMMAND_H */
 | 
				
			||||||
							
								
								
									
										39
									
								
								include/config.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/config.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					#ifndef CORE_CONFIG_H
 | 
				
			||||||
 | 
					#define CORE_CONFIG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <confini.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    RUN_TYPE_START,
 | 
				
			||||||
 | 
					    RUN_TYPE_INVALID,
 | 
				
			||||||
 | 
					} 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 */
 | 
				
			||||||
							
								
								
									
										30
									
								
								include/endpoints/api_v1_controllers.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								include/endpoints/api_v1_controllers.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ENDPOINTS_API_V1_CONTROLLERS_H
 | 
				
			||||||
 | 
					#define CORE_ENDPOINTS_API_V1_CONTROLLERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_discover_POST(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_PUT(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_DELETE(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_relays_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_relays_INT_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_controllers_STR_relays_INT_PUT(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_ENDPOINTS_API_V1_CONTROLLERS_H */
 | 
				
			||||||
							
								
								
									
										12
									
								
								include/endpoints/api_v1_relays.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								include/endpoints/api_v1_relays.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ENDPOINTS_API_V1_RELAYS_H
 | 
				
			||||||
 | 
					#define CORE_ENDPOINTS_API_V1_RELAYS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_relays_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_relays_tag_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_ENDPOINTS_API_V1_RELAYS_H */
 | 
				
			||||||
							
								
								
									
										24
									
								
								include/endpoints/api_v1_schedules.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								include/endpoints/api_v1_schedules.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ENDPOINTS_API_V1_SCHEDULES_H
 | 
				
			||||||
 | 
					#define CORE_ENDPOINTS_API_V1_SCHEDULES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <router.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_POST(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_PUT(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_STR_DELETE(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					api_v1_schedules_tag_STR_GET(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_ENDPOINTS_API_V1_SCHEDULES_H */
 | 
				
			||||||
							
								
								
									
										40
									
								
								include/enums.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								include/enums.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ENUMS_H
 | 
				
			||||||
 | 
					#define CORE_ENUMS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    POLL_FDS_DISCOVERY,
 | 
				
			||||||
 | 
					    POLL_FDS_COMMAND
 | 
				
			||||||
 | 
					} poll_fds_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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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 */
 | 
				
			||||||
							
								
								
									
										17
									
								
								include/helpers.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								include/helpers.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#ifndef CORE_HELPERS_H
 | 
				
			||||||
 | 
					#define CORE_HELPERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#include <confini.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_connect_tcp_server(char* host, uint16_t port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					helper_parse_cli(int argc, const char **argv, config_t *config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					helper_get_weekday(const struct tm *time_struct);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_HELPERS_H */
 | 
				
			||||||
							
								
								
									
										26
									
								
								include/logger.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								include/logger.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					#ifndef CORE_LOGGER_H
 | 
				
			||||||
 | 
					#define CORE_LOGGER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <colors.h>
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SOURCE_PATH_SIZE
 | 
				
			||||||
 | 
					    #define SOURCE_PATH_SIZE 0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
							
								
								
									
										1
									
								
								include/macros.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								include/macros.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					#define STRLEN(s) ((sizeof(s)/sizeof(s[0])) - sizeof(s[0]))
 | 
				
			||||||
							
								
								
									
										0
									
								
								include/migrations/.gitkeep
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								include/migrations/.gitkeep
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										53
									
								
								include/models/controller.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								include/models/controller.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					#ifndef CORE_MODELS_CONTROLLER_H
 | 
				
			||||||
 | 
					#define CORE_MODELS_CONTROLLER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <uuid/uuid.h>
 | 
				
			||||||
 | 
					#include <sqlite3.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IP_LENGTH 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int id;
 | 
				
			||||||
 | 
					    uuid_t uid;
 | 
				
			||||||
 | 
					    char name[MAX_NAME_LENGTH + 1];
 | 
				
			||||||
 | 
					    char ip[IP_LENGTH + 1];
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON*
 | 
				
			||||||
 | 
					controller_to_json(controller_t* contoller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					controller_t*
 | 
				
			||||||
 | 
					controller_get_by_id(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					controller_t*
 | 
				
			||||||
 | 
					controller_get_by_uid(uuid_t uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 */
 | 
				
			||||||
							
								
								
									
										22
									
								
								include/models/junction_relay_schedule.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								include/models/junction_relay_schedule.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					#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_get_relays_ids(int schedule_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 */
 | 
				
			||||||
							
								
								
									
										60
									
								
								include/models/relay.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								include/models/relay.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,60 @@
 | 
				
			||||||
 | 
					#ifndef CORE_RELAY_H
 | 
				
			||||||
 | 
					#define CORE_RELAY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <uuid/uuid.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <helpers.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					#include <models/schedule.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int id;
 | 
				
			||||||
 | 
					    char name[MAX_NAME_LENGTH + 1];
 | 
				
			||||||
 | 
					    int number;
 | 
				
			||||||
 | 
					    int controller_id;
 | 
				
			||||||
 | 
					    int active_schedule_id;
 | 
				
			||||||
 | 
					    schedule_t *active_schedule;
 | 
				
			||||||
 | 
					    schedule_t *schedules[7];
 | 
				
			||||||
 | 
					} relay_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					relay_save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					relay_remove();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					relay_reload_active_schedule(relay_t *relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON*
 | 
				
			||||||
 | 
					relay_to_json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					relay_free(relay_t *relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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_for_controller(int controller_id, int relay_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_with_schedule(int schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_by_controller_id(int controller_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CORE_RELAY_H */
 | 
				
			||||||
							
								
								
									
										67
									
								
								include/models/schedule.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								include/models/schedule.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,67 @@
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_is_protected(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_id_or_off(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_id(int id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_uid_or_off(uuid_t uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_uid(uuid_t uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t**
 | 
				
			||||||
 | 
					schedule_get_relay_weekdays(int relay_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 */
 | 
				
			||||||
							
								
								
									
										73
									
								
								include/router.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								include/router.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,73 @@
 | 
				
			||||||
 | 
					#ifndef CORE_ROUTER_H
 | 
				
			||||||
 | 
					#define CORE_ROUTER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mongoose.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ENDPOINTS_MAX_COUNT 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ENDPOINT_ARG_TYPE_INT,
 | 
				
			||||||
 | 
					    ENDPOINT_ARG_TYPE_STR
 | 
				
			||||||
 | 
					} endpoint_arg_type_e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HTTP_METHOD_GET     = (1 << 0),
 | 
				
			||||||
 | 
					    HTTP_METHOD_POST    = (1 << 1),
 | 
				
			||||||
 | 
					    HTTP_METHOD_PUT     = (1 << 2),
 | 
				
			||||||
 | 
					    HTTP_METHOD_DELETE  = (1 << 3),
 | 
				
			||||||
 | 
					    HTTP_METHOD_OPTIONS = (1 << 4)
 | 
				
			||||||
 | 
					} http_method_e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    endpoint_arg_type_e type;
 | 
				
			||||||
 | 
					    union
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int v_int;
 | 
				
			||||||
 | 
					        const char *v_str;
 | 
				
			||||||
 | 
					    } value;
 | 
				
			||||||
 | 
					} endpoint_args_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int status_code;
 | 
				
			||||||
 | 
					    const char *content_type;
 | 
				
			||||||
 | 
					    size_t content_length;
 | 
				
			||||||
 | 
					    const char *content;
 | 
				
			||||||
 | 
					    int alloced_content;
 | 
				
			||||||
 | 
					} endpoint_response_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void (*endpoint_func_f)(struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char *full_route;
 | 
				
			||||||
 | 
					    char **route;
 | 
				
			||||||
 | 
					    char *route_keeper;
 | 
				
			||||||
 | 
					    int method;
 | 
				
			||||||
 | 
					    int options;
 | 
				
			||||||
 | 
					    endpoint_func_f func;
 | 
				
			||||||
 | 
					    int trailing_slash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int args_count;
 | 
				
			||||||
 | 
					    endpoint_args_t *args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int possible_route;
 | 
				
			||||||
 | 
					    int args_found;
 | 
				
			||||||
 | 
					} endpoint_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					router_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endpoint_t*
 | 
				
			||||||
 | 
					router_register_endpoint(const char *route, int method, endpoint_func_f func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endpoint_t*
 | 
				
			||||||
 | 
					router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										109
									
								
								main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								main.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,109 @@
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_exec(global_database, "PRAGMA foreign_keys = ON", 0, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /******************** 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										74
									
								
								main.cc
									
										
									
									
									
								
							
							
						
						
									
										74
									
								
								main.cc
									
										
									
									
									
								
							| 
						 | 
					@ -1,74 +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(int argc, char** argv)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    signal(SIGINT, terminate);
 | 
					 | 
				
			||||||
    signal(SIGABRT, terminate);
 | 
					 | 
				
			||||||
    signal(SIGTERM, terminate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const char* config_file_name = "config.json";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(argc == 2)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        config_file_name = argv[1];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Load config file
 | 
					 | 
				
			||||||
    drogon::app().loadConfigFile(config_file_name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const char* db_name = drogon::app().instance().getCustomConfig()["db_name"].asCString();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Open database */
 | 
					 | 
				
			||||||
    int rc = sqlite3_open(db_name, &globals::db);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(rc) {
 | 
					 | 
				
			||||||
        LOG_FATAL << "Can't open database: " << sqlite3_errmsg(globals::db);
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(helpers::migrate_sql())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        terminate(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										293
									
								
								models/controller.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								models/controller.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,293 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sqlite3.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					db_update_insert(controller_t *controller, sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, controller->id);
 | 
				
			||||||
 | 
					    sqlite3_bind_blob(stmt, 2, controller->uid, sizeof(uuid_t), SQLITE_STATIC);
 | 
				
			||||||
 | 
					    sqlite3_bind_text(stmt, 3, controller->name, -1, SQLITE_STATIC);
 | 
				
			||||||
 | 
					    sqlite3_bind_text(stmt, 4, controller->ip, -1, SQLITE_STATIC);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 5, controller->active);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 6, controller->port);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 7, controller->relay_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc != SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static controller_t*
 | 
				
			||||||
 | 
					controller_db_select_mapper(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    controller_t *new_controller = malloc(sizeof(controller_t));
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					                        new_controller->id = sqlite3_column_int(stmt, i);
 | 
				
			||||||
 | 
					                        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;
 | 
				
			||||||
 | 
					            case 'u': // uid
 | 
				
			||||||
 | 
					                uuid_copy(new_controller->uid, (const unsigned char*)sqlite3_column_blob(stmt, i));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default: // ignore columns not implemented
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    new_controller->relays = relay_get_by_controller_id(new_controller->id);
 | 
				
			||||||
 | 
					    return new_controller;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static controller_t**
 | 
				
			||||||
 | 
					controller_db_select(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    controller_t **all_controllers = malloc(sizeof(controller_t*));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int row = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					        if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            controller_t *new_controller = controller_db_select_mapper(stmt);
 | 
				
			||||||
 | 
					            row++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            all_controllers = (controller_t**)realloc(all_controllers, sizeof(controller_t*) * (row + 1));
 | 
				
			||||||
 | 
					            all_controllers[row - 1] = new_controller;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(s == SQLITE_DONE)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error selecting controllers from database: %s\n", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					    all_controllers[row] = NULL;
 | 
				
			||||||
 | 
					    return all_controllers;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					controller_save(controller_t *controller)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    if(controller->id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "UPDATE controllers set uid = ?2, name = ?3, ip = ?4, active = ?5, port = ?6, relay_count = ?7 WHERE id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "INSERT INTO controllers(uid, name, ip, active, port, relay_count) values (?2, ?3, ?4, ?5, ?6, ?7);", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int result = db_update_insert(controller, stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(controller->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
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(!controller->id)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            controller->id = sqlite3_last_insert_rowid(global_database);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					controller_remove(controller_t *controller)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    if(!controller->id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM controllers WHERE id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, controller->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc != SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					controller_free(controller_t *controller)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    relay_free_list(controller->relays);
 | 
				
			||||||
 | 
					    free(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					controller_free_list(controller_t **controllers)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(int i = 0; controllers[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        controller_free(controllers[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(controllers);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON*
 | 
				
			||||||
 | 
					controller_to_json(controller_t *controller)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_CreateString(controller->name);
 | 
				
			||||||
 | 
					    if(json_name == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "name", json_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char uuid_str[UUID_STR_LEN];
 | 
				
			||||||
 | 
					    uuid_unparse(controller->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_ip = cJSON_CreateString(controller->ip);
 | 
				
			||||||
 | 
					    if(json_ip == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "ip", json_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_port = cJSON_CreateNumber(controller->port);
 | 
				
			||||||
 | 
					    if(json_port == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "port", json_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_relay_count = cJSON_CreateNumber(controller->relay_count);
 | 
				
			||||||
 | 
					    if(json_relay_count == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "relay_count", json_relay_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_active = cJSON_CreateBool(controller->active);
 | 
				
			||||||
 | 
					    if(json_active == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "active", json_active);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t **relays = relay_get_by_controller_id(controller->id);
 | 
				
			||||||
 | 
					    cJSON *json_relays = cJSON_CreateArray();
 | 
				
			||||||
 | 
					    for(int i = 0; relays[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json_relays, relay_to_json(relays[i]));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "relays", json_relays);
 | 
				
			||||||
 | 
					    relay_free_list(relays);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return json;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					controller_t*
 | 
				
			||||||
 | 
					controller_get_by_id(int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM controllers WHERE id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t **sql_result = controller_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					controller_t*
 | 
				
			||||||
 | 
					controller_get_by_uid(uuid_t uid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM controllers WHERE uid = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_blob(stmt, 1, uid, sizeof(uuid_t), SQLITE_STATIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t **sql_result = controller_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					controller_t**
 | 
				
			||||||
 | 
					controller_get_all()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM controllers;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return controller_db_select(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,263 +0,0 @@
 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <uuid/uuid.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <mpack.h>
 | 
					 | 
				
			||||||
#include <enums.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_blob(stmt, 1, controller->id, sizeof(uuid_t), 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
 | 
					 | 
				
			||||||
                        uuid_copy(new_controller->id, (const unsigned char*)sqlite3_column_blob(stmt, i));
 | 
					 | 
				
			||||||
                        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_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
            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_blob(stmt, 1, this->id, sizeof(uuid_t), SQLITE_STATIC);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Json::Value
 | 
					 | 
				
			||||||
controller_dbo::to_json()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    char id_str[37];
 | 
					 | 
				
			||||||
    uuid_unparse(this->id, id_str);
 | 
					 | 
				
			||||||
    Json::Value controller_json;
 | 
					 | 
				
			||||||
    controller_json["name"] = this->name;
 | 
					 | 
				
			||||||
    controller_json["id"] = id_str;
 | 
					 | 
				
			||||||
    controller_json["ip"] = this->ip;
 | 
					 | 
				
			||||||
    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, int bind_func_param)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder *filters[1];
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                    key,
 | 
					 | 
				
			||||||
                    value,
 | 
					 | 
				
			||||||
                    bind_func,
 | 
					 | 
				
			||||||
                    bind_func_param,
 | 
					 | 
				
			||||||
                    ";"
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
    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, char *payload, uint32_t payload_size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    LOG_DEBUG << "Commanding " << command_code;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int bytes_transferred;
 | 
					 | 
				
			||||||
    char port_str[6];
 | 
					 | 
				
			||||||
    sprintf(port_str, "%d", this->port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int fd_controller = helpers::open_tcp_connection(this->ip, port_str);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(fd_controller == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "Can't open command socket " << this->ip << ":" << port_str;
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if((bytes_transferred = send(fd_controller, &payload_size, sizeof(payload_size), 0)) <= 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "error during sending size";
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if((bytes_transferred = send(fd_controller, payload, payload_size, 0)) <= 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOG_ERROR << "error during sending";
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    close(fd_controller);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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,54 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_controller_DBO_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_controller_DBO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <uuid/uuid.h>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "relay_dbo.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class controller_dbo
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uuid_t id;
 | 
					 | 
				
			||||||
    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, int bind_func_param);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static controller_dbo**
 | 
					 | 
				
			||||||
    get_by(helpers::sql_filter_builder **filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static controller_dbo**
 | 
					 | 
				
			||||||
    get_all();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    command(int command_code, char *payload, uint32_t payload_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static void
 | 
					 | 
				
			||||||
    free_list(controller_dbo **controllers_list);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_controller_DBO_H
 | 
					 | 
				
			||||||
							
								
								
									
										145
									
								
								models/junction_relay_schedule.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								models/junction_relay_schedule.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,145 @@
 | 
				
			||||||
 | 
					#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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 junction ids from database: %s\n", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					                return NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					    ids[row] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ids;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					junction_relay_schedule_get_schedule_id(uint8_t weekday, int relay_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int *id_list = get_ids(stmt); 
 | 
				
			||||||
 | 
					    int result = id_list[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(id_list);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int*
 | 
				
			||||||
 | 
					junction_relay_schedule_get_relays_ids(int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT relay_id FROM junction_relay_schedule WHERE schedule_id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return get_ids(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,112 +0,0 @@
 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "junction_relay_schedule_dbo.h"
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_relay_schedule_dbo::insert(uint8_t weekday, int relay_id, int schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "INSERT INTO junction_relay_schedule(weekday, schedule_id, relay_id) values (?1, ?2, ?3);", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        printf("ERROR inserting data: %s\n", sqlite3_errmsg(globals::db));
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
junction_relay_schedule_dbo::get_schedule_id(uint8_t weekday, int relay_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int result = 0;
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT schedule_id FROM junction_relay_schedule WHERE weekday=?1 AND relay_id=?2 LIMIT 1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    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 Selecting relays from database: " << sqlite3_errstr(s);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_relay_schedule_dbo::remove(uint8_t weekday, int relay_id, int schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM junction_relay_schedule WHERE weekday=?1 AND schedule_id=?2 AND relay_id=?3;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_relay_schedule_dbo::remove_for_relay(int relay_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM junction_relay_schedule WHERE relay_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, relay_id);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_relay_schedule_dbo::remove_for_schedule(int schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM junction_relay_schedule WHERE schedule_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,29 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_JUNCTION_RELAY_SCHEDULE_DBO_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_JUNCTION_RELAY_SCHEDULE_DBO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <uuid/uuid.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace junction_relay_schedule_dbo
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int
 | 
					 | 
				
			||||||
    get_schedule_id(uint8_t weekday, int relay_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    insert(uint8_t weekday, int relay_id, int schedule_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove(uint8_t weekday, int relay_id, int schedule_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove_for_relay(int relay_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove_for_schedule(int schedule_id);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_JUNCTION_RELAY_SCHEDULE_DBO_H
 | 
					 | 
				
			||||||
							
								
								
									
										194
									
								
								models/junction_tag.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								models/junction_tag.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,194 @@
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(schedule_id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_bind_int(stmt, 2, schedule_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_bind_null(stmt, 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(relay_id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_bind_int(stmt, 3, relay_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_bind_null(stmt, 3);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					            if(new_id != 0) // found row for other target (relay <> schedule)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,174 +0,0 @@
 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "junction_tag_dbo.h"
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_tag_dbo::insert(int tag_id, int relay_id, int schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "INSERT INTO junction_tag(tag_id, schedule_id, relay_id) values (?1, ?2, ?3);", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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(globals::db));
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int*
 | 
					 | 
				
			||||||
get_ids(sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto *ids = (int*)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: " << sqlite3_errstr(s);
 | 
					 | 
				
			||||||
                sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
                return nullptr;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
    ids[row] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ids;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int*
 | 
					 | 
				
			||||||
junction_tag_dbo::get_relays_for_tag_id(int tag_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT relay_id FROM junction_tag WHERE tag_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, tag_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return get_ids(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int*
 | 
					 | 
				
			||||||
junction_tag_dbo::get_schedules_for_tag_id(int tag_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT schedule_id FROM junction_tag WHERE tag_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, tag_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return get_ids(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int*
 | 
					 | 
				
			||||||
junction_tag_dbo::get_tags_for_relay_id(int relay_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT tag_id FROM junction_tag WHERE relay_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, relay_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return get_ids(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int*
 | 
					 | 
				
			||||||
junction_tag_dbo::get_tags_for_schedule_id(int schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "SELECT tag_id FROM junction_tag WHERE schedule_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return get_ids(stmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_tag_dbo::remove(int tag_id, int relay_id, int schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM junction_tag WHERE tag_id=?1 AND schedule_id=?2 AND relay_id=?3;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_tag_dbo::remove_for_tag(int tag_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM junction_tag WHERE tag_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, tag_id);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_tag_dbo::remove_for_relay(int relay_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM junction_tag WHERE relay_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, relay_id);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
junction_tag_dbo::remove_for_schedule(int schedule_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlite3_prepare_v2(globals::db, "DELETE FROM junction_tag WHERE schedule_id=?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
					 | 
				
			||||||
    rc = sqlite3_step(stmt);
 | 
					 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rc == SQLITE_DONE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,41 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_JUNCTION_TAG_DBO_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_JUNCTION_TAG_DBO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <uuid/uuid.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace junction_tag_dbo
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int*
 | 
					 | 
				
			||||||
    get_relays_for_tag_id(int tag_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int*
 | 
					 | 
				
			||||||
    get_schedules_for_tag_id(int tag_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int*
 | 
					 | 
				
			||||||
    get_tags_for_relay_id(int relay_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int*
 | 
					 | 
				
			||||||
    get_tags_for_schedule_id(int schedule_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    insert(int tag_id, int relay_id, int schedule_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove(int tag_id, int relay_id, int schedule_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove_for_tag(int tag_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove_for_relay(int relay_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    remove_for_schedule(int schedule_id);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_JUNCTION_TAG_DBO_H
 | 
					 | 
				
			||||||
							
								
								
									
										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_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_blob();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_PERIOD_LIST_H
 | 
					 | 
				
			||||||
							
								
								
									
										376
									
								
								models/relay.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										376
									
								
								models/relay.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,376 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sqlite3.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cJSON.h>
 | 
				
			||||||
 | 
					#include <logger.h>
 | 
				
			||||||
 | 
					#include <database.h>
 | 
				
			||||||
 | 
					#include <models/relay.h>
 | 
				
			||||||
 | 
					#include <models/controller.h>
 | 
				
			||||||
 | 
					#include <models/schedule.h>
 | 
				
			||||||
 | 
					#include <models/junction_tag.h>
 | 
				
			||||||
 | 
					#include <models/junction_relay_schedule.h>
 | 
				
			||||||
 | 
					#include <models/tag.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					db_update_insert(relay_t *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_int(stmt, 4, relay->controller_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc != SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static relay_t*
 | 
				
			||||||
 | 
					relay_db_select_mapper(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    relay_t *new_relay = malloc(sizeof(relay_t));
 | 
				
			||||||
 | 
					    for(int i = 0; i < sqlite3_column_count(stmt); i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const char *name = sqlite3_column_name(stmt, i);
 | 
				
			||||||
 | 
					        switch(name[0])
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case 'c': // controller_id
 | 
				
			||||||
 | 
					                new_relay->controller_id = sqlite3_column_int(stmt, i);
 | 
				
			||||||
 | 
					                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;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default: // ignore columns not implemented
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t **schedules = schedule_get_relay_weekdays(new_relay->id);
 | 
				
			||||||
 | 
					    for(int i = 0; i < 7; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(schedules[i] == NULL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG_ERROR("got only %d/7 schedules for relay_id %d\n", i, new_relay->id);
 | 
				
			||||||
 | 
					            relay_free(new_relay);
 | 
				
			||||||
 | 
					            free(schedules);
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        new_relay->schedules[i] = schedules[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(schedules); // don't free list, because contents are kept in relay->schedules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_reload_active_schedule(new_relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return new_relay;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static relay_t**
 | 
				
			||||||
 | 
					relay_db_select(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    relay_t **all_relays = malloc(sizeof(relay_t*));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int row = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					        if (s == SQLITE_ROW)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            relay_t *new_relay = relay_db_select_mapper(stmt);
 | 
				
			||||||
 | 
					            row++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            all_relays = (relay_t**)realloc(all_relays, sizeof(relay_t*) * (row + 1));
 | 
				
			||||||
 | 
					            all_relays[row - 1] = new_relay;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(s == SQLITE_DONE)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                LOG_ERROR("error selecting relays from database: %s\n", sqlite3_errstr(s));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					    all_relays[row] = NULL;
 | 
				
			||||||
 | 
					    return all_relays;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					relay_save(relay_t *relay)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    if(relay->id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "UPDATE relays set number = ?2, name = ?3, controller_id = ?4 WHERE id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        sqlite3_prepare_v2(global_database, "INSERT INTO relays(number, name, controller_id) values (?2, ?3, ?4);", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int result = db_update_insert(relay, stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(relay->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
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(relay->id == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            relay->id = sqlite3_last_insert_rowid(global_database);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    junction_relay_schedule_remove_for_relay(relay->id);
 | 
				
			||||||
 | 
					    for(int i = 0; i < 7; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        junction_relay_schedule_insert(i, relay->id, relay->schedules[i]->id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					relay_remove(relay_t *relay)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    if(!relay->id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM relays WHERE id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, relay->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc != SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					relay_reload_active_schedule(relay_t *relay)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    time_t timestamp = time(NULL);
 | 
				
			||||||
 | 
					    struct tm *time_struct = localtime(×tamp);
 | 
				
			||||||
 | 
					    relay->active_schedule = relay->schedules[helper_get_weekday(time_struct)];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					relay_free(relay_t *relay)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(int i = 0; i < 7; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        schedule_free(relay->schedules[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(relay);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					relay_free_list(relay_t **relays)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(int i = 0; relays[i] != NULL; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        relay_free(relays[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(relays);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON*
 | 
				
			||||||
 | 
					relay_to_json(relay_t *relay)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    relay_reload_active_schedule(relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json = cJSON_CreateObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_number = cJSON_CreateNumber(relay->number);
 | 
				
			||||||
 | 
					    if(json_number == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to make number\n");
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "number", json_number);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_name = cJSON_CreateString(relay->name);
 | 
				
			||||||
 | 
					    if(json_name == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to make name\n");
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "name", json_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_t *controller = controller_get_by_id(relay->controller_id);
 | 
				
			||||||
 | 
					    if(!controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_WARN("failed to get controller\n");
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char uuid_str[UUID_STR_LEN];
 | 
				
			||||||
 | 
					    uuid_unparse(controller->uid, uuid_str);
 | 
				
			||||||
 | 
					    cJSON *json_controller_id = cJSON_CreateString(uuid_str);
 | 
				
			||||||
 | 
					    if(json_controller_id == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOG_DEBUG("failed to make controller id\n");
 | 
				
			||||||
 | 
					        cJSON_Delete(json);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "controller_id", json_controller_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_free(controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "active_schedule", schedule_to_json(relay->active_schedule));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_schedules = cJSON_CreateArray();
 | 
				
			||||||
 | 
					    for(int i = 0; i < 7; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cJSON_AddItemToArray(json_schedules, schedule_to_json(relay->schedules[i]));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cJSON_AddItemToObject(json, "schedules", json_schedules);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON *json_tags = cJSON_CreateArray();
 | 
				
			||||||
 | 
					    int *tags_ids = junction_tag_get_tags_for_relay_id(relay->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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t*
 | 
				
			||||||
 | 
					relay_get_by_id(int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t **sql_result = relay_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t*
 | 
				
			||||||
 | 
					relay_get_by_uid(uuid_t uid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE uid = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_blob(stmt, 1, uid, sizeof(uuid_t), SQLITE_STATIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t **sql_result = relay_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_all()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM relays;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return relay_db_select(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_with_schedule(int schedule_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT DISTINCT relays.* FROM relays INNER JOIN junction_relay_schedule ON relays.id == junction_relay_schedule.relay_id WHERE junction_relay_schedule.schedule_id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, schedule_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return relay_db_select(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t*
 | 
				
			||||||
 | 
					relay_get_for_controller(int controller_id, int relay_num)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE controller_id = ?1 AND number = ?2;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, controller_id);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 2, relay_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t **sql_result = relay_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relay_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relay_t**
 | 
				
			||||||
 | 
					relay_get_by_controller_id(int controller_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE controller_id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, controller_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return relay_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,290 +0,0 @@
 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <trantor/utils/Logger.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "relay_dbo.h"
 | 
					 | 
				
			||||||
#include "globals.h"
 | 
					 | 
				
			||||||
#include "junction_relay_schedule_dbo.h"
 | 
					 | 
				
			||||||
#include "junction_tag_dbo.h"
 | 
					 | 
				
			||||||
#include "tag_dbo.h"
 | 
					 | 
				
			||||||
#include "controller_dbo.h"
 | 
					 | 
				
			||||||
#include "schedule_dbo.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool relay_db_update_insert(relay_dbo *relay, sqlite3_stmt *stmt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    junction_relay_schedule_dbo::remove_for_relay(relay->id);
 | 
					 | 
				
			||||||
    for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        junction_relay_schedule_dbo::insert(i, relay->id, relay->schedules[i]->id);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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_blob(stmt, 4, relay->controller_id, sizeof(uuid_t), 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 'c': // controller_id
 | 
					 | 
				
			||||||
                uuid_copy(new_relay->controller_id, (const unsigned char*)sqlite3_column_blob(stmt, i));
 | 
					 | 
				
			||||||
                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;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default: // ignore columns not implemented
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int schedule_id = junction_relay_schedule_dbo::get_schedule_id(i, new_relay->id);
 | 
					 | 
				
			||||||
        new_relay->schedules[i] = schedule_dbo::get_by_id_or_off(schedule_id);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
relay_dbo::save()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sqlite3_stmt *stmt;
 | 
					 | 
				
			||||||
    if(this->id)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        sqlite3_prepare_v2(globals::db, "UPDATE relays set number = ?2, name = ?3, controller_id = ?4 WHERE id = ?1;", -1, &stmt, nullptr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        sqlite3_prepare_v2(globals::db, "INSERT INTO relays(number, name, controller_id) values (?2, ?3, ?4);", -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()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->active_schedule = this->schedules[helpers::get_day_of_week()];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char controller_id_str[37];
 | 
					 | 
				
			||||||
    uuid_unparse(this->controller_id, controller_id_str);
 | 
					 | 
				
			||||||
    char active_schedule_uid_str[37];
 | 
					 | 
				
			||||||
    schedule_dbo::unparse_uid(this->active_schedule->uid, active_schedule_uid_str);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value schedules_json(Json::arrayValue);
 | 
					 | 
				
			||||||
    for(int i = 0; i < 7; ++i)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        schedules_json.append(this->schedules[i]->to_json());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value relay_json;
 | 
					 | 
				
			||||||
    relay_json["name"] = this->name;
 | 
					 | 
				
			||||||
    relay_json["number"] = this->number;
 | 
					 | 
				
			||||||
    relay_json["active_schedule_id"] = active_schedule_uid_str;
 | 
					 | 
				
			||||||
    relay_json["controller_id"] = controller_id_str;
 | 
					 | 
				
			||||||
    relay_json["active_schedule"] = this->active_schedule->to_json();
 | 
					 | 
				
			||||||
    relay_json["schedules"] = schedules_json;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Json::Value tags_json(Json::arrayValue);
 | 
					 | 
				
			||||||
    int *tags_ids = junction_tag_dbo::get_tags_for_relay_id(this->id);
 | 
					 | 
				
			||||||
    if(tags_ids != nullptr)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int tags_count;
 | 
					 | 
				
			||||||
        for(tags_count = 0; tags_ids[tags_count] != 0; ++tags_count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        char **tags = (char**)malloc(sizeof(char*) * tags_count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(int i = 0; i < tags_count; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            tags[i] = tag_dbo::get_tag(tags_ids[i]);
 | 
					 | 
				
			||||||
            tags_json[i] = tags[i];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    relay_json["tags"] = tags_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, int bind_func_param)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder *filters[1];
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        key,
 | 
					 | 
				
			||||||
        value,
 | 
					 | 
				
			||||||
        bind_func,
 | 
					 | 
				
			||||||
        bind_func_param,
 | 
					 | 
				
			||||||
        ";"
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    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_by_id(int id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    relay_dbo **relays = relay_dbo::get_by_simple("id", &id, (intptr_t)&sqlite3_bind_int, 0);
 | 
					 | 
				
			||||||
    relay_dbo *result = relays[0];
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    free(relays);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
relay_dbo*
 | 
					 | 
				
			||||||
relay_dbo::get_relay_for_controller(uuid_t controller_id, int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder *filters[2];
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter(
 | 
					 | 
				
			||||||
            "number",
 | 
					 | 
				
			||||||
            &relay_num,
 | 
					 | 
				
			||||||
            (intptr_t)&sqlite3_bind_int,
 | 
					 | 
				
			||||||
            0,
 | 
					 | 
				
			||||||
            "AND"
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    helpers::sql_filter_builder filter2(
 | 
					 | 
				
			||||||
            "controller_id",
 | 
					 | 
				
			||||||
            (void*)controller_id,
 | 
					 | 
				
			||||||
            (intptr_t)sqlite3_bind_blob,
 | 
					 | 
				
			||||||
            sizeof(uuid_t),
 | 
					 | 
				
			||||||
            ";"
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    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(uuid_t search_controller_id, int relay_num)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    controller_dbo **controllers = controller_dbo::get_by_simple("id", search_controller_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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,58 +0,0 @@
 | 
				
			||||||
#ifndef EMGAUWA_CORE_RELAY_DBO_H
 | 
					 | 
				
			||||||
#define EMGAUWA_CORE_RELAY_DBO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sqlite3.h>
 | 
					 | 
				
			||||||
#include <json/value.h>
 | 
					 | 
				
			||||||
#include <uuid/uuid.h>
 | 
					 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include "schedule_dbo.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class relay_dbo
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int id;
 | 
					 | 
				
			||||||
    char name[128];
 | 
					 | 
				
			||||||
    int number;
 | 
					 | 
				
			||||||
    uuid_t controller_id;
 | 
					 | 
				
			||||||
    int active_schedule_id;
 | 
					 | 
				
			||||||
    schedule_dbo *active_schedule;
 | 
					 | 
				
			||||||
    schedule_dbo *schedules[7];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void
 | 
					 | 
				
			||||||
    reload_active_schedule();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool
 | 
					 | 
				
			||||||
    save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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, int bind_func_param);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo*
 | 
					 | 
				
			||||||
    get_by_id(int id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo**
 | 
					 | 
				
			||||||
    get_by(helpers::sql_filter_builder **filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo*
 | 
					 | 
				
			||||||
    get_relay_for_controller(uuid_t controller_id, int relay_num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static bool
 | 
					 | 
				
			||||||
    valid_num_for_controller(uuid_t search_controller_id, int relay_num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static relay_dbo**
 | 
					 | 
				
			||||||
    get_all();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //EMGAUWA_CORE_RELAY_DBO_H
 | 
					 | 
				
			||||||
							
								
								
									
										461
									
								
								models/schedule.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										461
									
								
								models/schedule.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,461 @@
 | 
				
			||||||
 | 
					#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("error 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
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(!schedule->id)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            schedule->id = sqlite3_last_insert_rowid(global_database);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_remove(schedule_t *schedule)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					    if(!schedule->id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "DELETE FROM schedules WHERE id=?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, schedule->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int rc = sqlite3_step(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc != SQLITE_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					schedule_is_protected(schedule_t *schedule)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uuid_t tmp_uuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					    memcpy(tmp_uuid, "off", 3);
 | 
				
			||||||
 | 
					    if(uuid_compare(schedule->uid, tmp_uuid) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					    memcpy(tmp_uuid, "on", 2);
 | 
				
			||||||
 | 
					    if(uuid_compare(schedule->uid, tmp_uuid) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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_by_id_or_off(int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM schedules WHERE id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t **sql_result = schedule_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    uuid_t tmp_uuid;
 | 
				
			||||||
 | 
					    memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					    memcpy(tmp_uuid, "off", 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return schedule_get_by_uid(tmp_uuid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_id(int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM schedules WHERE id = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t **sql_result = schedule_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_uid_or_off(uuid_t uid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM schedules WHERE uid = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_blob(stmt, 1, uid, sizeof(uuid_t), SQLITE_STATIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t **sql_result = schedule_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    uuid_t tmp_uuid;
 | 
				
			||||||
 | 
					    memset(tmp_uuid, 0, sizeof(uuid_t));
 | 
				
			||||||
 | 
					    memcpy(tmp_uuid, "off", 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return schedule_get_by_uid(tmp_uuid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t*
 | 
				
			||||||
 | 
					schedule_get_by_uid(uuid_t uid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT * FROM schedules WHERE uid = ?1;", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_blob(stmt, 1, uid, sizeof(uuid_t), SQLITE_STATIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t **sql_result = schedule_db_select(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_t *result = sql_result[0];
 | 
				
			||||||
 | 
					    free(sql_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schedule_t**
 | 
				
			||||||
 | 
					schedule_get_relay_weekdays(int relay_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sqlite3_stmt *stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sqlite3_prepare_v2(global_database, "SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule ON schedules.id == junction_relay_schedule.schedule_id WHERE junction_relay_schedule.relay_id = ?1 ORDER BY junction_relay_schedule.weekday ASC", -1, &stmt, NULL);
 | 
				
			||||||
 | 
					    sqlite3_bind_int(stmt, 1, relay_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return schedule_db_select(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue