diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cfa064..edf4d3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,8 @@ endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -g -latomic") +set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -Wall -Wextra -Werror -g -latomic") +set(CMAKE_CXX_FLAGS_DEBUG "-g") ########## # If you include the drogon source code locally in your project, use this method to add drogon @@ -76,6 +77,16 @@ add_custom_target(run DEPENDS core WORKING_DIRECTORY ${CMAKE_PROJECT_DIR} ) +add_custom_target(debug + COMMAND valgrind ./core + DEPENDS core + WORKING_DIRECTORY ${CMAKE_PROJECT_DIR} +) +add_custom_target(debug-full + COMMAND valgrind --leak-check=full --show-leak-kinds=all ./core + DEPENDS core + WORKING_DIRECTORY ${CMAKE_PROJECT_DIR} +) add_custom_target(test COMMAND ./run_tests.sh ${CMAKE_BINARY_DIR}/core ${CMAKE_SOURCE_DIR}/config.testing.json diff --git a/controllers/api_v1_controllers_relays.cc b/controllers/api_v1_controllers_relays.cc index 9bc4b16..e12968a 100644 --- a/controllers/api_v1_controllers_relays.cc +++ b/controllers/api_v1_controllers_relays.cc @@ -93,7 +93,7 @@ controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, Json::Value body = *req->getJsonObject(); uuid_t active_schedule_id; - if(schedule_dbo::parse_uid(body["active_schedule"].asCString(), 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(); @@ -102,18 +102,48 @@ controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, return; } + 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; + } + } + relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id, relay_num); - schedule_dbo **schedule = schedule_dbo::get_by_simple("uid", active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); + + schedule_dbo **schedule_list = schedule_dbo::get_by_simple("uid", active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); + schedule_dbo *active_schedule = schedule_list[0]; + + free(schedule_list); + + schedule_dbo *schedules[7]; + 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); + } bool db_action_result; if(relay) { strncpy(relay->name, body["name"].asCString(), 127); - relay->active_schedule_id = schedule[0]->id; uuid_copy(relay->controller_id, controller_id); - relay->reload_active_schedule(); + for(int i = 0; i < 7; ++i) + { + relay->schedules[i] = schedules[i]; + } + + relay->schedules[helpers::get_day_of_week()] = active_schedule; + relay->active_schedule = active_schedule; db_action_result = relay->update(); } @@ -123,10 +153,15 @@ controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, relay->number = relay_num; strncpy(relay->name, body["name"].asCString(), 127); - relay->active_schedule_id = schedule[0]->id; - uuid_copy(relay->controller_id, controller_id); + for(int i = 0; i < 7; ++i) + { + relay->schedules[i] = schedules[i]; + } - relay->reload_active_schedule(); + relay->schedules[helpers::get_day_of_week()] = active_schedule; + relay->active_schedule = active_schedule; + + uuid_copy(relay->controller_id, controller_id); db_action_result = relay->insert(); } diff --git a/filters/relays_valid_json.cc b/filters/relays_valid_json.cc index 57d7ecf..ad3806d 100644 --- a/filters/relays_valid_json.cc +++ b/filters/relays_valid_json.cc @@ -18,33 +18,87 @@ void valid_json::doFilter(const HttpRequestPtr &req, bool is_valid = true; + // level 1 is_valid &= body["name"].type() == Json::ValueType::stringValue; - is_valid &= body["active_schedule"].type() == Json::ValueType::stringValue; + is_valid &= body["active_schedule"].type() == Json::ValueType::objectValue; + is_valid &= body["schedules"].type() == Json::ValueType::arrayValue; - uuid_t active_schedule_id; - if(schedule_dbo::parse_uid(body["active_schedule"].asCString(), active_schedule_id)) + // level 2 + if(is_valid) { - LOG_DEBUG << "parse_uid failed"; + is_valid &= body["active_schedule"]["id"].type() == Json::ValueType::stringValue; + for(int i = 0; i < 7; ++i) + { + is_valid &= body["schedules"][i].type() == Json::ValueType::objectValue; + } + } + + // level 3 + if(is_valid) + { + 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(is_valid) + uuid_t active_schedule_id; + if(schedule_dbo::parse_uid(body["active_schedule"]["id"].asCString(), active_schedule_id)) { - schedule_dbo **schedules = schedule_dbo::get_by_simple("uid", active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); + 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; + } + + 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; + } + + 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) + if(!schedule_found) { - //Passed - fccb(); + LOG_DEBUG << "could not find schedule " << i; + auto res = drogon::HttpResponse::newHttpResponse(); + res->setStatusCode(k400BadRequest); + fcb(res); return; } } - //Check failed - LOG_DEBUG << "schedule not found"; - auto res = drogon::HttpResponse::newHttpResponse(); - res->setStatusCode(k400BadRequest); - fcb(res); + + //Passed + fccb(); + return; } diff --git a/helpers.h b/helpers.h index c250d2b..4538d66 100644 --- a/helpers.h +++ b/helpers.h @@ -39,6 +39,9 @@ namespace helpers int migrate_sql(); + + int + get_day_of_week(); } #endif //EMGAUWA_CORE_HELPERS_H diff --git a/helpers/get_day_of_week.cc b/helpers/get_day_of_week.cc new file mode 100644 index 0000000..ba0df39 --- /dev/null +++ b/helpers/get_day_of_week.cc @@ -0,0 +1,12 @@ +#include +#include + +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; +} diff --git a/main.cc b/main.cc index 011441b..8940453 100644 --- a/main.cc +++ b/main.cc @@ -34,7 +34,6 @@ main(int argc, char** argv) signal(SIGINT, terminate); signal(SIGABRT, terminate); signal(SIGTERM, terminate); - signal(SIGKILL, terminate); const char* config_file_name = "config.json"; diff --git a/models/relay_dbo.cc b/models/relay_dbo.cc index c6d0e1c..bb92382 100644 --- a/models/relay_dbo.cc +++ b/models/relay_dbo.cc @@ -11,10 +11,16 @@ static bool relay_db_update_insert(relay_dbo *relay, sqlite3_stmt *stmt) { int rc; + uint32_t schedules_ids[7]; + for(int i = 0; i < 7; ++i) + { + schedules_ids[i] = 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_int(stmt, 4, relay->active_schedule_id); + sqlite3_bind_blob(stmt, 4, schedules_ids, sizeof(uint32_t) * 7, SQLITE_STATIC); sqlite3_bind_blob(stmt, 5, relay->controller_id, sizeof(uuid_t), SQLITE_STATIC); sqlite3_bind_text(stmt, 6, relay->tag, -1, SQLITE_STATIC); @@ -34,15 +40,13 @@ static relay_dbo* relay_db_select_mapper(sqlite3_stmt *stmt) { auto *new_relay = new relay_dbo(); - const char* new_tag; + const char *new_tag; + const uint32_t *new_relays_ids; for(int i = 0; i < sqlite3_column_count(stmt); i++) { const char *name = sqlite3_column_name(stmt, i); switch(name[0]) { - case 'a': // active_schedule_dbid - new_relay->active_schedule_id = sqlite3_column_int(stmt, i); - break; case 'c': // controller_id uuid_copy(new_relay->controller_id, (const unsigned char*)sqlite3_column_blob(stmt, i)); break; @@ -62,6 +66,13 @@ relay_db_select_mapper(sqlite3_stmt *stmt) break; } break; + case 's': // schedules_ids + new_relays_ids = (const uint32_t*)sqlite3_column_blob(stmt, i); + for(int i = 0; i < 7; ++i) + { + new_relay->schedules[i] = schedule_dbo::get_by_id_or_off(new_relays_ids[i]); + } + break; case 't': // tag new_tag = (const char*)sqlite3_column_text(stmt, i); new_relay->tag[0] = '\0'; @@ -93,8 +104,6 @@ relay_db_select(sqlite3_stmt *stmt) { relay_dbo *new_relay = relay_db_select_mapper(stmt); - new_relay->reload_active_schedule(); - row++; all_relays = (relay_dbo**)realloc(all_relays, sizeof(relay_dbo*) * (row + 1)); @@ -120,35 +129,12 @@ relay_db_select(sqlite3_stmt *stmt) return all_relays; } -void -relay_dbo::reload_active_schedule() -{ - schedule_dbo **schedules = schedule_dbo::get_by_simple("id", &this->active_schedule_id, (intptr_t)&sqlite3_bind_int, 0); - - if(!schedules[0]) - { - free(schedules); - uuid_t off_uuid; - memset(off_uuid, 0, sizeof(uuid_t)); - memcpy(off_uuid, "off", 3); - schedules = schedule_dbo::get_by_simple("uid", off_uuid, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); - if(schedules[0]) - { - this->active_schedule_id = schedules[0]->id; - } - } - - this->active_schedule = schedules[0]; - - free(schedules); -} - bool relay_dbo::update() { sqlite3_stmt *stmt; - sqlite3_prepare_v2(globals::db, "UPDATE relays set number = ?2, name = ?3, active_schedule_id = ?4, controller_id = ?5, tag = ?6 WHERE id = ?1;", -1, &stmt, nullptr); + sqlite3_prepare_v2(globals::db, "UPDATE relays set number = ?2, name = ?3, schedules_ids = ?4, controller_id = ?5, tag = ?6 WHERE id = ?1;", -1, &stmt, nullptr); return relay_db_update_insert(this, stmt); } @@ -158,7 +144,7 @@ relay_dbo::insert() { sqlite3_stmt *stmt; - sqlite3_prepare_v2(globals::db, "INSERT INTO relays(number, name, active_schedule_id, controller_id, tag) values (?2, ?3, ?4, ?5, ?6);", -1, &stmt, nullptr); + sqlite3_prepare_v2(globals::db, "INSERT INTO relays(number, name, schedules_ids, controller_id, tag) values (?2, ?3, ?4, ?5, ?6);", -1, &stmt, nullptr); return relay_db_update_insert(this, stmt); } @@ -181,16 +167,26 @@ relay_dbo::remove() 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; relay_json["tag"] = this->tag; return relay_json; diff --git a/models/relay_dbo.h b/models/relay_dbo.h index 6250d70..0e7a923 100644 --- a/models/relay_dbo.h +++ b/models/relay_dbo.h @@ -19,6 +19,7 @@ public: int active_schedule_id; char tag[64]; schedule_dbo *active_schedule; + schedule_dbo *schedules[7]; void reload_active_schedule(); @@ -41,6 +42,9 @@ public: 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_or_off(const int id); + static relay_dbo** get_by(helpers::sql_filter_builder **filters); diff --git a/models/schedule_dbo.cc b/models/schedule_dbo.cc index ad4c367..8caff70 100644 --- a/models/schedule_dbo.cc +++ b/models/schedule_dbo.cc @@ -183,6 +183,29 @@ schedule_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_fu return schedule_db_select(stmt); } +schedule_dbo* +schedule_dbo::get_by_id_or_off(const int id) +{ + schedule_dbo **schedules = schedule_dbo::get_by_simple("id", &id, (intptr_t)&sqlite3_bind_int, 0); + + if(!schedules[0]) + { + free(schedules); + uuid_t off_uuid; + memset(off_uuid, 0, sizeof(uuid_t)); + memcpy(off_uuid, "off", 3); + schedules = schedule_dbo::get_by_simple("uid", off_uuid, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); + if(!schedules[0]) + { + LOG_FATAL << "schedule with uid 'off' not found"; + exit(1); + } + } + schedule_dbo *schedule = schedules[0]; + free(schedules); + return schedule; +} + schedule_dbo** schedule_dbo::get_by(helpers::sql_filter_builder **filters) { diff --git a/models/schedule_dbo.h b/models/schedule_dbo.h index 93579eb..99c9c30 100644 --- a/models/schedule_dbo.h +++ b/models/schedule_dbo.h @@ -38,6 +38,9 @@ public: static schedule_dbo** get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param); + static schedule_dbo* + get_by_id_or_off(const int id); + static schedule_dbo** get_by(helpers::sql_filter_builder **filters); diff --git a/sql/migration_0.sql b/sql/migration_0.sql index cb66692..e5b83d3 100644 --- a/sql/migration_0.sql +++ b/sql/migration_0.sql @@ -1,51 +1,52 @@ create table meta ( - version_num int not null + version_num INTEGER + NOT NULL ); create table controllers ( - id VARCHAR(33) not null - primary key - unique, + id VARCHAR(64) + NOT NULL + PRIMARY KEY + UNIQUE, name VARCHAR(128), ip VARCHAR(16), port INTEGER, relay_count INTEGER, tag varchar(64), - active BOOLEAN not null + active BOOLEAN + NOT NULL ); create table relays ( - id INTEGER - not null - primary key - unique, - name VARCHAR(128), - number INTEGER - not null, - controller_id VARCHAR(33) - not null - references controllers (id), - active_schedule_id int - references schedules (id), - tag vARCHAR(64) + id INTEGER + PRIMARY KEY + AUTOINCREMENT, + name VARCHAR(128), + number INTEGER + NOT NULL, + controller_id VARCHAR(33) + NOT NULL + REFERENCES CONTROLLERS (ID), + schedules_ids INTEGER + REFERENCES SCHEDULES (ID), + tag vARCHAR(64) ); create table schedules ( id INTEGER - not null - primary key - unique, + PRIMARY KEY + AUTOINCREMENT, uid VARCHAR(33) - not null - unique, + NOT NULL + UNIQUE, name VARCHAR(128), periods BLOB, tag vARCHAR(64) ); INSERT INTO schedules (uid, name, periods) VALUES (x'6f666600000000000000000000000000', 'off', x'00'); -INSERT INTO schedules (uid, name, periods) VALUES (x'6f6e0000000000000000000000000000', 'on', x'010000009F05'); +INSERT INTO schedules (uid, name, periods) VALUES (x'6f6e0000000000000000000000000000', 'on', x'010000009F05');