From 6a63218f85d80919c8bab87141f9f4c9c3acdfdf Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Thu, 5 Dec 2024 13:33:58 +0100 Subject: rest: add POST oglive/default Remove 'is_default' column from 'lives' database table and add column 'priority' of type INT. This new value can store a priority value but the actual design only stores 1 or 0. Update GET oglive/list to use the new 'priority' database value. Add POST oglive/default. Set the database column 'priority' to 1 if the new default exists in the database. Set the others to priority 0. Modify legacy ogliveinfo.json if the new default coresponds to a live not found in the database. Edit the field 'default' of the file's json. --- src/rest.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 248 insertions(+), 16 deletions(-) (limited to 'src/rest.c') diff --git a/src/rest.c b/src/rest.c index a5b0db2..d2ca050 100644 --- a/src/rest.c +++ b/src/rest.c @@ -4769,11 +4769,13 @@ static int og_cmd_oglive_list(struct og_rest_ctx *ctx) .data = ctx->buf_reply }; - const char *msglog, *live_name, *live_datetime; - json_t *root, *live_entry, *oglive_array; + json_t *root, *live_entry, *oglive_array, *default_entry; + const char *msglog, *live_name; + uint64_t live_timestamp; json_error_t json_err; struct og_dbi *dbi; dbi_result result; + int priority; root = json_load_file(OG_LIVE_JSON_FILE_PATH, 0, &json_err); if (!root) { @@ -4784,7 +4786,12 @@ static int og_cmd_oglive_list(struct og_rest_ctx *ctx) oglive_array = json_object_get(root, "oglive"); if (!oglive_array || !json_is_array(oglive_array)) { - syslog(LOG_ERR, "Expected 'oglive' to be a JSON array\n"); + json_decref(root); + return -1; + } + + default_entry = json_object_get(root, "default"); + if (!default_entry || json_typeof(default_entry) != JSON_INTEGER) { json_decref(root); return -1; } @@ -4799,8 +4806,8 @@ static int og_cmd_oglive_list(struct og_rest_ctx *ctx) } result = dbi_conn_queryf(dbi->conn, - "SELECT name, " - "DATE_FORMAT(creation_date, '%%a %%b %%d %%H:%%i:%%s %%Y') AS formatted_date " + "SELECT name, priority, " + "UNIX_TIMESTAMP(creation_date) AS creation_timestamp " "FROM oglive"); if (!result) { @@ -4815,7 +4822,19 @@ static int og_cmd_oglive_list(struct og_rest_ctx *ctx) while (dbi_result_next_row(result) > 0) { live_name = dbi_result_get_string(result, "name"); - live_datetime = dbi_result_get_string(result, "formatted_date"); + live_timestamp = dbi_result_get_longlong(result, "creation_timestamp"); + priority = dbi_result_get_int(result, "priority"); + + if (priority > 0) { + if (json_integer_set(default_entry, json_array_size(oglive_array)) < 0) { + syslog(LOG_ERR, "Failed to modify 'default' entry value\n"); + dbi_result_free(result); + og_dbi_close(dbi); + json_decref(root); + ctx->http_error = OG_HTTP_500_INTERNAL_SERVER_ERROR; + return -1; + } + } live_entry = json_object(); if (!live_entry) { @@ -4829,7 +4848,7 @@ static int og_cmd_oglive_list(struct og_rest_ctx *ctx) } json_object_set_new(live_entry, "directory", json_string(live_name)); - json_object_set_new(live_entry, "date", json_string(live_datetime)); + json_object_set_new(live_entry, "date", json_integer(live_timestamp)); json_array_append_new(oglive_array, live_entry); } @@ -5855,7 +5874,6 @@ static int og_cmd_oglive_add(struct og_rest_ctx *ctx) { const char *oglive_str; bool is_update = false; - int is_default_value; const char *msglog; struct og_dbi *dbi; uint64_t flags = 0; @@ -5906,20 +5924,16 @@ static int og_cmd_oglive_add(struct og_rest_ctx *ctx) dbi_result_free(result); - is_default_value = 0; - if (is_update) result = dbi_conn_queryf(dbi->conn, - "UPDATE oglive SET creation_date = NOW(), is_default = %d " + "UPDATE oglive SET creation_date = NOW() " "WHERE name = '%s'", - is_default_value, oglive_str); else result = dbi_conn_queryf(dbi->conn, - "INSERT INTO oglive (name, creation_date, is_default) " - "VALUES ('%s', NOW(), %d)", - oglive_str, - is_default_value); + "INSERT INTO oglive (name, creation_date) " + "VALUES ('%s', NOW())", + oglive_str); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", @@ -6012,6 +6026,210 @@ static int og_cmd_oglive_delete(struct og_rest_ctx *ctx) return 0; } +static int update_ogliveinfo_default(const char *oglive_str) +{ + char buf_data[OG_MSG_RESPONSE_MAXLEN]; + struct og_buffer og_buffer = { + .data = buf_data + }; + + json_t *root, *oglive_array, *default_entry, *live_entry, *dir_entry; + char tmp_filename[] = "/tmp/ogliveinfo_XXXXXX"; + int default_idx, i, fd, ret; + const char *live_name; + json_error_t json_err; + + root = json_load_file(OG_LIVE_JSON_FILE_PATH, 0, &json_err); + if (!root) { + syslog(LOG_ERR, "malformed json line %d: %s\n", + json_err.line, json_err.text); + return -1; + } + + oglive_array = json_object_get(root, "oglive"); + if (!oglive_array || !json_is_array(oglive_array)) { + json_decref(root); + return -1; + } + + default_entry = json_object_get(root, "default"); + if (!default_entry || json_typeof(default_entry) != JSON_INTEGER) { + json_decref(root); + return -1; + } + + default_idx = -1; + + for (i = 0; i < json_array_size(oglive_array); i++) { + live_entry = json_array_get(oglive_array, i); + if (json_typeof(live_entry) != JSON_OBJECT) { + json_decref(root); + return -1; + } + + dir_entry = json_object_get(live_entry, "directory"); + if (!dir_entry || json_typeof(dir_entry) != JSON_STRING) { + json_decref(root); + return -1; + } + live_name = json_string_value(dir_entry); + + if (!strncmp(oglive_str, live_name, strlen(live_name))) { + default_idx = i; + break; + } + } + + if (default_idx < 0) { + json_decref(root); + return -1; + } + + if (json_integer_set(default_entry, default_idx) < 0) { + syslog(LOG_ERR, "Failed to modify 'default' entry value\n"); + json_decref(root); + return -1; + } + + if (json_dump_callback(root, og_json_dump_clients, &og_buffer, + JSON_INDENT(2) | JSON_PRESERVE_ORDER)) { + json_decref(root); + return -1; + } + json_decref(root); + + fd = mkstemp(tmp_filename); + if (fd < 0) { + syslog(LOG_ERR, "cannot generate temp file %s: %s (%s:%d)\n", + tmp_filename, strerror(errno), __func__, __LINE__); + return -1; + } + + ret = write(fd, og_buffer.data, og_buffer.len); + if (ret < 0) { + syslog(LOG_ERR, "cannot write to temporary file %s: %s (%s:%d)\n", + tmp_filename, strerror(errno), __func__, __LINE__); + return -1; + } + + ret = write(fd, "\n", 1); + if (ret < 0) { + syslog(LOG_ERR, "cannot write to temporary file %s: %s (%s:%d)\n", + tmp_filename, strerror(errno), __func__, __LINE__); + return -1; + } + close(fd); + + if (ret < 0) { + syslog(LOG_ERR, "cannot write file %s: %s (%s:%d)\n", + tmp_filename, strerror(errno), __func__, __LINE__); + unlink(tmp_filename); + return -1; + } + + if (rename(tmp_filename, OG_LIVE_JSON_FILE_PATH) < 0) { + syslog(LOG_ERR, "cannot rename file %s to %s: %s (%s:%d)\n", + tmp_filename, OG_LIVE_JSON_FILE_PATH, strerror(errno), __func__, __LINE__); + unlink(tmp_filename); + return -1; + } + + return 0; +} + +static int og_cmd_oglive_set_default(struct og_rest_ctx *ctx) +{ + const char *oglive_str; + uint64_t flags = 0; + const char *msglog; + struct og_dbi *dbi; + dbi_result result; + bool db_has_live; + const char *key; + json_t *value; + int priority; + int err = 0; + + json_object_foreach(ctx->json, key, value) { + if (!strcmp(key, "name")) { + err = og_json_parse_string(value, &oglive_str); + flags |= OG_REST_PARAM_NAME; + } else { + err = -1; + } + + if (err < 0) + return err; + } + + if (!og_flags_validate(flags, OG_REST_PARAM_NAME)) + return -1; + + dbi = og_dbi_open(&ogconfig.db); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + ctx->http_error = OG_HTTP_501_SERVICE_UNAVAILABLE; + return -1; + } + + result = dbi_conn_queryf(dbi->conn, + "SELECT name FROM oglive WHERE name = '%s'", + oglive_str); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "Failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); + ctx->http_error = OG_HTTP_500_INTERNAL_SERVER_ERROR; + og_dbi_close(dbi); + return -1; + } + + db_has_live = dbi_result_next_row(result) > 0; + dbi_result_free(result); + + priority = 1; + if (db_has_live) { + result = dbi_conn_queryf(dbi->conn, + "UPDATE oglive SET priority = %d " + "WHERE name = '%s'", + priority, oglive_str); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + ctx->http_error = OG_HTTP_500_INTERNAL_SERVER_ERROR; + og_dbi_close(dbi); + return -1; + } + + dbi_result_free(result); + } else if (update_ogliveinfo_default(oglive_str) < 0) { + syslog(LOG_ERR, "No live entries found with name %s", oglive_str); + ctx->http_error = OG_HTTP_404_NOT_FOUND; + og_dbi_close(dbi); + return -1; + } + + result = dbi_conn_queryf(dbi->conn, + "UPDATE oglive SET priority = 0 " + "WHERE priority != 0 AND name != '%s'", + oglive_str); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + ctx->http_error = OG_HTTP_500_INTERNAL_SERVER_ERROR; + og_dbi_close(dbi); + return -1; + } + + dbi_result_free(result); + og_dbi_close(dbi); + + return 0; +} + static int og_cmd_get_server_stats(struct og_rest_ctx *ctx) { json_t *root, *time_obj, *memory, *swap; @@ -6242,6 +6460,7 @@ struct { [OG_URI_OGLIVE_ADD] = { "oglive/add", }, [OG_URI_OGLIVE_DELETE] = { "oglive/delete", }, [OG_URI_OGLIVE_SET] = { "oglive/set", }, + [OG_URI_OGLIVE_DEFAULT] = { "oglive/default", }, [OG_URI_CENTER_ADD] = { "center/add", }, [OG_URI_CENTER_UPDATE] = { "center/update", }, [OG_URI_CENTER_DELETE] = { "center/delete", }, @@ -6953,6 +7172,19 @@ int og_client_state_process_payload_rest(struct og_client *cli) goto err_process_rest_payload; } err = og_cmd_oglive_set(&ctx); + } else if (!strncmp(cmd, "oglive/default", strlen("oglive/default"))) { + if (method != OG_METHOD_POST) { + ctx.http_error = OG_HTTP_405_METHOD_NOT_ALLOWED; + goto err_process_rest_payload; + } + + if (!root) { + syslog(LOG_ERR, + "command oglive default with no payload\n"); + ctx.http_error = OG_HTTP_400_BAD_REQUEST; + goto err_process_rest_payload; + } + err = og_cmd_oglive_set_default(&ctx); } else if (!strncmp(cmd, "center/add", strlen("center/add"))) { if (method != OG_METHOD_POST) { -- cgit v1.2.3-18-g5258