chat: invite-ссылки с выбором достижимого узла + tcp_io фикс half-close FIN

- Общий модуль invite_build: сборка utun://-ссылок, авто-выбор лучшего
  достижимого узла, список кандидатов (вынесено из android jni_bridge)
- chatgui: диалог invite с выбором узла (комбобокс), события INVITE_CANDIDATES /
  INVITE_LINK_READY через gui_bridge
- headless/chatcli: invite <ch_id> [node_id], команда invite_nodes
- tcp_io: error_cb отличает грациозный EPOLLHUP (SO_ERROR==0) от реальной ошибки —
  при приостановленном чтении FIN не роняет недослейные данные (фикс flaky half-close)
- run_test.sh: half-close echo на выделенном порту 19190 + отдельный DNAT (был недостижим)
This commit is contained in:
evgeny committed 2026-09-07 13:59:15 +03:00
1 parent a17a85a383
commit 1345f44e10
23 files changed
+872 -539

No files matched your search

+1 -18
View File
@@ -430,24 +430,7 @@ void MainWindow::onTrayActivated(QSystemTrayIcon::ActivationReason reason) {
void MainWindow::showShareInviteDialog(const QString& channelId) {
if (!m_db || !m_db->isOpen()) return;
QByteArray pubkey;
if (m_node && m_node->isRunning())
pubkey = QByteArray::fromHex(m_node->pubKeyHex().toLatin1());
if (pubkey.size() != 32) {
QMessageBox::warning(this, "Error", "Failed to get node public key.");
return;
}
QList<NodeAddr> addrs = m_node->getInviteAddresses(m_db);
QString link = encodeInviteLink(channelId.toULongLong(), pubkey, addrs);
if (link.isEmpty()) {
QMessageBox::warning(this, "Error", "Failed to create invite link.");
return;
}
ShareInviteDialog dlg(link, this);
ShareInviteDialog dlg(channelId, m_db, this);
dlg.exec();
}