335 lines
8.7 KiB
C
335 lines
8.7 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sqlite3.h>
|
|
|
|
#include <cache.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)
|
|
{
|
|
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_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)
|
|
{
|
|
int opened_transaction = database_transaction_begin();
|
|
|
|
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));
|
|
}
|
|
|
|
if(opened_transaction)
|
|
{
|
|
database_transaction_rollback();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!controller->id)
|
|
{
|
|
controller->id = sqlite3_last_insert_rowid(global_database);
|
|
}
|
|
|
|
if(opened_transaction)
|
|
{
|
|
database_transaction_commit();
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
cJSON*
|
|
controller_to_json(controller_t *controller)
|
|
{
|
|
cJSON *json;
|
|
|
|
char *cached = cache_get_json_controller(controller->id);
|
|
if(cached)
|
|
{
|
|
json = cJSON_CreateRaw(cached);
|
|
free(cached);
|
|
return json;
|
|
}
|
|
|
|
char uuid_str[UUID_STR_LEN];
|
|
uuid_unparse(controller->uid, uuid_str);
|
|
|
|
LOGGER_DEBUG("JSONifying controller %s\n", uuid_str);
|
|
|
|
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 = relay_to_json(relays[i]);
|
|
cJSON_AddItemToArray(json_relays, json_relay);
|
|
}
|
|
cJSON_AddItemToObject(json, "relays", json_relays);
|
|
relay_free_list(relays);
|
|
|
|
char *json_str = cJSON_Print(json);
|
|
cache_put_json_controller(controller->id, json_str);
|
|
cJSON_Delete(json);
|
|
|
|
json = cJSON_CreateRaw(json_str);
|
|
free(json_str);
|
|
return json;
|
|
}
|
|
|
|
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);
|
|
}
|