diff --git a/README.md b/README.md index 43209ff4cab96583a017132c489bac612736d8b6..63124e642a15257ee968e3187545f66a1641f3de 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 745485c79ee7034c264f38d7a06e8628a4f1307c..2f2c18ddec44bbbb7be0ddcae1092a71521a9626 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 b68219648110ae80bd8ab1d2196e4904c5b200e6..7a75115004582fcac67d102492a90b37edd5b425 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 c6882ac0bda0be6104ae2bda7f6c6fa7abf20cd5..1aee4b78701608bd0737128b8fff0c8470f3cdc2 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 bdde871306aec88b4849214025bed1527c24aa30..f24293579b41224a8a3938e8e745b339940762ce 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);