This commit is contained in:
2026-03-11 00:34:34 -04:00
parent cbd2270628
commit 0ed782c186
8 changed files with 50 additions and 349 deletions

View File

@@ -1,7 +1,6 @@
#include "include/chat.h"
#include "include/api.h"
#include "include/data.h"
#include "include/db.h"
#include "include/session.h"
#include <inttypes.h>
@@ -11,9 +10,33 @@
#include <time.h>
#include <yyjson.h>
static const char DEFAULT_ROOM[] = "global";
MsgData* chat_history[CHAT_HISTORY_SZ] = {NULL};
size_t chat_history_head = 0; // Next insertion index.
size_t chat_history_count = 0; // Number of valid entries.
static MsgID next_msg_id = 1;
// Legacy in-memory ring removed; history is now persisted in SQLite.
MsgData* chat_history_msg_add(MsgData* msg) {
chat_history[chat_history_head] = msg;
chat_history_head = (chat_history_head + 1) % CHAT_HISTORY_SZ;
if (chat_history_count < CHAT_HISTORY_SZ) { chat_history_count++; }
return msg;
}
MsgData** chat_history_nice(void) {
MsgData** msgs = calloc(CHAT_HISTORY_SZ, sizeof(MsgData*));
// Oldest entry is head - count (mod size).
size_t start = (chat_history_head + CHAT_HISTORY_SZ - chat_history_count) %
CHAT_HISTORY_SZ;
for (size_t j = 0; j < chat_history_count; j++) {
size_t idx = (start + j) % CHAT_HISTORY_SZ;
msgs[j] = chat_history[idx];
}
return msgs;
}
// Parse a raw packet.
Packet* packet_parse(const char* in, size_t len) {
@@ -46,9 +69,6 @@ void do_join(Session* sess, Packet* packet) {
session_set_name(sess, name);
}
#define WELCOME_HISTORY_LIMIT 50
#define HISTORY_LIMIT_MAX 200
// Do a welcome packet.
void do_welcome(Session* sess) {
// Build list of online users (only sessions with a name).
@@ -65,20 +85,10 @@ void do_welcome(Session* sess) {
oi++;
}
// Fetch latest messages from DB, then reverse to oldest-first.
MsgData** history = NULL;
// Build history list.
MsgData** history = chat_history_nice();
size_t historyc = 0;
if (db_fetch_messages(
DEFAULT_ROOM, 0, WELCOME_HISTORY_LIMIT, &history, &historyc
) != 0) {
history = NULL;
historyc = 0;
}
for (size_t i = 0; i < historyc / 2; i++) {
MsgData* tmp = history[i];
history[i] = history[historyc - 1 - i];
history[historyc - 1 - i] = tmp;
}
while (historyc < CHAT_HISTORY_SZ && history[historyc]) historyc++;
PacketWelcome data = {
.id = session_get_id(sess),
@@ -93,84 +103,7 @@ void do_welcome(Session* sess) {
session_send(sess, packet);
free(packet);
free(online);
if (history) {
for (size_t i = 0; i < historyc; i++) free(history[i]);
free(history);
}
}
// Handle a history request packet.
static void do_history_req(Session* sess, Packet* packet) {
if (!sess || !packet) return;
const yyjson_val* data = (const yyjson_val*)packet->data;
const yyjson_val* jroom = data ? yyjson_obj_get(data, "room") : NULL;
const char* room_str =
(jroom && yyjson_is_str(jroom)) ? yyjson_get_str(jroom) : DEFAULT_ROOM;
if (!room_verify(room_str)) room_str = DEFAULT_ROOM;
MsgID before = 0;
const yyjson_val* jbefore = data ? yyjson_obj_get(data, "before") : NULL;
if (jbefore) {
if (yyjson_is_int(jbefore)) {
int64_t v = yyjson_get_int(jbefore);
if (v > 0) before = (MsgID)v;
} else if (yyjson_is_str(jbefore)) {
const char* s = yyjson_get_str(jbefore);
char* endp = NULL;
unsigned long long tmp = strtoull(s, &endp, 10);
if (endp && *endp == '\0') before = (MsgID)tmp;
}
}
size_t limit = WELCOME_HISTORY_LIMIT;
const yyjson_val* jlimit = data ? yyjson_obj_get(data, "limit") : NULL;
if (jlimit && yyjson_is_int(jlimit)) {
int64_t v = yyjson_get_int(jlimit);
if (v > 0 && v <= HISTORY_LIMIT_MAX) limit = (size_t)v;
}
MsgData** rows = NULL;
size_t count = 0;
if (db_fetch_messages(room_str, before, limit + 1, &rows, &count) != 0) {
return;
}
bool has_more = false;
if (count > limit) {
has_more = true;
free(rows[count - 1]);
rows[count - 1] = NULL;
count = limit;
}
// reverse to oldest-first
for (size_t i = 0; i < count / 2; i++) {
MsgData* tmp = rows[i];
rows[i] = rows[count - 1 - i];
rows[count - 1 - i] = tmp;
}
MsgID oldest_id = count ? rows[0]->id : 0;
PacketHistoryRes res = {
.room = {0},
.historyc = count,
.history = rows,
.has_more = has_more,
.oldest_id = oldest_id
};
strncpy(res.room, room_str, ROOM_MAX_LENGTH - 1);
res.room[ROOM_MAX_LENGTH - 1] = '\0';
Packet* out = packet_init(PACKET_TYPE_HISTORY_RES, &res);
session_send(sess, out);
free(out);
if (rows) {
for (size_t i = 0; i < count; i++) free(rows[i]);
free(rows);
}
free(history);
}
// Do a welcome packet.
@@ -255,18 +188,15 @@ void do_msg(Session* sess, Packet* packet) {
}
}
MsgData* msg = calloc(1, sizeof(MsgData));
MsgData* msg = malloc(sizeof(MsgData));
if (!msg) {
lwsl_err("Failed to allocate MsgData.\n");
return;
}
msg->id = next_msg_id++;
msg->author.id = session_get_id(sess);
msg->author.name = session_get_name(sess);
strncpy(msg->author_name, *msg->author.name, NAME_MAX_LENGTH - 1);
msg->author_name[NAME_MAX_LENGTH - 1] = '\0';
strncpy(msg->room, DEFAULT_ROOM, ROOM_MAX_LENGTH - 1);
msg->room[ROOM_MAX_LENGTH - 1] = '\0';
msg->parent = parent;
strncpy(msg->content, content, MSG_MAX_LENGTH - 1);
msg->content[MSG_MAX_LENGTH - 1] = '\0';
@@ -278,14 +208,7 @@ void do_msg(Session* sess, Packet* packet) {
(msg->parent == UINT64_MAX ? "null" : "")
);
if (db_insert_message(msg, &msg->id) != 0) {
ack.status = "db_error";
Packet* p = packet_init(PACKET_TYPE_MSG_ACK, &ack);
session_send(sess, p);
free(p);
free(msg);
return;
}
chat_history_msg_add(msg);
ack.id = msg->id;
Packet* ackp = packet_init(PACKET_TYPE_MSG_ACK, &ack);
@@ -295,7 +218,6 @@ void do_msg(Session* sess, Packet* packet) {
Packet* evt = packet_init(PACKET_TYPE_MSG_EVT, msg);
session_send_all(evt);
free(evt);
free(msg);
}
static void do_ping(Session* sess) {
@@ -427,9 +349,6 @@ int cb_chat(
free(ackp);
break;
}
case PACKET_TYPE_HISTORY_REQ:
do_history_req(sess, packet);
break;
case PACKET_TYPE_PONG:
// Client responded; nothing else to do (timer continues).
if (sess) {