#include #include #include #include #include #include #include #include #include #include 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 { 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(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) { LOGGER_ERR("error inserting data: %s\n", sqlite3_errmsg(global_database)); } else { LOGGER_ERR("error updating data: %s\n", sqlite3_errmsg(global_database)); } } else { if(!controller->id) { controller->id = sqlite3_last_insert_rowid(global_database); } } cache_invalidate_controller(controller->id); 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); } char* controller_to_json(controller_t *controller) { char *cached = cache_get_json_controller(controller->id); if(cached) { return cached; } char uuid_str[UUID_STR_LEN]; uuid_unparse(controller->uid, uuid_str); LOGGER_DEBUG("JSONifying controller %s\n", uuid_str); 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); 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 *json_relay = cJSON_CreateRaw(relay_to_json(relays[i])); cJSON_AddItemToArray(json_relays, json_relay); } cJSON_AddItemToObject(json, "relays", json_relays); relay_free_list(relays); char *result = cJSON_Print(json); cJSON_Delete(json); cache_put_json_controller(controller->id, result); return result; } controller_t* controller_get_by_id(int id) { LOGGER_DEBUG("getting controller [id=%d] from database\n", 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) { char uuid_str[UUID_STR_LEN]; uuid_unparse(uid, uuid_str); LOGGER_DEBUG("getting controller [uid=%s] from database\n", uuid_str); 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() { LOGGER_DEBUG("getting all controllers from database\n"); sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT * FROM controllers;", -1, &stmt, NULL); return controller_db_select(stmt); }