Commit Graph
5138 Commits
Author SHA1 Message Date
Evgeny a4ae1c6b41 fix: RMS mic level, 25ms timer, speaker test, overlay recording indicator
- AudioRecorder: peak replaced with RMS (sqrt mean of squares)
- AudioDeviceSettings: level meter timer 100ms -> 25ms
- SoundManager: playRawPcm uses ma_audio_buffer_ref instead of ma_decoder (fixes speaker test)
- InputBar: recording overlay positioned over text input, no layout shift
- messagelist: removed old recording indicator widget
2026-07-26 21:27:57 +03:00
Evgeny 850a260aac fix: voice message display, playback, recording UI, audio settings
- messagelist: parse content_type from JSON when DB column is empty
- messagelist: recording indicator (red dot + timer + cancel button)
- messagedelegate: editorEvent for play/pause toggle + progress bar
- messagedelegate: VoicePlayState tracking with QTimer
- InputBar: proper recordingContext (mediaDir + channelId)
- DbManager: dbPath() for media directory resolution
- AudioRecorder: peakLevel() for mic level meter
- VoiceEncoder: codec quality presets (Low/Standard/High)
- audiodevicesettingspage: Default device option first
- audiodevicesettingspage: mic level meter + test microphone
- audiodevicesettingspage: test speaker button
- audiodevicesettingspage: codec preset combo (Low/Standard/High)
- mainwindow: load opus_codec_preset from ui_state on startup
2026-07-26 21:19:29 +03:00
Evgeny 4fde0b0325 feat: integrate Opus codec into lib/libopus + voice messages in chatgui
- Add lib/libopus/ (opus v1.6.1 embedded source: CELT 18 .c, SILK 77 .c, SILK float 28 .c, OPUS core 14 .c)
- Add lib/opus_codec.h/.c (wrapper: encoder, decoder, raw PCM int16)
- Add tests/test_opus_codec.c (7 tests: silence, sine, compression, PLC, null, defaults, multi-frame)
- chatgui: AudioRecorder (miniaudio capture, 48kHz mono)
- chatgui: VoiceEncoder (PCM→Opus file with custom container)
- chatgui: VoicePlayer (Opus→PCM playback via SoundManager)
- chatgui: PTT button in InputBar, voice message send/receive in MessageList
- chatgui: AudioDeviceSettingsPage (device selection, persisted in ui_state)
- chatgui: MessageDelegate voice message rendering (play button + duration)
- Update autotools: configure.ac, Makefile.am, src/Makefile.am, tests/Makefile.am
- Update CMake: chatgui CMakeLists.txt, libutun CMakeLists.txt (link libopus_internal.a)
2026-07-26 20:34:38 +03:00
Evgeny 4a23593020 member_sync: add merkle_sync_broadcast relay to other SYNCED sessions 2026-07-26 18:44:45 +03:00
Evgeny ef1e064bdc merkle_sync: broadcast relay for star topology + all 6 test stages pass
- Replace active/synced with sess_state (SESS_SYNCING/SESS_SYNCED)
- Add merkle_sync_broadcast() API for relaying changes to SYNCED peers
- apply_items callback now receives from_peer parameter
- _handle_hashes: reset pending_count on session reuse (overwrite fix)
- _handle_batch: send broadcast to synced sessions on new items
- Test Stage 5: sequential B->A + C->A with relay (no 3rd sync needed)
- Test Stage 6: cancel + start_overwrite pass
- Fix _wait_for: remove i_phase global timeout dependency
2026-07-26 18:20:10 +03:00
Evgeny b9bde23d51 Stage 5 WIP: sequential syncs for 3-instance test, increased timeouts 2026-07-26 17:53:43 +03:00
Evgeny a1ecab997e merkle_sync: fix 4 protocol bugs + add test suite (Stages 1-4)
- g_merkle singleton → per-instance msync (utun_instance.h)
- level_prefix: off-by-one shift (63→64)
- _handle_hashes: differs |= for shared buckets with different hashes
- _handle_batch: sub_pl double-level-offset (next_lvl→lvl)
- pending[] array replaces pending_requests counter
- member_sync: mask_shift 63→64 alignment
- test_merkle_sync.c: prefix arithmetic, tree building, 2-instance integration, randomized 50-iter sync
2026-07-26 17:42:27 +03:00
Evgeny 0e11d858e8 chatgui: fix all animations showing the same TGS (rlottie model cache key collision)
lottie_animation_from_data uses 'key' as a cache key for parsed models.
All LottieIcon instances were created with key="", causing rlottie's
model cache to return the first loaded animation for all subsequent
requests. Only visible on Windows where rlottie cache is enabled by
default.

Fix: pass unique animPath as key to each LottieIcon constructor.
Also replaced fprintf(stderr) diag with GUI_INFO logging via
AnimTimer::logRegisteredIcons() in debug_ui.h.
2026-07-26 15:18:59 +03:00
Evgeny 49da899964 chatgui: channel sorting by name or last message time with preview
- Add last_msg_at column to channels table
- Update last_msg_at on every message insert (send/receive)
- Parameterize getChannels() with ChannelSortMode enum (Alphabetical/Recent)
- Add getChannelLastMessage() for preview text in channel list
- Add sorting combo to Profile settings page (stored in ui_state)
- Reload channels on message receive when sort is recent
2026-07-26 11:08:59 +03:00
Evgeny 332df381d1 chatgui: propagate local nick changes to message authors via MsgAuthorNodeIdRole + reloadLocalNicks 2026-07-26 10:11:31 +03:00
Evgeny 22db84816e chatgui: add local_nick TEXT to peers table DDL, remove ALTER TABLE hacks 2026-07-26 09:45:00 +03:00
Evgeny 86843693c9 chatgui: ensure local_nick column exists before SELECT in getChannelMembers 2026-07-26 09:43:39 +03:00
Evgeny df3fc04523 chatgui: RenameDialog — quick rename via context menu, separate mini dialog 2026-07-26 09:33:31 +03:00
Evgeny 85bdc00aaf chatgui: local nicknames per channel member — edit via MemberPropsDialog, override display everywhere 2026-07-26 09:19:31 +03:00
Evgeny 373a2e4687 chatgui: member detail panel redesign — compact format with relative time, colored online dot, 5s auto-refresh 2026-07-26 09:09:21 +03:00
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