Исправление аватарки на экране разблокировки, плавная анимация инпута, онлайн-статус по входящим сообщениям, push-навигация в чат, оптимизация debug-логов
This commit is contained in:
@@ -57,8 +57,10 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
private var heartbeatTask: Task<Void, Never>?
|
||||
private var handshakeTimeoutTask: Task<Void, Never>?
|
||||
private let searchHandlersLock = NSLock()
|
||||
private let resultHandlersLock = NSLock()
|
||||
private let packetQueueLock = NSLock()
|
||||
private var searchResultHandlers: [UUID: (PacketSearch) -> Void] = [:]
|
||||
private var resultHandlers: [UUID: (PacketResult) -> Void] = [:]
|
||||
|
||||
// Saved credentials for auto-reconnect
|
||||
private var savedPublicKey: String?
|
||||
@@ -98,6 +100,15 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
savedPrivateHash = nil
|
||||
}
|
||||
|
||||
/// Immediately reconnect after returning from background, bypassing backoff.
|
||||
func reconnectIfNeeded() {
|
||||
guard savedPublicKey != nil, savedPrivateHash != nil else { return }
|
||||
if connectionState == .authenticated || connectionState == .handshaking { return }
|
||||
Self.logger.info("Force reconnect from foreground")
|
||||
connectionState = .connecting
|
||||
client.forceReconnect()
|
||||
}
|
||||
|
||||
// MARK: - Sending
|
||||
|
||||
func sendPacket(_ packet: any Packet) {
|
||||
@@ -128,6 +139,24 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
searchHandlersLock.unlock()
|
||||
}
|
||||
|
||||
// MARK: - Result Handlers (Android parity: waitPacket(0x02))
|
||||
|
||||
/// Register a one-shot handler for PacketResult (0x02).
|
||||
@discardableResult
|
||||
func addResultHandler(_ handler: @escaping (PacketResult) -> Void) -> UUID {
|
||||
let id = UUID()
|
||||
resultHandlersLock.lock()
|
||||
resultHandlers[id] = handler
|
||||
resultHandlersLock.unlock()
|
||||
return id
|
||||
}
|
||||
|
||||
func removeResultHandler(_ id: UUID) {
|
||||
resultHandlersLock.lock()
|
||||
resultHandlers.removeValue(forKey: id)
|
||||
resultHandlersLock.unlock()
|
||||
}
|
||||
|
||||
// MARK: - Private Setup
|
||||
|
||||
private func setupClientCallbacks() {
|
||||
@@ -173,7 +202,7 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
}
|
||||
|
||||
let device = HandshakeDevice(
|
||||
deviceId: UIDevice.current.identifierForVendor?.uuidString ?? "unknown",
|
||||
deviceId: DeviceIdentityManager.shared.currentDeviceId(),
|
||||
deviceName: UIDevice.current.name,
|
||||
deviceOs: "iOS \(UIDevice.current.systemVersion)"
|
||||
)
|
||||
@@ -184,7 +213,7 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
protocolVersion: 1,
|
||||
heartbeatInterval: 15,
|
||||
device: device,
|
||||
handshakeState: .completed
|
||||
handshakeState: .needDeviceVerification
|
||||
)
|
||||
|
||||
sendPacketDirect(handshake)
|
||||
@@ -238,7 +267,8 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
}
|
||||
case 0x02:
|
||||
if let p = packet as? PacketResult {
|
||||
let _ = ResultCode(rawValue: p.resultCode)
|
||||
Self.logger.info("📥 PacketResult: code=\(p.resultCode)")
|
||||
notifyResultHandlers(p)
|
||||
}
|
||||
case 0x03:
|
||||
if let p = packet as? PacketSearch {
|
||||
@@ -293,6 +323,18 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
private func notifyResultHandlers(_ packet: PacketResult) {
|
||||
resultHandlersLock.lock()
|
||||
let handlers = resultHandlers
|
||||
// One-shot: clear all handlers after dispatch (Android parity)
|
||||
resultHandlers.removeAll()
|
||||
resultHandlersLock.unlock()
|
||||
|
||||
for (_, handler) in handlers {
|
||||
handler(packet)
|
||||
}
|
||||
}
|
||||
|
||||
private func handleHandshakeResponse(_ packet: PacketHandshake) {
|
||||
handshakeTimeoutTask?.cancel()
|
||||
handshakeTimeoutTask = nil
|
||||
|
||||
Reference in New Issue
Block a user