|
|
|
|
@ -378,48 +378,40 @@ int chat_core_get_channels_json(struct UTUN_INSTANCE* inst, char* buf, size_t bu
|
|
|
|
|
|
|
|
|
|
int chat_core_get_messages_json(struct UTUN_INSTANCE* inst, const char* ch_id, int count, int offset, |
|
|
|
|
char* buf, size_t buf_size, size_t* out_len) { |
|
|
|
|
struct chat_core_ctx* cc = CC(inst); |
|
|
|
|
if (!cc || !cc->initialized || !ch_id || !buf || !out_len) return -1; |
|
|
|
|
char tbl[80]; msg_table_name(ch_id, tbl, sizeof(tbl)); |
|
|
|
|
char* w = buf; char* end = buf + buf_size; |
|
|
|
|
*w++ = '['; const char* sep = ""; |
|
|
|
|
char sql[256]; |
|
|
|
|
struct chat_core_ctx* cc = inst ? CC(inst) : NULL; |
|
|
|
|
if (out_len) *out_len = 0; |
|
|
|
|
if (!cc || !cc->initialized || !ch_id || !buf || !out_len || buf_size < 3 || offset < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: invalid message listing arguments", CC_ID); return -1; |
|
|
|
|
} |
|
|
|
|
char table[80], sql[768]; msg_table_name(ch_id, table, sizeof(table)); |
|
|
|
|
snprintf(sql, sizeof(sql), |
|
|
|
|
"SELECT m.id, m.timestamp, m.node_id, CAST(m.data AS TEXT), n.name, m.local_attrs " |
|
|
|
|
"FROM \"%s\" m LEFT JOIN nodes n ON m.node_id=n.node_id " |
|
|
|
|
"ORDER BY m.timestamp DESC LIMIT ? OFFSET ?", tbl); |
|
|
|
|
"SELECT json_object('id',m.id,'message_id',lower(hex(m.message_id)),'ts',m.timestamp," |
|
|
|
|
"'author_id',printf('0x%%016llx',m.node_id),'author_name',coalesce(n.name,'')," |
|
|
|
|
"'content_type',CASE WHEN json_valid(CAST(m.data AS TEXT)) THEN json_extract(CAST(m.data AS TEXT),'$.ct') ELSE 'text' END," |
|
|
|
|
"'data',coalesce(CAST(m.data AS TEXT),''),'local_attrs',coalesce(m.local_attrs,''))" |
|
|
|
|
" FROM \"%s\" m LEFT JOIN nodes n ON m.node_id=n.node_id" |
|
|
|
|
" ORDER BY m.timestamp DESC,m.author_signature DESC LIMIT ? OFFSET ?", table); |
|
|
|
|
sqlite3_stmt* st = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(cc->db, sql, -1, &st, NULL) != SQLITE_OK) { *out_len = 0; return -1; } |
|
|
|
|
sqlite3_bind_int(st, 1, count > 0 ? count : 100); |
|
|
|
|
sqlite3_bind_int(st, 2, offset); |
|
|
|
|
while (sqlite3_step(st) == SQLITE_ROW) { |
|
|
|
|
int64_t id = sqlite3_column_int64(st, 0); |
|
|
|
|
int64_t ts = sqlite3_column_int64(st, 1); |
|
|
|
|
uint64_t author_id = (uint64_t)sqlite3_column_int64(st, 2); |
|
|
|
|
const char* data = (const char*)sqlite3_column_text(st, 3); |
|
|
|
|
const char* author_name = (const char*)sqlite3_column_text(st, 4); |
|
|
|
|
const char* la = (const char*)sqlite3_column_text(st, 5); |
|
|
|
|
if (!data) data = ""; |
|
|
|
|
if (!la) la = ""; |
|
|
|
|
const char* ct = "text"; |
|
|
|
|
char ctbuf[32] = {0}; |
|
|
|
|
const char* ctpos = strstr(data, "\"ct\":\""); |
|
|
|
|
if (ctpos) { ctpos += 6; int ci = 0; while (*ctpos && *ctpos != '"' && ci < 31) ctbuf[ci++] = *ctpos++; ct = ctbuf; } |
|
|
|
|
char esc_data[4096], esc_aname[256], esc_la[256]; |
|
|
|
|
json_escape(data, esc_data, sizeof(esc_data)); |
|
|
|
|
json_escape(author_name ? author_name : "", esc_aname, sizeof(esc_aname)); |
|
|
|
|
json_escape(la, esc_la, sizeof(esc_la)); |
|
|
|
|
w += snprintf(w, (size_t)(end - w), |
|
|
|
|
"%s{\"id\":%lld,\"ts\":%lld,\"author_id\":\"0x%016llx\",\"author_name\":\"%s\"," |
|
|
|
|
"\"content_type\":\"%s\",\"data\":\"%.2000s\",\"local_attrs\":\"%s\"}", |
|
|
|
|
sep, (long long)id, (long long)ts, (unsigned long long)author_id, esc_aname, ct, esc_data, esc_la); |
|
|
|
|
sep = ","; |
|
|
|
|
if (sqlite3_prepare_v2(cc->db, sql, -1, &st, NULL) != SQLITE_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: messages query ch=%s: %s", CC_ID, ch_id, sqlite3_errmsg(cc->db)); return -1; |
|
|
|
|
} |
|
|
|
|
sqlite3_bind_int(st, 1, count > 0 ? count : 100); sqlite3_bind_int(st, 2, offset); |
|
|
|
|
size_t off = 1; buf[0] = '['; int step, result = 0; |
|
|
|
|
while ((step = sqlite3_step(st)) == SQLITE_ROW) { |
|
|
|
|
const char* row = (const char*)sqlite3_column_text(st, 0); size_t bytes = sqlite3_column_bytes(st, 0); |
|
|
|
|
if (!row || bytes + (off > 1) + 2 > buf_size - off) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: messages exceed output buffer ch=%s capacity=%zu", CC_ID, ch_id, buf_size); |
|
|
|
|
result = -1; break; |
|
|
|
|
} |
|
|
|
|
if (off > 1) buf[off++] = ','; |
|
|
|
|
memcpy(buf + off, row, bytes); off += bytes; |
|
|
|
|
} |
|
|
|
|
if (result == 0 && step != SQLITE_DONE) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: messages read ch=%s: %s", CC_ID, ch_id, sqlite3_errmsg(cc->db)); result = -1; |
|
|
|
|
} |
|
|
|
|
sqlite3_finalize(st); |
|
|
|
|
*w++ = ']'; |
|
|
|
|
*w = '\0'; |
|
|
|
|
*out_len = (size_t)(w - buf); |
|
|
|
|
return 0; |
|
|
|
|
if (result < 0) { buf[0] = 0; return -1; } |
|
|
|
|
buf[off++] = ']'; buf[off] = 0; *out_len = off; return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int chat_core_get_members_json(struct UTUN_INSTANCE* inst, const char* ch_id, char* buf, size_t buf_size, size_t* out_len) { |
|
|
|
|
|