add ping pong
This commit is contained in:
		
							parent
							
								
									f886386374
								
							
						
					
					
						commit
						41adedee40
					
				@ -39,6 +39,7 @@ final class SocketService {
 | 
			
		||||
    private var socket: SocketIOClient?
 | 
			
		||||
    private var heartbeatTimer: DispatchSourceTimer?
 | 
			
		||||
    private var heartbeatAckInFlight = false
 | 
			
		||||
    private var lastHeartbeatSentAt: Date?
 | 
			
		||||
    private var consecutiveHeartbeatMisses = 0
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
@ -193,6 +194,10 @@ final class SocketService {
 | 
			
		||||
            self?.handleHeartbeatSuccess()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        socket.on("message") { [weak self] data, _ in
 | 
			
		||||
            self?.handleMessageEvent(data)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.manager = manager
 | 
			
		||||
        self.socket = socket
 | 
			
		||||
    }
 | 
			
		||||
@ -224,6 +229,7 @@ final class SocketService {
 | 
			
		||||
        heartbeatTimer = nil
 | 
			
		||||
        heartbeatAckInFlight = false
 | 
			
		||||
        consecutiveHeartbeatMisses = 0
 | 
			
		||||
        lastHeartbeatSentAt = nil
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func performHeartbeatCheck() {
 | 
			
		||||
@ -246,43 +252,61 @@ final class SocketService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func sendHeartbeat(on socket: SocketIOClient) {
 | 
			
		||||
        guard !heartbeatAckInFlight else { return }
 | 
			
		||||
        heartbeatAckInFlight = true
 | 
			
		||||
 | 
			
		||||
        socket.emitWithAck(heartbeatEventName, ["timestamp": Date().timeIntervalSince1970])
 | 
			
		||||
            .timingOut(after: heartbeatTimeout) { [weak self] data in
 | 
			
		||||
                guard let self else { return }
 | 
			
		||||
                self.heartbeatAckInFlight = false
 | 
			
		||||
 | 
			
		||||
                if self.isSuccessfulHeartbeatResponse(data) {
 | 
			
		||||
                    self.handleHeartbeatSuccess()
 | 
			
		||||
                } else {
 | 
			
		||||
                    self.handleMissedHeartbeat(for: socket)
 | 
			
		||||
                }
 | 
			
		||||
        if heartbeatAckInFlight {
 | 
			
		||||
            if let lastSentAt = lastHeartbeatSentAt,
 | 
			
		||||
               Date().timeIntervalSince(lastSentAt) >= heartbeatTimeout {
 | 
			
		||||
                heartbeatAckInFlight = false
 | 
			
		||||
                handleMissedHeartbeat(for: socket)
 | 
			
		||||
            } else {
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        heartbeatAckInFlight = true
 | 
			
		||||
        lastHeartbeatSentAt = Date()
 | 
			
		||||
 | 
			
		||||
        socket.emit(heartbeatEventName, ["data": "ping"])
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func isSuccessfulHeartbeatResponse(_ data: [Any]) -> Bool {
 | 
			
		||||
        guard !data.isEmpty else { return true }
 | 
			
		||||
    private func handleMessageEvent(_ data: [Any]) {
 | 
			
		||||
        guard let payload = data.first else { return }
 | 
			
		||||
 | 
			
		||||
        if let stringValue = data.first as? String, stringValue.uppercased() == "NO ACK" {
 | 
			
		||||
            return false
 | 
			
		||||
        let messageText: String?
 | 
			
		||||
 | 
			
		||||
        if let dictionary = payload as? [String: Any] {
 | 
			
		||||
            if let nestedData = dictionary["data"] as? [String: Any],
 | 
			
		||||
               let nestedMessage = nestedData["message"] as? String {
 | 
			
		||||
                messageText = nestedMessage
 | 
			
		||||
            } else {
 | 
			
		||||
                messageText = dictionary["message"] as? String
 | 
			
		||||
            }
 | 
			
		||||
        } else if let stringValue = payload as? String {
 | 
			
		||||
            messageText = stringValue
 | 
			
		||||
        } else {
 | 
			
		||||
            messageText = nil
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let ackStatus = data.first as? SocketAckStatus, ackStatus == .noAck {
 | 
			
		||||
            return false
 | 
			
		||||
        guard let message = messageText?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() else {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true
 | 
			
		||||
        if message == "pong" {
 | 
			
		||||
            handleHeartbeatSuccess()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func handleHeartbeatSuccess() {
 | 
			
		||||
        consecutiveHeartbeatMisses = 0
 | 
			
		||||
        heartbeatAckInFlight = false
 | 
			
		||||
        lastHeartbeatSentAt = nil
 | 
			
		||||
        updateConnectionState(.connected)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func handleMissedHeartbeat(for socket: SocketIOClient) {
 | 
			
		||||
        consecutiveHeartbeatMisses += 1
 | 
			
		||||
        heartbeatAckInFlight = false
 | 
			
		||||
        lastHeartbeatSentAt = nil
 | 
			
		||||
        updateConnectionState(.connecting)
 | 
			
		||||
        guard consecutiveHeartbeatMisses > maxHeartbeatMissCount else {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ struct AppConfig {
 | 
			
		||||
    static let PROTOCOL = "https"
 | 
			
		||||
    static let API_SERVER = "\(PROTOCOL)://api.yobble.org"
 | 
			
		||||
    static let SOCKET_PATH = "/socket.io/"
 | 
			
		||||
    static let SOCKET_HEARTBEAT_EVENT = "ping"
 | 
			
		||||
    static let SOCKET_HEARTBEAT_EVENT = "client_message"
 | 
			
		||||
 | 
			
		||||
    static let USER_AGENT = "yobble ios"
 | 
			
		||||
    static let APP_BUILD = "appstore" // appstore / freestore
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user