From 2a44156d155737ae81a17de0b97f5370ee461279 Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Wed, 15 Apr 2020 14:52:20 +0200
Subject: [PATCH] WIP: A first try of getting the continue working

---
 inc/lektor/database.h |  5 +++--
 src/commands.c        | 18 +++++++++++++++---
 src/database/queue.c  | 24 ++++++++++++++----------
 src/main/lkt.c        | 14 ++++++--------
 src/net/listen.c      | 13 +++++++++++--
 5 files changed, 49 insertions(+), 25 deletions(-)

diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index 796398e9..03b451fa 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -82,8 +82,9 @@ struct lkt_callback {
 };
 
 /* List the content of the queue */
-bool database_queue_list_from(sqlite3 *db, unsigned int count, struct lkt_callback *callback);
-bool database_queue_list_abs(sqlite3 *db, unsigned int from, unsigned int to, struct lkt_callback *callback);
+bool database_queue_list_from(sqlite3 *db, size_t count, size_t *continuation, struct lkt_callback *callback);
+bool database_queue_list_abs(sqlite3 *db, size_t from, size_t to, size_t *continuation,
+                             struct lkt_callback *callback);
 
 /* Search the database */
 bool database_search_queue_init(sqlite3 *db, char *col_name, char *rgx, sqlite3_stmt **ret);
diff --git a/src/commands.c b/src/commands.c
index 67314205..94381e9a 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1,5 +1,6 @@
 #define _POSIX_C_SOURCE 200809L
 
+#include <lektor/macro.h>
 #include <lektor/commands.h>
 #include <lektor/database.h>
 #include <lektor/net.h>
@@ -884,8 +885,9 @@ bool
 command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     unsigned int count, from, to, tmp_switch;
-    long val;
+    long val, ret;
     char *endptr, *str;
+    size_t continuation = lkt_get_continuation(srv, c);
     struct lkt_callback callback = {
         .call = lkt_callback_send_row_v1,
         .srv = srv,
@@ -954,11 +956,21 @@ command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_
     /* The command is used in its relative forme, display elements from the
        current one. */
 is_relative:
-    return database_queue_list_from(srv->db, count, &callback);
+    count -= continuation;
+    if (count < lkt_remaining_msg(srv, c) - 1) {
+        lkt_set_continuation(srv, c, 0);
+        return database_queue_list_from(srv->db, count, &continuation, &callback);
+    } else {
+        count = lkt_remaining_msg(srv, c) - 2;  /* One for `continue: i` and one for OK/ACK. */
+        ret = database_queue_list_from(srv->db, count, &continuation, &callback);
+        lkt_set_continuation(srv, c, continuation + count);
+        return ret;
+    }
 
     /* The command is used with a range specifier. */
 is_absolute:
-    return database_queue_list_abs(srv->db, from, to, &callback);
+    ret = database_queue_list_abs(srv->db, from, to, &continuation, &callback);
+    return ret;
 }
 
 bool
diff --git a/src/database/queue.c b/src/database/queue.c
index ff7f174e..8419740d 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -673,25 +673,29 @@ error:
 }
 
 bool
-database_queue_list_abs(sqlite3 *db, unsigned int from, unsigned int to, struct lkt_callback *callback)
+database_queue_list_abs(sqlite3 *db, size_t from, size_t to, size_t *continuation,
+                        struct lkt_callback *callback)
 {
-    const char *SQL_STMT =
+    const char *SQL_TEMPLATE =
         "WITH content AS ("
         " SELECT kara.id AS id, string, LENGTH(CAST(kara.id AS TEXT)) AS len"
         "  FROM queue_"
         "  JOIN kara ON kara_id = kara.id"
         "  WHERE position >= ? AND position <= ?"
-        "  GROUP BY position ORDER BY position)"
+        "  GROUP BY position ORDER BY position LIMIT %d OFFSET %d)"
         "SELECT id, string, (SELECT MAX(len) FROM content)"
         " FROM content;";
     int code, id, id_len;
+    char SQL_STMT[LKT_MAX_SQLITE_STATEMENT];
     const char *row;
     bool ret = false;
     sqlite3_stmt *stmt;
 
+    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_TEMPLATE, to - from + 1, *continuation);
+    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
-    SQLITE_BIND_INT(db, stmt, 1, from, error);
-    SQLITE_BIND_INT(db, stmt, 2, to, error);
+    SQLITE_BIND_INT(db, stmt, 1, (int) from, error);
+    SQLITE_BIND_INT(db, stmt, 2, (int) to, error);
 
     for (;;) {
         code = sqlite3_step(stmt);
@@ -723,7 +727,7 @@ error:
 }
 
 bool
-database_queue_list_from(sqlite3 *db, unsigned int count, struct lkt_callback *callback)
+database_queue_list_from(sqlite3 *db, size_t count, size_t *continuation, struct lkt_callback *callback)
 {
     const char *SQL_TEMPLATE =
         "WITH content AS ("
@@ -733,17 +737,17 @@ database_queue_list_from(sqlite3 *db, unsigned int count, struct lkt_callback *c
         "    WHEN queue_state.current IS NULL THEN 1"
         "    ELSE queue_state.current END"
         "  JOIN kara ON kara_id = kara.id"
-        "  GROUP BY position ORDER BY position LIMIT %d)"
+        "  GROUP BY position ORDER BY position LIMIT %d OFFSET %d)"
         "SELECT id, string, (SELECT MAX(len) FROM content)"
         " FROM content;";
-    static const int stmt_len = 512;
-    char SQL_STMT[stmt_len];
+    char SQL_STMT[LKT_MAX_SQLITE_STATEMENT];
     int code, id, id_len;
     const char *row;
     bool ret = false;
     sqlite3_stmt *stmt;
 
-    snprintf(SQL_STMT, stmt_len, SQL_TEMPLATE, count);
+    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_TEMPLATE, count, *continuation);
+    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
 
     for (;;) {
diff --git a/src/main/lkt.c b/src/main/lkt.c
index 2356f744..da9ad84b 100644
--- a/src/main/lkt.c
+++ b/src/main/lkt.c
@@ -196,7 +196,7 @@ err:
 static inline int
 write_continue(FILE *sock, const int continuation)
 {
-    return write_socket(sock, "continue %d\n", continuation);
+    return write_socket_format(sock, "continue %d\n", continuation);
 }
 
 static FILE *
@@ -585,13 +585,11 @@ list__(struct lkt_cmd_args *args)
     FILE *sock = NULL;
 redo:
     sock = lkt_connect();
-
-    if (continuation > 0)
-        write_continue(sock, continuation);
-
-    write_socket(sock, "playlist ", strlen("playlist "));
-    write_socket(sock, args->argv[0], strlen(args->argv[0]));
-    write_socket(sock, "\n", sizeof(char));
+    write_socket_format(sock, "command_list_begin\n"
+                        "continue %d\n"
+                        "playlist %s\n"
+                        "command_list_end\n",
+                        continuation, args->argv[0]);
 
     for (;;) {
         memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char));
diff --git a/src/net/listen.c b/src/net/listen.c
index 11418168..f4bbf152 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -160,7 +160,7 @@ command_list_begin(struct lkt_state *srv, size_t c, int list_ok)
 static int
 handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
 {
-    int err;
+    int err, continuation = 0;
 
     switch (*lkt_client_get_mask(srv, c)) {
     case MPD_IDLE_NONE:
@@ -193,8 +193,11 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
         else if (!strcmp(cmd.name, "ping"))
             err = 0;
         else if (!strcmp(cmd.name, "continue")) {
-            srv->clients[c - 1].continuation = atoi(cmd.args[0]);
+            continuation = atoi(cmd.args[0]);
+            lkt_set_continuation(srv, c, continuation);
+            fprintf(stderr, " * Client is continuing from %d\n", continuation);
             err = 0;
+            goto skip_continue;
         }
 
         else if (!strcmp(cmd.name, "next"))
@@ -300,6 +303,12 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
         break;
     }
 
+    continuation = lkt_get_continuation(srv, c);
+    if (continuation > 0) {
+        fprintf(stderr, " * Client should continue from %d\n", continuation);
+        send_continue(srv, c, continuation);
+    }
+skip_continue:
     send_status(srv, c, err, cmd.name);
 end_no_send_status:
     return err;
-- 
GitLab