Фикс: исправлено исчезновение части уведомлений при открытии пуша

This commit is contained in:
2026-04-06 23:35:29 +05:00
parent 333908a4d9
commit a5945152c0
27 changed files with 2240 additions and 340 deletions

View File

@@ -14,6 +14,18 @@ enum ConnectionState: String {
case authenticated
}
struct MalformedMessagePacketInfo: Sendable {
let packetSize: Int
let fingerprint: String
let messageIdHint: String
}
struct MalformedCriticalPacketInfo: Sendable {
let packetId: Int
let packetSize: Int
let fingerprint: String
}
// MARK: - ProtocolManager
/// Central networking coordinator. Owns WebSocket, routes packets, manages handshake.
@@ -58,6 +70,8 @@ final class ProtocolManager: @unchecked Sendable {
var onWebRTCReceived: ((PacketWebRTC) -> Void)?
var onIceServersReceived: ((PacketIceServers) -> Void)?
var onHandshakeCompleted: ((PacketHandshake) -> Void)?
var onMalformedMessageReceived: ((MalformedMessagePacketInfo) -> Void)?
var onMalformedCriticalPacketReceived: ((MalformedCriticalPacketInfo) -> Void)?
// MARK: - Private
@@ -687,6 +701,15 @@ final class ProtocolManager: @unchecked Sendable {
switch packetId {
case 0x00:
if let p = packet as? PacketHandshake {
if p.isMalformed {
reportMalformedCriticalPacket(
packetId: packetId,
packetSize: data.count,
fingerprint: p.malformedFingerprint,
fallbackFingerprint: "packet00_parse_failed"
)
return
}
handleHandshakeResponse(p)
}
case 0x01:
@@ -712,6 +735,25 @@ final class ProtocolManager: @unchecked Sendable {
}
case 0x06:
if let p = packet as? PacketMessage {
if p.isMalformed {
let messageIdHint = p.messageId.isEmpty ? "-" : String(p.messageId.prefix(8))
let fingerprint = p.malformedFingerprint.isEmpty ? "packet06_parse_failed" : p.malformedFingerprint
reportMalformedCriticalPacket(
packetId: packetId,
packetSize: data.count,
fingerprint: fingerprint,
fallbackFingerprint: "packet06_parse_failed",
messageIdHint: messageIdHint
)
onMalformedMessageReceived?(
MalformedMessagePacketInfo(
packetSize: data.count,
fingerprint: fingerprint,
messageIdHint: messageIdHint
)
)
return
}
onMessageReceived?(p)
}
case 0x07:
@@ -781,6 +823,15 @@ final class ProtocolManager: @unchecked Sendable {
}
case 0x19:
if let p = packet as? PacketSync {
if p.isMalformed {
reportMalformedCriticalPacket(
packetId: packetId,
packetSize: data.count,
fingerprint: p.malformedFingerprint,
fallbackFingerprint: "packet19_parse_failed"
)
return
}
// Android parity: set sync flag SYNCHRONOUSLY on receive queue
// BEFORE dispatching to MainActor callback. This prevents the race
// where a 0x06 message Task runs on MainActor before BATCH_START Task.
@@ -797,11 +848,29 @@ final class ProtocolManager: @unchecked Sendable {
}
case 0x1A:
if let p = packet as? PacketSignalPeer {
if p.isMalformed {
reportMalformedCriticalPacket(
packetId: packetId,
packetSize: data.count,
fingerprint: p.malformedFingerprint,
fallbackFingerprint: "packet1a_parse_failed"
)
return
}
onSignalPeerReceived?(p)
notifySignalPeerHandlers(p)
}
case 0x1B:
if let p = packet as? PacketWebRTC {
if p.isMalformed {
reportMalformedCriticalPacket(
packetId: packetId,
packetSize: data.count,
fingerprint: p.malformedFingerprint,
fallbackFingerprint: "packet1b_parse_failed"
)
return
}
onWebRTCReceived?(p)
notifyWebRtcHandlers(p)
}
@@ -861,6 +930,44 @@ final class ProtocolManager: @unchecked Sendable {
}
}
private func reportMalformedCriticalPacket(
packetId: Int,
packetSize: Int,
fingerprint: String,
fallbackFingerprint: String,
messageIdHint: String? = nil
) {
let packetHex = String(format: "0x%02X", packetId)
let normalizedFingerprint = Self.compactFingerprint(
fingerprint.isEmpty ? fallbackFingerprint : fingerprint
)
if let messageIdHint {
Self.logger.error(
"Dropping malformed \(packetHex) packet size=\(packetSize) msgHint=\(messageIdHint) fp=\(normalizedFingerprint)"
)
} else {
Self.logger.error(
"Dropping malformed \(packetHex) packet size=\(packetSize) fp=\(normalizedFingerprint)"
)
}
onMalformedCriticalPacketReceived?(
MalformedCriticalPacketInfo(
packetId: packetId,
packetSize: packetSize,
fingerprint: normalizedFingerprint
)
)
}
private static func compactFingerprint(_ fingerprint: String) -> String {
let sanitized = fingerprint
.replacingOccurrences(of: "\n", with: " ")
.replacingOccurrences(of: "\t", with: " ")
guard sanitized.count > 120 else { return sanitized }
return String(sanitized.prefix(120))
}
private func handleHandshakeResponse(_ packet: PacketHandshake) {
handshakeTimeoutTask?.cancel()
handshakeTimeoutTask = nil
@@ -1091,4 +1198,10 @@ final class ProtocolManager: @unchecked Sendable {
return nil
}
}
// MARK: - Test Support
func testHandleIncomingData(_ data: Data) {
handleIncomingData(data)
}
}