From 726a725fa7d7d04b706b0bf9a8283b5ff620fef9 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Sun, 31 Jan 2021 11:21:30 +0100 Subject: [PATCH] MPD: A working delete command --- README.md | 4 +-- src/base/commands.c | 2 +- src/database/macro.h | 12 +++---- src/database/queue.c | 82 +++++++++++++++++++++++++++----------------- src/net/listen.c | 5 +-- 5 files changed, 63 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 43209ff4..63124e64 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,8 @@ stickers with lektor, this is WIP. If you are using special modules or are compiling lektor without static modules, you may set their **absolute path** inside the lektor's config file. -To generate AppImages, add `enable-appimage` to the `configure` line. Note that the only supported -distribution methode is AppImage. +To generate AppImages, add `--enable-appimage` to the `configure` line. Note +that the only supported distribution methode is AppImage. > **Important note**: if you are building using WSL, `lektord` will likely not launch, because `XDG_RUNTIME_DIR` is not defined here. This folder is important, this is where most of your diff --git a/src/base/commands.c b/src/base/commands.c index 745485c7..2f2c18dd 100644 --- a/src/base/commands.c +++ b/src/base/commands.c @@ -479,7 +479,7 @@ command_delid(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]) char *endptr = NULL, err = 0; int uri = 0; - RETURN_UNLESS(args[0], "No id provided", false); + RETURN_UNLESS(args && args[0], "No id provided", false); STRTOL(id, args[0], endptr, err); RETURN_IF(err, "STRTOL failed", false); diff --git a/src/database/macro.h b/src/database/macro.h index b6821964..7a751150 100644 --- a/src/database/macro.h +++ b/src/database/macro.h @@ -1,19 +1,19 @@ #if ! defined(__LKT_DATABASE_MACRO_H__) #define __LKT_DATABASE_MACRO_H__ -#define SQLITE_PREPARE(db, stmt, SQL, goto_label) \ +#define SQLITE_PREPARE(db, stmt, SQL, goto_label) { \ if (sqlite3_prepare_v2((sqlite3 *) db, SQL, -1, &(stmt), 0) != SQLITE_OK) { \ LOG_DEBUG("DB", "Failed to prepare statement: %s", \ sqlite3_errmsg((sqlite3 *) db)); \ goto goto_label; \ - } + }} -#define SQLITE_EXEC(db, SQL, goto_label) \ +#define SQLITE_EXEC(db, SQL, goto_label) { \ if (sqlite3_exec((sqlite3 *) db, SQL, NULL, NULL, NULL) != SQLITE_OK) { \ LOG_DEBUG("DB", "Failed to exec statement: %s", \ sqlite3_errmsg((sqlite3 *) db)); \ goto goto_label; \ - } + }} #define SQLITE_BIND_TEXT(db, stmt, pos, text, error) { \ if (sqlite3_bind_text(stmt, pos, text, -1, 0) != SQLITE_OK) { \ @@ -30,12 +30,12 @@ goto error; \ }} -#define SQLITE_STEP(db, stmt, code, error) \ +#define SQLITE_STEP(db, stmt, code, error) { \ if (sqlite3_step(stmt) != code) { \ LOG_DEBUG("DB", "Failed to step: %s", \ sqlite3_errmsg((sqlite3 *) db)); \ goto error; \ - } + }} #define SQLITE_STEP_ROW(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_ROW, error) #define SQLITE_STEP_DONE(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_DONE, error) diff --git a/src/database/queue.c b/src/database/queue.c index c6882ac0..1aee4b78 100644 --- a/src/database/queue.c +++ b/src/database/queue.c @@ -323,45 +323,65 @@ database_queue_del_pos(volatile sqlite3 *db, int pos) { bool sta = false; sqlite3_stmt *stmt = NULL; - struct lkt_queue_state queue; + struct lkt_queue_state queue = { .current = -1 }; RETURN_UNLESS(database_queue_state(db, &queue), "Failed to get the queue state", false); - /* Dec by one position... */ - if (queue.current > pos) { - static const char *SQL = - "BEGIN TRANSACTION;" - "UPDATE queue_state SET current = 1 - current;" - "DELETE FROM queue WHERE position = ?;" - "END TRANSACTION;"; - SQLITE_PREPARE(db, stmt, SQL, failed_in_delete_before); - SQLITE_BIND_INT(db, stmt, 1, pos, failed_in_delete_before); - SQLITE_STEP_DONE(db, stmt, failed_in_delete_before); - sta = true; - failed_in_delete_before: - sqlite3_finalize(stmt); - if (!sta) - SQLITE_DO_ROLLBACK(db); - return sta; + /* Delete the current kara, can't do that because we need to skip it, and + * send signals to the window module to do so, so we just fail here... */ + if (queue.current == pos) { + LOG_ERROR("DB", "Can't delete the currently playing kara at position %d in queue", pos); + return false; } - /* EASY! */ - else if (queue.current < pos) { - static const char *SQL = "DELETE FROM queue WHERE position = ?;"; - SQLITE_PREPARE(db, stmt, SQL, failed_in_delete_after); - SQLITE_BIND_INT(db, stmt, 1, pos, failed_in_delete_after); - SQLITE_STEP_DONE(db, stmt, failed_in_delete_after); - sta = true; - failed_in_delete_after: - sqlite3_finalize(stmt); - return sta; + static const char *SQL_TEMPLATE = + /* Create temporary queue */ + "DELETE FROM queue_tmp;" + "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';" + /* -1 to all positions after the deleted kara */ + "DELETE FROM queue WHERE position = %d;" + "INSERT INTO queue_tmp (kara_id, priority)" + " SELECT kara_id, priority" + " FROM queue;" + /* Re-init positions in the queue */ + "DELETE FROM queue;" + "DELETE FROM sqlite_sequence WHERE name = 'queue';" + /* Insert back all karas */ + "INSERT INTO queue (kara_id, priority, position)" + " SELECT kara_id, priority, position" + " FROM queue_tmp;" + /* Slap correct values here */ + "UPDATE sqlite_sequence" + " SET seq = (SELECT COUNT(position) FROM queue)" + " WHERE name = 'queue';" + "DELETE FROM queue_tmp;" + "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';"; + char SQL[LKT_MAX_SQLITE_STATEMENT]; + safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, SQL_TEMPLATE, pos); + + SQLITE_EXEC(db, "BEGIN TRANSACTION;", error_no_rollback); + SQLITE_EXEC(db, SQL, error_rollback); + if (pos < queue.current) { + LOG_DEBUG("DB", "Needs to decrement current index: pos %d < current %d", pos, queue.current); + SQLITE_EXEC(db, "UPDATE queue_state SET current = current - 1;", error_in_delete_or_update); + } + + sta = true; +error_in_delete_or_update: + if (sta) { + /* Commit transaction, if failed use a magnificient goto... */ + SQLITE_EXEC(db, "END TRANSACTION;", error_rollback); } - /* Delete the current kara, can't do that because we need to skip it, and - * send signals to the window module to do so, so we just fail here... */ else { - LOG_ERROR("DB", "Can't delete the currently playing kara at position %d in queue", pos); - return false; + error_rollback: + sta = false; + LOG_DEBUG("DB", "An error occured, needs to rollback transaction"); + SQLITE_DO_ROLLBACK(db); } +error_no_rollback: + if (stmt != NULL) + sqlite3_finalize(stmt); + return sta; } bool diff --git a/src/net/listen.c b/src/net/listen.c index bdde8713..f2429357 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -251,8 +251,9 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) else if (STR_MATCH(cmd.name, "addid")) err = ! command_addid(srv, cmd.args); else if (STR_MATCH(cmd.name, "deleteid")) - err = ! (cmd.args[0] != NULL && - command_delid(srv, cmd.args)); + err = ! command_delid(srv, cmd.args); + else if (STR_MATCH(cmd.name, "delete")) + err = ! command_del(srv, cmd.args); else if (STR_MATCH(cmd.name, "playlistclear")) err = ! command_plt_clear(srv, cmd.args); -- GitLab