#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <uuid/uuid.h> #include <sqlite3.h> #include <models/controller.h> #include <logger.h> #include <config.h> #include <constants.h> #include <database.h> controller_t *global_controller; static int db_update_insert(controller_t *controller, sqlite3_stmt *stmt) { LOGGER_DEBUG("saving controller '%s' into database (id: %d)\n", controller->name, controller->id); 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_int(stmt, 4, controller->command_port); 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 'i': // id new_controller->id = sqlite3_column_int(stmt, i); break; case 'c': // command_port new_controller->command_port = sqlite3_column_int(stmt, i); break; case 'n': // name strncpy(new_controller->name, (const char*)sqlite3_column_text(stmt, i), 127); 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 = malloc(sizeof(relay_t) * global_config->relay_count); uint8_t i; for(i = 0; i < global_config->relay_count; ++i) { new_controller->relays[i] = relay_load(i); if(!new_controller->relays[i]) { new_controller->relays[i] = relay_create(i); relay_save(new_controller->relays[i]); } } return new_controller; } static controller_t** controller_db_select(sqlite3_stmt *stmt) { controller_t **all_controllers = malloc(sizeof(controller_t*)); int row = 0; for(;;) { 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 { LOGGER_ERR("error selecting controllers from database: %s\n", sqlite3_errstr(s)); break; } } } sqlite3_finalize(stmt); all_controllers[row] = NULL; return all_controllers; } int controller_save() { int opened_transaction = database_transaction_begin(); sqlite3_stmt *stmt; if(global_controller->id) { sqlite3_prepare_v2(global_database, "UPDATE controllers set uid = ?2, name = ?3, command_port = ?4 WHERE id = ?1;", -1, &stmt, NULL); } else { sqlite3_prepare_v2(global_database, "INSERT INTO controllers(uid, name, command_port) values (?2, ?3, ?4);", -1, &stmt, NULL); } int result = db_update_insert(global_controller, stmt); if(result) { if(global_controller->id) { LOGGER_ERR("error inserting data: %s\n", sqlite3_errmsg(global_database)); } else { LOGGER_ERR("error updating data: %s\n", sqlite3_errmsg(global_database)); } if(opened_transaction) { database_transaction_rollback(); } } else { if(!global_controller->id) { global_controller->id = sqlite3_last_insert_rowid(global_database); } if(opened_transaction) { database_transaction_commit(); } } return result; } controller_t* controller_load() { LOGGER_DEBUG("getting controller from database\n"); sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT * FROM controllers LIMIT 1;", -1, &stmt, NULL); controller_t **sql_result = controller_db_select(stmt); controller_t *result = sql_result[0]; free(sql_result); 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; } controller_t* controller_create(void) { controller_t *new_controller = malloc(sizeof(*new_controller)); new_controller->id = 0; uuid_generate(new_controller->uid); strncpy(new_controller->name, global_config->name, MAX_NAME_LENGTH); new_controller->name[MAX_NAME_LENGTH] = '\0'; new_controller->command_port = 0; new_controller->relays = malloc(sizeof(relay_t) * global_config->relay_count); uint8_t i; for(i = 0; i < global_config->relay_count; ++i) { new_controller->relays[i] = relay_load(i); if(!new_controller->relays[i]) { new_controller->relays[i] = relay_create(i); relay_save(new_controller->relays[i]); } } return new_controller; } void controller_set_name(controller_t *controller, const char *name) { strncpy(controller->name, name, MAX_NAME_LENGTH); controller->name[MAX_NAME_LENGTH] = '\0'; } void controller_free(controller_t *controller) { for(int i = 0; i < global_config->relay_count; ++i) { relay_free(controller->relays[i]); } free(controller->relays); free(controller); } void controller_debug(controller_t *controller) { if(controller == NULL) { LOGGER_DEBUG("controller is NULL\n"); return; } char uuid_str[37]; uuid_unparse(controller->uid, uuid_str); LOGGER_DEBUG("(1/3) %s @ %p\n", uuid_str, (void*)controller); LOGGER_DEBUG("(2/3) name: %s\n", controller->name); LOGGER_DEBUG("(3/3) relays @ %p:\n", (void*)controller->relays); for(int i = 0; i < global_config->relay_count; ++i) { relay_debug(controller->relays[i]); } }