jellyflood/JellyfinPlayer/OpenCastSwift/Networking/Channels/HeartbeatChannel.swift

98 lines
2.6 KiB
Swift

//
// CastHeartbeatChannel.swift
// OpenCastSwift
//
// Created by Miles Hollingsworth on 4/22/18
// Copyright © 2018 Miles Hollingsworth. All rights reserved.
//
import Foundation
import SwiftyJSON
class HeartbeatChannel: CastChannel {
private lazy var timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(sendPing), userInfo: nil, repeats: true)
private let disconnectTimeout: TimeInterval = 10
private var disconnectTimer: Timer? {
willSet {
disconnectTimer?.invalidate()
}
didSet {
guard let timer = disconnectTimer else { return }
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}
}
override weak var requestDispatcher: RequestDispatchable! {
didSet {
if let _ = requestDispatcher {
startBeating()
} else {
timer.invalidate()
}
}
}
private var delegate: HeartbeatChannelDelegate? {
return requestDispatcher as? HeartbeatChannelDelegate
}
init() {
super.init(namespace: CastNamespace.heartbeat)
}
override func handleResponse(_ json: JSON, sourceId: String) {
delegate?.channelDidConnect(self)
guard let rawType = json["type"].string else { return }
guard let type = CastMessageType(rawValue: rawType) else {
print("Unknown type: \(rawType)")
print(json)
return
}
if type == .ping {
sendPong(to: sourceId)
print("PING from \(sourceId)")
}
disconnectTimer = Timer(timeInterval: disconnectTimeout,
target: self,
selector: #selector(handleTimeout),
userInfo: nil,
repeats: false)
}
private func startBeating() {
_ = timer
sendPing()
}
@objc private func sendPing() {
let request = requestDispatcher.request(withNamespace: namespace,
destinationId: CastConstants.transport,
payload: [CastJSONPayloadKeys.type: CastMessageType.ping.rawValue])
send(request)
}
private func sendPong(to destinationId: String) {
let request = requestDispatcher.request(withNamespace: namespace,
destinationId: destinationId,
payload: [CastJSONPayloadKeys.type: CastMessageType.pong.rawValue])
send(request)
}
@objc private func handleTimeout() {
delegate?.channelDidTimeout(self)
}
}
protocol HeartbeatChannelDelegate: AnyObject {
func channelDidConnect(_ channel: HeartbeatChannel)
func channelDidTimeout(_ channel: HeartbeatChannel)
}