Browse Source

fix chatgui: message format, member notify, chain_hash sync

- on_db_sync_insert: parse JSON {"n":...,"ct":...,"d":...}, store
  d→data, n→node_id, ct→content_type with proper chain_hash
  (fixes JSON displayed instead of message text)
- chat_core_cursor_open: SELECT chain_hash column
- chat_core_cursor_next: include chain_hash(32) in output record
- cs_handle_send_data: parse chain_hash in received records
  (fixes chain_hash mismatch → all sync records were dropped)
- cs_handle_channel_join: post GUI_EVT_MEMBERS_CHANGED
  (fixes creator not seeing new member after join)
- cs_handle_welcome: trigger INIT_SYNC with inviter after join
  (fixes no message sync after invite join)
topo_upd
Evgeny 3 months ago
parent
commit
2d179ec41d
  1. 42
      tools/chatgui/transport/chat_core.c
  2. 26
      tools/chatgui/transport/chat_sync.c

42
tools/chatgui/transport/chat_core.c

@ -453,7 +453,7 @@ uint32_t chat_core_cursor_open(const char* ch_id) {
if (g_cc.cursors[i]) continue;
char tbl[80]; msg_table_name(ch_id, tbl, sizeof(tbl));
char sql[256]; snprintf(sql, sizeof(sql),
"SELECT timestamp, datahash, node_id, content_type, data"
"SELECT timestamp, datahash, node_id, content_type, data, chain_hash"
" FROM \"%s\" ORDER BY timestamp, datahash ASC", tbl);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(g_cc.db, sql, -1, &stmt, NULL) != SQLITE_OK) return 0;
@ -479,10 +479,12 @@ int chat_core_cursor_next(uint32_t cursor_id, uint8_t* buf, size_t buf_size,
uint64_t nid= (uint64_t)sqlite3_column_int64(stmt, 2);
const char* ct = (const char*)sqlite3_column_text(stmt, 3);
int ct_len = sqlite3_column_bytes(stmt, 3);
const uint8_t* data = (const uint8_t*)sqlite3_column_blob(stmt, 4);
const uint8_t* dptr = (const uint8_t*)sqlite3_column_blob(stmt, 4);
int dlen = sqlite3_column_bytes(stmt, 4);
const uint8_t* ch_ptr = (const uint8_t*)sqlite3_column_blob(stmt, 5);
int ch_len = sqlite3_column_bytes(stmt, 5);
size_t need = 8 + 8 + 8 + 1 + (size_t)ct_len + 4 + (size_t)dlen;
size_t need = 8 + 8 + 8 + 1 + (size_t)ct_len + 4 + (size_t)dlen + 32;
if (need > buf_size) return -1;
uint8_t* out = buf;
@ -493,7 +495,9 @@ int chat_core_cursor_next(uint32_t cursor_id, uint8_t* buf, size_t buf_size,
if (ct_len) { memcpy(out, ct, (size_t)ct_len); out += ct_len; }
uint32_t dl32 = (uint32_t)dlen;
memcpy(out, &dl32, 4); out += 4;
if (dlen) { memcpy(out, data, (size_t)dlen); out += dlen; }
if (dlen) { memcpy(out, dptr, (size_t)dlen); out += dlen; }
if (ch_ptr && ch_len >= 32) memcpy(out, ch_ptr, 32); else memset(out, 0, 32);
out += 32;
*out_len = (size_t)(out - buf);
return 0;
}
@ -994,22 +998,40 @@ static void si_register(struct DB_SYNC_INSTANCE* si, const char* ch_id) {
static void on_db_sync_insert(struct DB_SYNC_INSTANCE* si, const char* data, size_t len, uint64_t author, void* arg) {
const char* ch_id = (const char*)arg;
uint64_t dh; compute_datahash((const uint8_t*)data, len, &dh);
/* parse JSON: {"n":<uint64>,"ch":"<str>","ct":"<str>","d":"<str>"} */
const char* p = data; const char* end = data + len; uint64_t jn = 0;
{ /* "n" */
const char* n = strstr(p, "\"n\":"); if (!n) return;
n += 4; jn = strtoull(n, NULL, 0); p = n;
}
const char* jct = "text/plain"; size_t jct_len = 10;
{ /* "ct" */
const char* ct = strstr(p, "\"ct\":\""); if (ct) { ct += 6; const char* ce = strchr(ct, '"'); if (ce) { jct = ct; jct_len = (size_t)(ce - ct); p = ce; } }
}
const char* jd_start = NULL; size_t jd_len = 0;
{ /* "d" */
const char* d = strstr(p, "\"d\":\""); if (d) { d += 5; const char* de = d; while (de < end) { if (*de == '"' && (de == d || *(de - 1) != '\\')) break; de++; } if (de < end) { jd_start = d; jd_len = (size_t)(de - d); } }
}
if (!jd_start) return;
uint64_t dh; compute_datahash((const uint8_t*)jd_start, jd_len, &dh);
uint64_t ts = get_time_us();
char tbl[80]; msg_table_name(ch_id, tbl, sizeof(tbl));
uint8_t prev_ch[32]; get_last_chain_hash(ch_id, prev_ch);
uint8_t chain_h[32]; compute_chain_hash(prev_ch, (int64_t)ts, dh, chain_h);
char sql[512]; snprintf(sql, sizeof(sql),
"INSERT OR IGNORE INTO \"%s\" (node_id,content_type,data,timestamp,datahash,chain_hash,signature,is_outgoing,is_read,sync_flags)"
" VALUES(?,?,?,?,?,?,?,?,?,?)", tbl);
sqlite3_stmt* st=NULL;
if (sqlite3_prepare_v2(g_cc.db,sql,-1,&st,NULL)!=SQLITE_OK) return;
sqlite3_bind_int64(st,1,(sqlite3_int64)author);
sqlite3_bind_text(st,2,"text/plain",-1,SQLITE_STATIC);
sqlite3_bind_blob(st,3,data,(int)len,SQLITE_STATIC);
sqlite3_bind_int64(st,1,(sqlite3_int64)jn);
sqlite3_bind_text(st,2,jct,(int)jct_len,SQLITE_STATIC);
sqlite3_bind_blob(st,3,jd_start,(int)jd_len,SQLITE_STATIC);
sqlite3_bind_int64(st,4,(sqlite3_int64)ts);
sqlite3_bind_int64(st,5,(sqlite3_int64)dh);
{ static const uint8_t z32[32]={0}; sqlite3_bind_blob(st,6,z32,32,SQLITE_STATIC); }
sqlite3_bind_blob(st,6,chain_h,32,SQLITE_STATIC);
{ static const uint8_t z64[64]={0}; sqlite3_bind_blob(st,7,z64,64,SQLITE_STATIC); }
sqlite3_bind_int(st,8,author==g_cc.my_node_id?1:0);
sqlite3_bind_int(st,8,(uint64_t)jn==g_cc.my_node_id?1:0);
sqlite3_bind_int(st,9,1); sqlite3_bind_int(st,10,0);
int rc=sqlite3_step(st); sqlite3_finalize(st);
if (rc==SQLITE_DONE) {

26
tools/chatgui/transport/chat_sync.c

@ -213,8 +213,9 @@ static void cs_handle_send_data(struct chat_sync* cs, uint64_t peer,
ptr += ct_len; remain -= ct_len;
if (remain < 4) break;
uint32_t dlen; memcpy(&dlen, ptr, 4); ptr += 4; remain -= 4;
if (remain < dlen) break;
if (remain < dlen + 32) break;
ptr += dlen; remain -= dlen;
ptr += 32; remain -= 32; /* chain_hash */
size_t reclen = (size_t)(ptr - rec_start);
chat_core_insert_record(ch_id, rec_start, reclen);
@ -949,6 +950,9 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
ch = cs_find(cs, ch_id);
}
{ uint8_t evt[65]; uint8_t cl=(uint8_t)strlen(ch_id); evt[0]=cl; memcpy(evt+1,ch_id,cl);
gui_bridge_post(GUI_EVT_MEMBERS_CHANGED, evt, 1+cl); }
DEBUG_INFO(DEBUG_CATEGORY_CONNECTIVITY, "%s: JOIN accepted node=0x%016llx ch=%s addrs=%d",
CS_ID, (unsigned long long)node_id, ch_id, addr_cnt);
}
@ -1000,6 +1004,26 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
cs_refresh_channels(cs);
/* initiate message sync with the inviter after join */
for (int i = 0; i < cs->channel_count; i++) {
struct channel_cache* ch2 = &cs->channels[i];
if (strcmp(ch2->channel_id, ch_id) != 0) continue;
int found = 0;
for (int j = 0; j < ch2->peer_count; j++)
if (ch2->peer_ids[j] == peer) { found = 1; break; }
if (found) {
ch2->synced = CS_SYNC_IN_PROGRESS;
uint8_t msg[37]; msg[0] = CS_MSG_INIT_SYNC;
chat_core_chain_hash_at(ch2->channel_id,
ch2->msg_count > 0 ? ch2->msg_count - 1 : 0, ch2->last_chain_hash);
memcpy(msg + 1, &ch2->msg_count, 4);
memcpy(msg + 5, ch2->last_chain_hash, 32);
cs_send(cs, ch2->channel_id, peer, msg, 37);
member_sync_start(cs->inst, peer, ch2->channel_id, _on_member_sync_done, ch2);
}
break;
}
uint8_t evt[65]; uint8_t ch_id_len = (uint8_t)strlen(ch_id);
evt[0] = ch_id_len; memcpy(evt + 1, ch_id, ch_id_len);
gui_bridge_post(GUI_EVT_CHANNEL_UPDATED, evt, 1 + ch_id_len);

Loading…
Cancel
Save