Commit Graph
2373 Commits
Author SHA1 Message Date
Evgeny 11ab897fe5 chatgui: fix RTT display 10x overstatement (DB stores 0.1ms, displayed as ms); remove unused rtt_avg_100 2026-07-26 08:57:02 +03:00
Evgeny 12904a97e0 chatgui: AccountDelegate — palette-consistent colors (light/alternateBase instead of hardcoded) 2026-07-26 07:43:01 +03:00
Evgeny 77d89b841a chatgui: double-click member edit, fix delegate backgrounds; transport: invite_sync/member_sync robustness 2026-07-26 07:18:27 +03:00
Evgeny cd3c3ad07d merkle_sync: fix level 0 SQL range, rebuild trees at startup
- _get_level_hashes: use separate SQL without prefix64<=? for level 0.
  UINT64_MAX cast to sqlite3_int64 becomes -1, making prefix64<=-1 always
  false for positive prefixes → bitmap always 0 → sync never exchanges data.
- member_sync_init: add _rebuild_all_trees to scan all peers_* tables and
  call merkle_sync_recompute_path for each member. Ensures merkle_tree_hash
  has entries for members added before merkle sync existed.
2026-07-25 23:31:36 +03:00
Evgeny 6bf8482558 merkle_sync: fix BATCH parse, synthetic HASHES, initiator done_cb
- Add 2-byte dlen prefix to terminal BATCH/HASHES data so receiver knows
  exact byte count — fixes rem=0 bug that truncated multi-item BATCHes.
- Fix synthetic HASHES prefix_bytes: use merkle_sync_prefix_bytes(next_lvl)
  for both declaration and _prefix_write, not current level's pb_i.
- Fix initiator never getting _session_done: responder sends confirmation
  HASHES(is_data=1,level=0) before _session_done so initiator's done_cb fires.
- Add level==0 guard in _member_get_items/_member_update_bucket_hash
  to prevent SQL queries with bogus mask on virtual root level.
2026-07-25 23:11:53 +03:00
Evgeny be10714972 merkle_sync: fix prefix reconstruction, remove timeouts/retries
- _get_level_hashes: remove (0x1F << parent_shift) from range_end so
  bitmap only includes children of the actual parent prefix (not all
  parents). Add level 0 virtual root that queries all level-1 entries.
- merkle_sync_start: send HASHES at level 0 (virtual root) instead of
  level 1/prefix 0. Root-level REQUEST prefix reconstruction now uses
  the correct level-1 prefix from DB.
- _handle_batch: use merkle_sync_prefix_bytes(next_lvl) for synthetic
  child HASHES instead of current level's pb_i (could be wrong size).
- Remove timeout/retry mechanism: delete _session_timeout_cb,
  _session_start_timer, timer/retries fields. ETCP provides reliable
  transport — no need for application-layer retries.
2026-07-25 23:00:42 +03:00
Evgeny 332e3a61e5 fix merkle_sync: prefix serialization writes LSB bytes instead of MSB
_prefix_write was writing the least significant pb bytes of the 64-bit
prefix, but the protocol expects the most significant pb bytes (bits
63..64-pb*8). For pb<=4 these ranges are disjoint → wire always got
zeros. _prefix_read also lacked the final left-shift to align the
result at bit 63.

This caused all level>=2 merkle sync requests/batches to receive
prefix=0 instead of the real prefix, making get_items/update_bucket_hash
find zero members → handle_batch len=7 with no data → sync completed
without actually exchanging member data.
2026-07-25 21:53:06 +03:00
Evgeny ccc5396167 merkle_sync: fix _handle_batch — call _session_done after terminal buckets 2026-07-25 21:32:00 +03:00
Evgeny d512bacc81 merkle_sync: fix message format — type after ns (match chat_sync) 2026-07-25 20:56:05 +03:00
Evgeny ecb03ca290 conn_mgr: detect duplicate conn in handshake; etcp: loud collision errors in link/peer_id 2026-07-25 19:43:26 +03:00
Evgeny a4582202a8 merkle_sync: fix range_end formula — cover all parent+child bucket bits 2026-07-25 17:58:51 +03:00
Evgeny be5a760de9 merkle_sync: add debug logs to _get_level_hashes (SQL error + bitmap result) 2026-07-25 17:43:22 +03:00
Evgeny 5983acd988 merkle_sync: fix _get_level_hashes — range query instead of exact mismatch (prefix encoding bug) 2026-07-25 17:37:12 +03:00
Evgeny 7a9e3bea5f db_sync: mc>pc guard with last_peer_count — detect stalled sync when pc doesn't change 2026-07-25 16:56:30 +03:00
Evgeny 3490789249 db_sync: skip SYNC_DONE in count>0 handler when received==0 — breaks bad_sig recv→send loop on client side 2026-07-25 16:49:46 +03:00
Evgeny c9436219a0 db_sync: fix synced_pos overwrite in SYNC_DONE — use max to preserve total_processed advance 2026-07-25 16:28:09 +03:00
Evgeny 34404403ef db_sync: verify sig before send + fix total_processed double-count 2026-07-25 16:10:20 +03:00
Evgeny e9fce43be5 db_sync: fix bad_sig infinite loop — delete+rechain, advance synced_pos past dup/bad_sig, accept on covered tail 2026-07-25 15:58:18 +03:00
Evgeny 27906e9f91 db_sync: односторонний sync, sparse-таблица, vp в SEND_DATA, PUSH-релей 2026-07-25 15:00:21 +03:00
Evgeny fe18c454e2 chatgui: add diagnostic logging for Windows emoji animation bug investigation 2026-07-24 22:11:03 +03:00
Evgeny e071a9e2f8 db_sync: fix test sync protocol isolation (add auto_sync flag, destroy order, test refactor)
- utun_instance: fix destroy order (topo_groups before conn_mgr to avoid UAF in topo_recovery)
- topo_recovery: add NULL guard for instance/ua in try_next
- db_sync_instance_add: add auto_sync flag (1=send INIT_SYNC, 0=quiet)
  replaces separate _quiet variant, cleaner API
- db_sync_peer_set_state, db_sync_reinitiate: test-only peer control utilities
- test_db_sync: full rewrite — stable, isolated sync protocol testing
  all 3 branches (peer_empty, hash_MATCH, divergence) tested without PUSH contamination
  Phase 6 extended: triple merge + tail PUSH + mid PUSH cascade on star topology
  runs in 1.4s, consistently passes 10/10
- db_sync_doc: updated protocol architecture description
- chatgui: update db_sync_instance_add call with auto_sync=1
2026-07-24 21:27:23 +03:00
Evgeny ad56767646 db_sync: notify all peers when cascade_from changes chain (lock-free sync)
После cascade_from в db_handle_send_data оповещаем ВСЕХ пиров
с synced_pos >= fix_from о том что цепочка изменилась — откатываем
их synced_pos. Это устраняет неэффективность конкурентных sync:
раньше только пир-отправитель обновлялся, остальные видели устаревшие
хеши и обнаруживали ложное расхождение на следующем цикле.
2026-07-24 17:26:09 +03:00
Evgeny c46cb9a979 db_sync: fix si_send_data_batch column bug (author→node_id), add cascade_from to PUSH, add divergence+cascade test phases
- si_send_data_batch: неправильный SQL SELECT с несуществующей колонкой author
  вместо node_id → ломал всю передачу данных в REFINE/SEND_DATA
- Добавлена проверка si_prep и возврат int с кодом ошибки
- Все вызовы si_send_data_batch проверяют возврат, при ошибке сброс sync_state
- db_handle_push: добавлен db_cascade_from после вставки (раньше chain_hash
  не пересчитывался после PUSH)
- db_handle_refine: DEBUG_WARN при scnt==0 (fm за пределами диапазона)
- Добавлена публичная db_sync_chain_verify() для верификации цепочек
- test_db_sync: фаза 4 (divergence через разныe hashes + REFINE/SEND_DATA),
  фаза 5 (PUSH без хвоста + cascade verification)
- Убран мёртвый код db_sync_on_new_conn
- chatgui: адаптивная раскраска пузырей исходящих сообщений
2026-07-24 16:55:08 +03:00
Evgeny df8d910efa chatgui: fix Ctrl-C on Linux — remove thread_local from g_currentNode
SIGINT on Linux can be delivered to any thread (not just worker).
signal_handler uses g_currentNode->requestStop(); with thread_local,
g_currentNode was nullptr in non-worker threads — Ctrl-C did nothing.

Removing thread_local fixes signal delivery: g_currentNode is set once
before signal handler is registered, pointer read is atomic on x86/x64.
2026-07-24 16:02:49 +03:00
Evgeny e8920fe00e chatgui: MsgIsOutgoingRole support for outgoing message alignment 2026-07-24 15:55:34 +03:00
Evgeny fbc1bff1e1 chatgui: proper animation shutdown + TerminateProcess for rlottie threads
- AnimTimer::shutdown(): stop QTimer, clear m_icons before icon destruction
- ~MainWindow: AnimTimer::shutdown() -> cleanupAnimations() (correct order)
- main: replace ExitProcess with TerminateProcess(GetCurrentProcess,0)
  TerminateProcess skips DLL_PROCESS_DETACH, avoiding libwinpthread
  pthread_join hang on rlottie/miniaudio threads.
  rlottie C API has no global shutdown - internal RleTaskScheduler threads
  cannot be stopped through public API. Same for miniaudio WASAPI threads.
  All owned resources already freed before TerminateProcess.
2026-07-24 15:49:58 +03:00
Evgeny 73be79d204 chatgui: fix rlottie thread hang on Windows shutdown
Root cause: librlottie RleTaskScheduler creates 32 worker threads on first
lottie_animation_from_data call. These pthreads wait in WaitForMultipleObjects(INFINITE)
and never exit. On MinGW, exit()/pthread_join blocks forever.

Changes:
- messagelist: s_icons moved to file-static; cleanupAnimations() clears them,
  calling lottie_animation_destroy BEFORE static destruction
- mainwindow: ~MainWindow calls MessageList::cleanupAnimations() after node stop
- main: ShutdownSentinel counts threads at exit; if >4 remaining, calls
  ExitProcess(0) to bypass CRT pthread_join hang
- main: if rlottie properly shuts down (<=4 threads), normal return (no ExitProcess)
2026-07-24 14:54:12 +03:00
Evgeny 74c6b0d102 chatgui: add shutdown diagnostics — ~DbManager, ~SoundManager, g_shutdown_sentinel
Three diagnostic points covering the gap between ~MainWindow done and CRT exit:
- DbManager: destroyed — confirms local dtors started after ~MainWindow
- SoundManager: static destructor entered — confirms static destruction phase
- main: static destructors done (g_shutdown_sentinel dtor) — confirms ALL statics done

If process hangs, we know exactly which phase failed.
2026-07-24 14:34:00 +03:00
Evgeny 0d558245ce chatgui: move SoundManager shutdown to ~MainWindow before node cleanup
- SoundManager::shutdown() called explicitly in ~MainWindow (not static destruction)
- Before ma_engine_uninit: DEBUG_INFO diagnostic in timestamped log
- After ma_engine_uninit: DEBUG_INFO diagnostic
- Double-call safe: static destructor hits m_initialized=false, returns immediately
2026-07-24 14:22:28 +03:00
Evgeny fbaf58530f chatgui: rework shutdown — main thread owns cleanup, remove glШбаls
Changes:
- UtunNode::requestStop() — async stop from any thread (m_stop+wakeup)
- UtunNode::finalize() — cleanup in main thread (etcp_router, chat_sync, chat_core, utun_instance, uasync)
- UtunNode::stop() — requestStop + join + finalize (for tray Quit path)
- Worker runLoop: only exits poll loop on m_stop, then emits stopped — no cleanup
- stopped() handler: calls finalize() in main thread, then qApp->quit()
- Tray Quit: calls requestStop(), stopped handler does finalize+quit
- Ctrl-C (Windows): SetConsoleCtrlHandler calls requestStop() via g_ctrl_node
- Ctrl-C (Linux): signal_handler calls requestStop() via g_currentNode
- Removed: g_shutdown, g_signal_ua, utun_node_signal_shutdown globals
2026-07-24 14:14:27 +03:00
Evgeny 4c623e25ce chatgui: add shutdown diagnostics (poll exit reason, cleanup steps, app.exec return) 2026-07-24 13:56:29 +03:00
Evgeny faddbef32a chatgui: add SetConsoleCtrlHandler for reliable Ctrl-C on Windows 2026-07-24 13:51:23 +03:00
Evgeny a7ec45c4af db_sync: replace all sync logs with unified narrative format sync [TBL:NODE]
- Unified format: 'sync [SHORT_TBL:PEER_HI] <-/->  action: key_data'
- Each log line explains what the algorithm is doing and why
- Added batch progress tracking in dump-all and tail SEND_DATA loops
- Track dropped records (duplicates, bad_sigs, parse_fails) in SEND_DATA recv
- Show synced_pos transitions (old->new) in SEND_DATA and SYNC_DONE
- Show all launched syncs in PEER CHECK log
- Convert all silent returns to ERROR logs with [TBL:NODE] context
- Convert old WARN/ERROR formats to new sync [TBL:NODE] format
- Add sync_state reset details on ERROR and timeout paths
2026-07-24 13:23:17 +03:00
Evgeny ce9e58a925 chatgui: add scroll-to-bottom floating button, incremental message refresh via getMessagesSince 2026-07-24 04:07:51 +03:00
Evgeny b6d44bd947 chatgui: don't save scroll position when at bottom — restore to bottom on reopen
When scrollbar is at max, save lastPosMsgId=0 so restoreScrollPosition
falls through to scrollToBottom() instead of restoring a stale mid-scroll pos.
2026-07-24 03:52:05 +03:00
Evgeny 6cafff200b chatgui: add SIGINT/SIGTERM handler (as in utun.c), save scroll pos on every debounce
Signal handler via g_shutdown + uasync_wakeup ensures clean uasync poll exit.
updateReadPosition() now saves both lastReadMsgId and lastPosMsgId on every
scroll stop (300ms debounce), not just when read position changes.
connect(stopped, quit) triggers graceful Qt shutdown after uasync cleanup.
2026-07-24 03:47:15 +03:00
Evgeny 83ca0c65a4 chatgui: fix corrupted channel_id from non-null-terminated binary protocol
QString::fromUtf8(ch_id) read past length-prefixed string, capturing garbage.
Use fromUtf8(ch_id, ch_id_len) — length already available from bridge but was unused.
Messages now appear on refresh and unread badge correctly matches channel.
2026-07-24 03:33:14 +03:00
Evgeny fdc30d1a4e chatgui: synchronous DB write in saveChannelState/updateReadPosition, add shutdown debug logs
Replace gui_bridge_post_uasync_fn (async queue lost on shutdown) with direct
chat_core_save_ui_state (sync SQLite write). SQLite WAL handles concurrent access.
Add DEBUG_DEBUG traces in closeEvent, ~MainWindow, aboutToQuit.
2026-07-24 03:29:37 +03:00
Evgeny 393b7d36c8 chatgui: save scroll/read position on app quit via aboutToQuit
Make saveChannelState() public, connect to QApplication::aboutToQuit so
state is persisted on SIGINT, tray quit, or any other shutdown.
2026-07-24 03:24:54 +03:00
Evgeny 6ef21613c8 chatgui: pass author node_id in MSG_RECEIVED event, skip sound for own messages
Add author_node_id:8 to GUI_EVT_MSG_RECEIVED data format.
Callback now includes uint64_t author parameter.
SoundManager::play('msg_incoming') only when author != myNodeId.
2026-07-24 03:22:10 +03:00
Evgeny 37c5fa5607 chatgui: fix scroll jump on refresh, force debounce, add DEBUG logs
- Same-channel refresh: save scroll pos in memory, restore from memory (no DB race)
- Force m_readDebounce->start() after loadChannel (scrollToBottom may not trigger valueChanged)
- DEBUG_DEBUG logs in updateReadPosition, saveChannelState, onMessageReceived, setChannelUnreadCount
2026-07-24 02:59:15 +03:00
Evgeny 0c4862c66a chatgui: track read position via debounced scroll, only fully visible msgs are read
- Debounce timer (300ms) advances lastReadMsgId only when message is fully in viewport
- Unread badge no longer resets on channel select — only when actual scroll reads msgs
- saveChannelState() uses tracked m_lastReadMsgId instead of viewport bottom
- getChannels() reads lastReadMsgId from ui_state (was reading unused channels column)
2026-07-24 00:30:44 +03:00
Evgeny 216e516192 build: use explicit file list for liblmdb in CMake instead of GLOB
file(GLOB) + regex FILTER didn't work reliably on Windows. Replace with
explicit listing of mdb.c + midl.c (same as autotools).
2026-07-24 00:13:25 +03:00
Evgeny 726a4b8303 Revert unnecessary #ifndef _WIN32 guards in mplay.c — CMakeLists.txt filter handles exclusion 2026-07-24 00:03:03 +03:00
Evgeny e5dd41e5b2 build: exclude LMDB utilities from Windows CMake build, guard POSIX includes in mplay.c
file(GLOB) in libutun/CMakeLists.txt picked up mplay.c, mdb_dump.c and other
standalone LMDB tools that are not library code and fail on Windows. Filter them
out, keep only mdb.c + midl.c.
2026-07-23 23:58:39 +03:00
Evgeny 86d227bffe chatgui: remember last read message, restore scroll position, show unread count badge
Store read/scroll positions per channel via ui_state table (key-value).
Draw red +N badge on channel list items for unread messages.
Fix getMessages() to fetch last N messages (was fetching first N).
2026-07-23 23:47:35 +03:00
Evgeny de14f82048 chatgui: replace manual source lists with file(GLOB) in libutun/CMakeLists.txt
libutun/CMakeLists.txt: 151→84 lines (-67)
UASYNC_SOURCES: file(GLOB /*.c /liblmdb/*.c)
UTUN_COMMON_SOURCES: file(GLOB_RECURSE /*.c) excluding
  lwip_orig/, uip/, transport_layer/BBR/, utun.c
New .c files in src/ or lib/ are now automatically included.
2026-07-23 22:46:48 +03:00
Evgeny cf6108b1f1 chatgui: unify logging — debug_ui.h delegates to debug_config.h
debug_ui.h (50→10 lines): GUI_ERROR/WARN/INFO/DEBUG now delegate to
DEBUG_ERROR/WARN/INFO/DEBUG(DEBUG_CATEGORY_DEBUG, ...) from debug_config.h
Eliminates dual logging output, dual log file configuration.
Removed guiDebugFile() — debug_enable_file_output() already handles it.
Removed debug_ui.h include from utun_node.cpp (unused).
2026-07-23 22:45:26 +03:00
Evgeny 4aede4c6bd chatgui: extract MainWindow constructor into sub-methods
MainWindow (~15 lines): setupUi+setupTray+setupSoundFromConfig+
setupBridgeCallbacks+setupMessaging+setupNode+setupConnects
setupSoundFromConfig(): sound config parsing + loading
setupBridgeCallbacks(): 7 gui_bridge callback registrations
setupConnects(): 5 Qt signal connections
2026-07-23 22:44:32 +03:00
Evgeny 6c59ed43b2 chatgui: move crypto from MainWindow to transport layer
chat_channel.c: new chat_core_create_channel_auto(name) — generates
X25519/Ed25519 keys, random channel_id, Ed25519 signature, creates channel.
chat_core_create_channel_auto_trampoline for gui_bridge_post_uasync_fn.

mainwindow.cpp: onCreateGroupRequested() reduced from 100 to 15 lines.
Removed openssl/evp.h and openssl/rand.h includes from UI code.
2026-07-23 22:43:13 +03:00