Кросс-платформенное шифрование фото/аватаров, профиль собеседника, вложения в чате

This commit is contained in:
2026-03-16 05:57:07 +05:00
parent dd4642f251
commit 624038915d
43 changed files with 5212 additions and 656 deletions

View File

@@ -104,10 +104,50 @@ final class ProtocolManager: @unchecked Sendable {
}
}
/// Immediately reconnect after returning from background, bypassing backoff.
/// Verify connection health after returning from background.
/// If connection appears alive, sends a WebSocket ping to confirm.
/// If ping fails or times out (2s), forces immediate reconnection.
func reconnectIfNeeded() {
guard savedPublicKey != nil, savedPrivateHash != nil else { return }
if connectionState == .authenticated || connectionState == .handshaking { return }
// Don't interrupt active handshake
if connectionState == .handshaking { return }
if connectionState == .authenticated && client.isConnected {
// Connection looks alive verify with ping (2s timeout)
Self.logger.info("Verifying connection with ping...")
let pingTimeoutTask = Task { [weak self] in
try? await Task.sleep(nanoseconds: 2_000_000_000)
guard !Task.isCancelled, let self else { return }
Self.logger.info("Ping timeout — connection dead, force reconnecting")
self.handshakeComplete = false
self.heartbeatTask?.cancel()
Task { @MainActor in
self.connectionState = .connecting
}
self.client.forceReconnect()
}
client.sendPing { [weak self] error in
pingTimeoutTask.cancel()
guard let self else { return }
if let error {
Self.logger.info("Ping failed: \(error.localizedDescription) — force reconnecting")
self.handshakeComplete = false
self.heartbeatTask?.cancel()
Task { @MainActor in
self.connectionState = .connecting
}
self.client.forceReconnect()
} else {
Self.logger.info("Ping succeeded — connection alive")
}
}
return
}
// Not authenticated or not connected force reconnect immediately
Self.logger.info("Force reconnect from foreground")
connectionState = .connecting
client.forceReconnect()