diff --git a/doc/protocol.rst b/doc/protocol.rst index 5b5e2cf03..214ab7520 100644 --- a/doc/protocol.rst +++ b/doc/protocol.rst @@ -1513,6 +1513,9 @@ Examples: sticker: name_1=value_1 OK +:command:`stickernames` + Gets a list of uniq sticker names. + Connection settings =================== diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx index da0ebd2b7..ddfe9a2b9 100644 --- a/src/command/AllCommands.cxx +++ b/src/command/AllCommands.cxx @@ -186,6 +186,7 @@ static constexpr struct command commands[] = { { "status", PERMISSION_READ, 0, 0, handle_status }, #ifdef ENABLE_SQLITE { "sticker", PERMISSION_ADMIN, 3, -1, handle_sticker }, + { "stickernames", PERMISSION_ADMIN, 0, 0, handle_sticker_names }, #endif { "stop", PERMISSION_PLAYER, 0, 0, handle_stop }, { "subscribe", PERMISSION_READ, 1, 1, handle_subscribe }, diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx index 800114efa..4f74049a0 100644 --- a/src/command/StickerCommands.cxx +++ b/src/command/StickerCommands.cxx @@ -102,6 +102,24 @@ public: return CommandResult::OK; } + virtual CommandResult Names() { + auto data = CallbackContext{ + .name = "", + .sticker_type = sticker_type, + .response = response, + .is_song = StringIsEqual("song", sticker_type) + }; + + auto callback = [](const char *found_value, void *user_data) { + auto context = reinterpret_cast(user_data); + context->response.Fmt("name: {}\n", found_value); + }; + + sticker_database.Names(callback, &data); + + return CommandResult::OK; + } + protected: DomainHandler(Response &_response, const Database &_database, @@ -292,6 +310,24 @@ private: } // namespace +CommandResult +handle_sticker_names(Client &client, Request args, Response &r) +{ + (void) args; + auto &instance = client.GetInstance(); + if (!instance.HasStickerDatabase()) { + r.Error(ACK_ERROR_UNKNOWN, "sticker database is disabled"); + return CommandResult::ERROR; + } + + auto &db = client.GetPartition().GetDatabaseOrThrow(); + auto &sticker_database = *instance.sticker_database; + + std::unique_ptr handler = std::make_unique(r, db, sticker_database); + + return handler->Names(); +} + CommandResult handle_sticker(Client &client, Request args, Response &r) { diff --git a/src/command/StickerCommands.hxx b/src/command/StickerCommands.hxx index 08912f089..aa3aeef2c 100644 --- a/src/command/StickerCommands.hxx +++ b/src/command/StickerCommands.hxx @@ -12,5 +12,7 @@ class Response; CommandResult handle_sticker(Client &client, Request request, Response &response); +CommandResult +handle_sticker_names(Client &client, Request request, Response &response); #endif diff --git a/src/sticker/Database.cxx b/src/sticker/Database.cxx index 2c78fe997..c5b3429e2 100644 --- a/src/sticker/Database.cxx +++ b/src/sticker/Database.cxx @@ -32,6 +32,7 @@ enum sticker_sql { STICKER_SQL_TRANSACTION_BEGIN, STICKER_SQL_TRANSACTION_COMMIT, STICKER_SQL_TRANSACTION_ROLLBACK, + STICKER_SQL_NAMES, STICKER_SQL_COUNT }; @@ -72,6 +73,9 @@ static constexpr auto sticker_sql = std::array { //[STICKER_SQL_TRANSACTION_ROLLBACK] "ROLLBACK", + + //[STICKER_SQL_NAMES] + "SELECT DISTINCT name FROM sticker order by name", }; static constexpr const char sticker_sql_create[] = @@ -366,6 +370,23 @@ StickerDatabase::GetUniqueStickers() return result; } +void +StickerDatabase::Names(void (*func)(const char *value, void *user_data), void *user_data) +{ + assert(func != nullptr); + + sqlite3_stmt *const s = stmt[STICKER_SQL_NAMES]; + assert(s != nullptr); + + AtScopeExit(s) { + sqlite3_reset(s); + }; + + ExecuteForEach(s, [s, func, user_data](){ + func((const char*)sqlite3_column_text(s, 0), user_data); + }); +} + void StickerDatabase::BatchDeleteNoIdle(const std::list &stickers) { diff --git a/src/sticker/Database.hxx b/src/sticker/Database.hxx index c4a3cceef..8d7f8d28f 100644 --- a/src/sticker/Database.hxx +++ b/src/sticker/Database.hxx @@ -54,6 +54,7 @@ class StickerDatabase { SQL_TRANSACTION_BEGIN, SQL_TRANSACTION_COMMIT, SQL_TRANSACTION_ROLLBACK, + SQL_NAMES, SQL_COUNT }; @@ -146,6 +147,11 @@ public: void *user_data), void *user_data); + /** + * Uniq and sorted list of all sticker names + */ + void Names(void (*func)(const char *value, void *user_data), void *user_data); + using StickerTypeUriPair = std::pair; /**