Commit Graph
794 Commits
Author SHA1 Message Date
Evgeny 4ec930c8f0 chatgui: fix dual selection highlight and missing online count
- channellist.cpp: selectionChanged guard now checks currentIndex().row()
  is within model->rowCount() to avoid re-selecting stale index after
  model clear, which caused both channels to stay blue when switching.
- chat_sync.c: cs_refresh_channels now posts CHANNEL_PEERS_ONLINE
  for all channels after loading, fixing online count showing only
  on the last connected group.
2026-07-23 21:25:39 +03:00
Evgeny cbd9536a28 chatgui: fix invite link and Russian channel name encoding
- chat_sync.c: after invite trampoline, check if connection to invite
  node is already UP and trigger cs_on_conn_up to send CHANNEL_INFO_REQ.
  Fixes invite not completing when connection is reused (Fix 1 side effect).
- mainwindow.cpp: use name.toUtf8().constData() instead of qPrintable()
  to preserve UTF-8 encoding on Windows (Russian channel names).
2026-07-23 21:07:41 +03:00
Evgeny 3e95cf5ca6 fix: dialog hangs on join success + remove per-packet spam logs
- chat_sync.c: move pending_invite clear from INFO_RESP to WELCOME,
  post GUI_EVT_CONNECT_RESULT on invite success in cs_handle_welcome
- etcp_connections.c: NORM_DECRYPT_TRY/CRYPTO_DECRYPT_OK DEBUG_DEBUG->TRACE
- secure_channel.c: ENCRYPT/DECRYPT DEBUG_DEBUG->TRACE
2026-07-23 16:36:40 +03:00
Evgeny 196c2896d3 debug: sochet count after instance_init (категория debug, видно при текущем конфиге) 2026-07-23 14:17:58 +03:00
Evgeny 3e0a4e0eb1 fix: замена malloc на u_strdup в channelSelected — u_free падал на чужой памяти 2026-07-23 13:12:04 +03:00
Evgeny 0e324cf36d chat_core: connect_channel API — запуск topo_group_connect_init при выборе канала из GUI, убрано дублирование создания групп в utun_node 2026-07-23 12:51:45 +03:00
Evgeny be258eea4d fix: remove stale peers_* CREATE TABLE from chat_core, drop ORDER BY node_RTT
chat_core_ensure_channel_ready() had a duplicate CREATE TABLE peers_*
with OLD schema (no node_RTT, node_type, connected). Since it was called
from 4 places WITHOUT topo_node_sqlite_channel_put() first, the old
schema was created first, and IF NOT EXISTS in the new DDL was a no-op.

Removed the entire old block. Only topo_node_sqlite_channel_put() now
creates peers_* tables with the full schema.

Also removed ORDER BY p.node_RTT from get_public_peers/get_local_peers —
ordering not needed for sequential connect attempts.
2026-07-23 00:24:16 +03:00
Evgeny 6edd40d141 topo_group_connect: авто-подключение CHAT-групп + conn_mgr_connect_from_invite + замена chat_conn_mgr в chatgui
Добавлено:
- conn_mgr_connect_from_invite() — подключение к новому узлу по invite-данным
  (INIT → INVITE_INFO_REQ/RESP → проверка членства в группе → сохранение в БД)
- topo_group_connect.c — авто-подключение при старте CHAT-группы:
  Phase 1: одновременный connect всех connected=1 пиров, таймаут, отмена незавершённых
  Phase 2: последовательный перебор публичных адресов до первого успеха
- Счётчик active_conn_count с проверкой nodeinfo-путей (UP/DOWN)
- restart() при phase=DONE и count==0

БД:
- connected INTEGER NOT NULL DEFAULT 0 в peers_<ch> + ALTER TABLE для существующих
- topo_node_sqlite_set_connected / get_connected_peers / get_public_peers

Chatgui:
- Включён topo_group (убран utun_instance_set_topo_group_enabled(0))
- Создание TOPO_GROUP_TYPE_CHAT при channel_ready и при старте
- Invite connect через conn_mgr_connect_from_invite
- Удалён chat_conn_mgr (из сборки) + весь старый auto-connect код
2026-07-22 22:48:12 +03:00
Evgeny 4215349349 topo_recovery: каскадное восстановление узлов с группировкой по next_hop
При разрыве ETCP-соединения модуль собирает каскадно отвалившиеся узлы:
- add_node из hop_list вычисляет next_hop относительно failed_peer,
  группирует узлы в отдельные recovery-контексты (direct/indirect списки)
- start запускает асинхронный перебор для каждой группы параллельно
- is_next_hop-узел пробуется первым с приоритетом по мин. RTT
- таймаут 2с на попытку, conn_mgr_cancel_callback при отмене
- отмена: topo_group_new_conn (on_up) находит узел в любом ctx -> ctx целиком
- завершение: оба списка пусты -> освобождение ctx
2026-07-22 19:01:55 +03:00
Evgeny 852ce401e7 Добавлен group_id в etcp_router и topo_group, удалён msg_transport
- etcp_router: SVC_ROUTE_HDR (+8B), ETCP_ROUTER_CONN/TRANSIT_QUEUE хеши расширены под group_id
- Все caller'ы (proxy, routing, conn_mgr, nat, chatgui, tests) обновлены
- topo_group: глобальный реестр TOPO_NODE по node_id, ref_count=0 при создании
- BGP-обмен активируется для всех групп (а не только дефолтной)
- Протокол: group_id добавлен в WITHDRAW/TABLE_REQ/TABLE_COMPLETE/ERR_GROUP_MISMATCH
- Per-connection коллбэки заменены на instance-level conn_status
- msg_transport полностью удалён из проекта
57/57 тестов
2026-07-22 15:51:03 +03:00
Evgeny 5265783164 fix: self node online=0 after chat_core_init refactor — add topo_node_sqlite_node_set_online(self, 1) 2026-07-22 13:54:36 +03:00
Evgeny e2d9879636 refactor: remove direct nodes table writes from chat_core/conn_mgr, use topo_node_sqlite API
- chat_core_init: replace INSERT INTO nodes with topo_node_sqlite_node_update_verified, remove redundant topo_node_sqlite_init call
- chat_core_update_my_name: replace UPDATE nodes with topo_node_sqlite_node_update_verified
- chat_conn_mgr_connect_from_invite: simplify invite node insert (x25519 only, no ed25519)
- topo_node_sqlite: add detailed column comments to peers table DDL (both server and chatgui)
- chat_core: add detailed column comments to peers table CREATE TABLE
2026-07-22 13:38:17 +03:00
Evgeny 7aa4a34f35 fix chatgui: members showing offline after JOIN — always refresh channel cache before posting online count 2026-07-22 12:19:59 +03:00
Evgeny a7346c25e3 fix chatgui: members not showing (schema mismatch) and username showing JSON instead of name
- topo_node_sqlite_member_put: remove joined_at column from INSERT (not in server schema, duplicates join_ts)
- chat_core: rename peers table column name→userinfo to match server schema + add ALTER TABLE migration
- chat_sync: remove 3 redundant INSERT INTO nodes that wrote raw JSON userinfo into nodes.name, overwriting correct plain name from topo_node_sqlite_node_update_verified
2026-07-22 12:03:57 +03:00
Evgeny df809f251c ntp: use NTP-corrected time everywhere instead of unixepoch()/gettimeofday
- db_sync_next_timestamp(): ntp_time_get_us() via si->db_sync->inst
- topo_node_sqlite_node_put: +time_t now_sec param, replace unixepoch()
- topo_node_sqlite_node_update_verified: +time_t created_at param
- topo_node_sqlite_member_put: joined_at = join_ts (already NTP-corrected)
- All INSERTs (nodes, local_identity, accounts, peers):
  replace DEFAULT(unixepoch()) with explicit ntp_time_get_seconds()
- ON CONFLICT DO UPDATE: created_at = COALESCE(nodes.created_at, excluded.created_at)
- Updated callers: topo_group.c, chat_sync.c, chat_conn_mgr.c, chat_core.c
2026-07-22 11:39:10 +03:00
Evgeny fab1c77cfb chatgui: remove unused addServer/addClient/removeServer/removeClient 2026-07-22 10:22:37 +03:00
Evgeny 6574c58257 chatgui: unify config update logic, fix node_id derivation, fix test
- config_updater.{h,cpp}: single implementation — config_update_in_lines
  for batch updates + config_update_option for file-level. REPLACE/APPEND
  modes, section auto-creation
- node_config.cpp: generateIdentity() now derives node_id via
  SHA256(pubkey) (like sc_derive_node_id_from_pubkey) instead of random.
  save() uses config_update_in_lines for line-level update when file
  exists, saveFull() only for new file and addServer/addClient.
  Removed duplicate findSectionBounds/updateOptionInSection/configUpdateOption
- test_config_updater.cpp: Q_ASSERT replaced with VERIFY macro — Q_ASSERT
  in Release mode does not evaluate the expression, causing false positives.
  Test now works in both Debug and Release
2026-07-22 10:13:40 +03:00
Evgeny ab252a0984 chatgui: include platform_compat.h for htole64 on Windows 2026-07-22 09:23:35 +03:00
Evgeny 090acc1f00 etc/rtt: UPSERT node_update_verified; gui: account delegate (rtt+nat subline), context menu member props (admin/supernode), cleanOrphanedPeers, refreshRtt timer 2s 2026-07-22 01:15:33 +03:00
Evgeny fcf3fb7f51 refactor: move transport (etcp/stcp/normalizer) to transport_layer/, routing (bgp/pings/topo*) to routing_layer/ 2026-07-21 20:25:41 +03:00
Evgeny 3dda701c67 schema: rm is_dm, rename name→userinfo (json_flat), fix join_msg format
- Remove is_dm column from channels table (dm detection by member count)
- Rename member name column to userinfo — extensible json_flat format
- Add json_flat.c/h library for compact JSON serialization
- Fix join_sig message format: use ch_x25519+ch_ed25519 instead of channel_id string
- Remove name from join_msg body (now in userinfo via json_flat)
- Update chat_core, chat_sync, member_sync, db_manager to new format
- Add topo_strategy.txt — архитектурные заметки по топологии
2026-07-21 00:11:50 +03:00
Evgeny 88d51349ea statuspage: компактный блок часов, offset в секундах
- Шрифт часов 20 (был 22), bold оставлен
- Убраны зазоры: padding 10px→1px, margins 12,8→4,0, spacing 8→2
- Offset в NTP-статусе: микросекунды → секунды (114.8 s)
- Убран зазор (пустая строка) между NTP и Connections
2026-07-20 01:31:49 +03:00
Evgeny 7a5df3e196 etcp: add node_changed callback chain + chatgui subscription
- etcp.h: add node_changed_cbks field to ETCP_CONN
- etcp_api.h/c: add etcp_conn_node_changed() + add/remove_node_changed_cbk
- etcp_connections.c: fire node_changed callbacks on pubkey mismatch
  (with DEBUG_WARN(GENERAL) logging source addr, peer_id, old/new pubkey)
- etcp.c: cleanup node_changed_cbks on connection close
- chat_conn_mgr.c: subscribe to node_changed — clear DB addresses,
  reset in-memory cache, close connections (deferred for current conn),
  post GUI_EVT_NODE_CHANGED
- gui_bridge.h: GUI_EVT_NODE_CHANGED=11
- gui_bridge_impl.cpp: handle GUI_EVT_NODE_CHANGED
2026-07-19 22:09:23 +03:00
Evgeny 1b21ee9d73 chatgui: live NTP-corrected clock (HH:mm:ss) on Status page with per-second sync 2026-07-19 20:38:22 +03:00
Evgeny a7d842440c chatgui: split chat_core into chat_conn_mgr — connection manager with rotation, max_parallel slots, background ping, per-connection DOWN callback
- chat_conn_mgr.c/h: new connection manager (1 per instance, global in g_cc)
  - cm_rotation() — single rotation method: random addr pick, INIT, retry
  - 10 parallel slots per node (CM_MAX_PARALLEL), evict worst RTT on excess
  - DEAD slot reuse before close — close only when replacement ready
  - per-connection DOWN callback via etcp_conn_add_down_cbk
  - background ping cycle: random node→random addr RTT measurement
- chat_core.c: added g_cc.conn_mgr field, init/destroy/getter
- chat_sync.c: migrate to new API, add_node() at WELCOME/JOIN/PEER_UPSERT
- Removed old ca_state/ca_ctx/ca_* single-flight code
2026-07-19 19:00:29 +03:00
Evgeny 98bfb9dcd2 chatgui: per-event sound settings with DB persistence
- Sound files loaded from filesystem (sound_dir in INI config, absolute or relative)
- Per-event enable/disable + volume stored in DB (ui_state table)
- SoundManager: setEvent(), effective volume = master * per-event
- SoundSettingsPage UI: 4 event rows (checkbox + slider)
- chat_core_save_ui_state() for async DB writes via uasync thread
- DbManager::getUiStateInt() for reading settings from GUI thread
- Default sounds copied to sounds/ dir next to DB, config entries written
2026-07-19 15:17:52 +03:00
Evgeny 1593079da8 chatgui: fix sound_manager use-after-free crash on Windows
- Keep mp3Data + ma_decoder alive for sound lifetime (was freed before audio thread)
- Remove MA_SOUND_FLAG_DECODE — stream from decoder instead of pre-decoding
- Shutdown in reverse order: sound → decoder → mp3Data
2026-07-19 14:58:34 +03:00
Evgeny c2ad2e78c3 chatgui: add sound playback via miniaudio (MP3 notification sounds)
- SoundManager singleton wraps ma_engine + ma_sound (non-blocking, background thread)
- MP3 files embedded in QRC, decoded to PCM at startup with MA_SOUND_FLAG_DECODE
- miniaudio.h (MIT) in lib/, IMPLEMENTATION in separate miniaudio_impl.c
- Sound settings page in SettingsDialog: enable/disable, volume slider (0-100%)
- Config keys [gui] sound_enabled, sound_volume
- Incoming messages trigger msg_incoming.mp3 sound
2026-07-19 14:46:21 +03:00
Evgeny f6f7e12192 refactor: demote high-frequency debug logs (raw_recv/dispatch→TRACE, normalizer→DEBUG), NTP drift→WARN 2026-07-19 13:53:27 +03:00
Evgeny 2e7c32c893 fix(db): use INSERT ... ON CONFLICT instead of INSERT OR REPLACE for nodes table
INSERT OR REPLACE deletes the old row and inserts a new one,
resetting unspecified columns (online, update_ts) to DEFAULT 0.
This was wiping online=1 set by cs_on_peer_status_changed/member_sync_set_online.

Replaced 5 INSERT OR REPLACE INTO nodes with INSERT INTO ... ON CONFLICT
DO UPDATE SET — only updates the specified columns, preserving online status.

Files:
- chat_core.c:638 (invite flow)
- chat_sync.c:1045 (CHANNEL_INFO_RESP), 1193 (JOIN), 1449 (PEER_UPSERT)
- topo_node_sqlite.c:121 (BGP node_put)
2026-07-19 11:16:26 +03:00
Evgeny cf46a59d3a fix(chatgui): replace qDebug with DEBUG_INFO for online trace logs 2026-07-19 11:04:35 +03:00
Evgeny ac0d1c18ed debug(chatgui): add online status trace across full chain
- cs_is_peer_online: log found/init/links/online
- cs_on_peer_status_changed: log channel_count + found_in_channel
- cs_handle_welcome/cs_handle_channel_join: log before cs_post_channel_online
- MainWindow::onChannelPeersOnline: log cid+online
- ChannelList::setChannelPeersOnline: log search/rows, each row cid+match, SET or NOT FOUND
- ChannelList::loadChannels: log each added row cid+name
2026-07-19 10:58:25 +03:00
Evgeny 9de16be012 fix(chatgui): remove duplicate loadChannels after JoinDialog close, remove 800ms delay
- showJoinDialog: don't call loadChannels after dialog close — channel already in model via CHANNEL_UPDATED event, online badge via CHANNEL_PEERS_ONLINE. Duplicate loadChannels was resetting the peer online count.
- onConnectResult: remove 800ms QTimer — dialog closes immediately. Channel data arrives independently through the event pipeline.
2026-07-19 10:50:25 +03:00
Evgeny 3a7b359f87 fix(chat_sync): online status for joiner on inviter side not sent to GUI/peers
- cs_handle_channel_join: call cs_post_channel_online immediately after adding joiner
- member_sync_start with _on_invite_sync_done callback: on MT_OK push online=1 via merkle_sync_push_update
- DEBUG per-peer online status in cs_post_channel_online
2026-07-19 09:30:51 +03:00
Evgeny e3286d409f chatgui: кнопка + для invite в каналах, автокопирование ссылки, автоподключение из буфера
- Замена контекстного меню 'Пригласить' на кнопку + (18x18) справа снизу каждого канала с hover-эффектом
- InviteDialog: авто-копирование ссылки в буфер (Clipboard + Selection) при открытии
- JoinDialog: параметр autoJoinLink — если в буфере валидная utun:// ссылка, диалог сразу стартует подключение
2026-07-19 09:05:55 +03:00
Evgeny 501b636d19 topo_group: disable in chatgui; fix NAT detection for matching addresses
- Add utun_instance_set_topo_group_enabled() flag (default=1, chatgui sets 0)
- Move nat_detection create/destroy from topo_group.c to utun_instance.c (unconditional)
- NAT detection: simplify third_node search (any connected node)
- NAT detection: allow NULL topo_groups in receive_cbk and handlers
- NAT detection: handle NAT_INFO without topo_group (update socket directly)
- route_ping: make TOPO_GROUP optional in send_req_addr/handle_req
- topo_node: when NAT verified and address matches interface, set entry type to NAT instead of INTERFACE + socket_id|1
- topo_node: detect nat_type change in changed computation for rebuild
- test_nat_detection: fix socket_id check (|1 for NAT entries)
- chatgui: call utun_instance_set_topo_group_enabled(0)
2026-07-19 08:33:33 +03:00
Evgeny 208a0c8ae8 fix(chat_sync): peer online status not updated in invite flow
- cs_on_conn_up: call cs_on_peer_status_changed(peer,1) before return
  in invite path (was skipped, leaving inviter at online=0 in DB)
- cs_handle_welcome: remove unconditional set_online(0) — online
  status is managed by conn_up/conn_down, not by WELCOME
- cs_handle_welcome: add cs_post_channel_online() after WELCOME
  to send PEERS_ONLINE to GUI when channel is fully loaded
- cs_post_channel_online: add DEBUG log for PEERS_ONLINE event
- db_sync peer_check: suppress spam log when no peers connected
2026-07-19 07:54:06 +03:00
Evgeny 4df7195a58 debug: add ADDR_SYNC logs for BGP node_put DELETE and member_sync recv ac 2026-07-19 00:09:46 +03:00
Evgeny 586d46f1e6 fix: WELCOME wire format — flags+update_sig parsing, peer_needed gap, invalid join_sig skip 2026-07-18 23:53:04 +03:00
Evgeny 39a376e255 fix: BGP и чат больше не затирают адреса друг друга в node_addresses
- BGP DELETE: +AND socket_id != 0 — не трогает чат-адреса (invite/JOIN/WELCOME)
- Чат invite DELETE: +AND socket_id=0 — не трогает BGP-адреса
2026-07-18 23:23:14 +03:00
Evgeny 70930b784f chatgui: fix — локальные адреса не записывались (g_cc.initialized до sync_my_addresses) + таймаут коллбэк 12→20 байт 2026-07-18 22:18:01 +03:00
Evgeny 57f861f360 chatgui: диагностические логи ADDR_SYNC во всех точках записи/удаления адресов в БД
- chat_core_sync_my_addresses: DELETE + INSERT с подсчётом строк, CHECK verify
- chat_core_connect_from_invite: DELETE + INSERT с IP:port
- member_sync_put: DELETE + INSERT с IP:port, warn если addrs_data=NULL
- cs_handle_channel_info_resp: адрес инвайтера из ETCP link
- cs_handle_channel_join: адреса джойнера
- cs_handle_peer_upsert: адреса пира
- cs_handle_welcome: адреса из WELCOME

Все логи с префиксом [ADDR_SYNC] в DEBUG_CATEGORY_DEBUG
2026-07-18 21:46:46 +03:00
Evgeny 0b385dca50 chatgui: обновление статуса/адресов узлов через чат-протокол
- merkle_sync: synced-флаг в сессии, MSG_ITEM_UPDATE(0x04), push_update() — рассылка лёгких дельт (online-статус) всем synced-соседям
- member_sync: apply_update в ops, node_updated_cb для GUI-нотификации внешних обновлений
- chat_sync: cs_on_peer_status_changed() — единая функция: БД + GUI + push_update + throttled member_sync_start (1/сек)
- cs_on_conn_down: исправлено — теперь сбрасывает nodes.online=0
- flush при destroy
2026-07-18 21:28:59 +03:00
Evgeny 20f5e6c953 sqlite: add cache_size/mmap_size/temp_store PRAGMAs to db_sync and topo_group — 159x insert speedup, fix test_chat_sync_stress timeout 2026-07-18 20:16:24 +03:00
Evgeny 0e0ad9316a fix race condition: DB_READY lost when utun thread starts before gui_bridge_init
- mainwindow.cpp: swap setupMessaging() before setupNode() so g_receiver is created first
- gui_bridge_impl.cpp: add DEBUG_WARN when gui_bridge_post drops event due to NULL g_receiver
2026-07-18 18:08:09 +03:00
Evgeny 29e2527b6b consolidate 3 SQLite connections into 1 shared handle
- utun_node.cpp: open topo_sqlite_db with FULLMUTEX + all PRAGMAs (WAL, FK, NORMAL sync, checkpoint)
- db_sync.c: reuse inst->topo_sqlite_db if available (shared_db flag)
- chat_core.c: reuse inst->topo_sqlite_db if available (shared_db flag)
- db_sync_destroy/chat_core_destroy: skip close on shared handle
- Only topo_groups_destroy closes the shared handle
- Fallback: each module opens own connection if topo_sqlite_db is NULL
2026-07-18 17:33:29 +03:00
Evgeny 853297290f chatgui: fix NodesPage truncated Node ID + add DB diagnostics
- NodesPage: show full 64-bit Node ID (hex16) instead of truncated 4 hex chars
- NodesPage: show diagnostic when DB handle is NULL (was silent return)
- DatabaseSettingsPage: show 'Database not connected' when DB handle is NULL
- DatabaseSettingsPage: add refreshStatus() called on tab select
- SettingsDialog: refresh Database tab on category change
2026-07-18 17:04:50 +03:00
Evgeny 93665c50f0 etcp: remove dead set_*_cbk functions, use add/remove only 2026-07-18 16:52:43 +03:00
Evgeny ef1922327a rename ready_cbks → init_cbks (connection init, not fully ready)
ready_cbks/etcp_conn_set_ready_cbk/add_ready/remove_ready → init_cbks/..._init_cbk
ca_ready_cb → ca_init_cb
cm_direct_ready_cb → cm_direct_init_cb
cm_reverse_ready_cb → cm_reverse_init_cb
ntp_node_on_conn_ready → ntp_node_on_conn_init
connect_ready_cb → connect_init_cb

init accurately describes when conn->initialized=1, before keepalives establish UP.
Also fire etcp_fire_conn_status INIT at this point instead of create time.
2026-07-18 16:38:24 +03:00
Evgeny ef3d7c3f37 chat_core: call ensure_channel_ready on invite — create msg/peers tables + register in db_sync
Without this, invite creates the channel in SQLite but db_sync never
knows about it, so peer sync fails with 'instance NOT FOUND'.
2026-07-18 16:14:53 +03:00