fix(macos): add node bridge ping loop
This commit is contained in:
committed by
Peter Steinberger
parent
7b81d97ec2
commit
975aa5bf82
@@ -23,6 +23,9 @@ actor MacNodeBridgeSession {
|
|||||||
private var buffer = Data()
|
private var buffer = Data()
|
||||||
private var pendingRPC: [String: CheckedContinuation<BridgeRPCResponse, Error>] = [:]
|
private var pendingRPC: [String: CheckedContinuation<BridgeRPCResponse, Error>] = [:]
|
||||||
private var serverEventSubscribers: [UUID: AsyncStream<BridgeEventFrame>.Continuation] = [:]
|
private var serverEventSubscribers: [UUID: AsyncStream<BridgeEventFrame>.Continuation] = [:]
|
||||||
|
private var pingTask: Task<Void, Never>?
|
||||||
|
private var lastPongAt: Date?
|
||||||
|
private var lastPingId: String?
|
||||||
|
|
||||||
private(set) var state: State = .idle
|
private(set) var state: State = .idle
|
||||||
|
|
||||||
@@ -77,6 +80,7 @@ actor MacNodeBridgeSession {
|
|||||||
if base.type == "hello-ok" {
|
if base.type == "hello-ok" {
|
||||||
let ok = try self.decoder.decode(BridgeHelloOk.self, from: data)
|
let ok = try self.decoder.decode(BridgeHelloOk.self, from: data)
|
||||||
self.state = .connected(serverName: ok.serverName)
|
self.state = .connected(serverName: ok.serverName)
|
||||||
|
self.startPingLoop()
|
||||||
await onConnected?(ok.serverName)
|
await onConnected?(ok.serverName)
|
||||||
} else if base.type == "error" {
|
} else if base.type == "error" {
|
||||||
let err = try self.decoder.decode(BridgeErrorFrame.self, from: data)
|
let err = try self.decoder.decode(BridgeErrorFrame.self, from: data)
|
||||||
@@ -113,6 +117,10 @@ actor MacNodeBridgeSession {
|
|||||||
let ping = try self.decoder.decode(BridgePing.self, from: nextData)
|
let ping = try self.decoder.decode(BridgePing.self, from: nextData)
|
||||||
try await self.send(BridgePong(type: "pong", id: ping.id))
|
try await self.send(BridgePong(type: "pong", id: ping.id))
|
||||||
|
|
||||||
|
case "pong":
|
||||||
|
let pong = try self.decoder.decode(BridgePong.self, from: nextData)
|
||||||
|
self.notePong(pong)
|
||||||
|
|
||||||
case "invoke":
|
case "invoke":
|
||||||
let req = try self.decoder.decode(BridgeInvokeRequest.self, from: nextData)
|
let req = try self.decoder.decode(BridgeInvokeRequest.self, from: nextData)
|
||||||
let res = await onInvoke(req)
|
let res = await onInvoke(req)
|
||||||
@@ -182,6 +190,11 @@ actor MacNodeBridgeSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func disconnect() async {
|
func disconnect() async {
|
||||||
|
self.pingTask?.cancel()
|
||||||
|
self.pingTask = nil
|
||||||
|
self.lastPongAt = nil
|
||||||
|
self.lastPingId = nil
|
||||||
|
|
||||||
self.connection?.cancel()
|
self.connection?.cancel()
|
||||||
self.connection = nil
|
self.connection = nil
|
||||||
self.queue = nil
|
self.queue = nil
|
||||||
@@ -280,6 +293,52 @@ actor MacNodeBridgeSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func startPingLoop() {
|
||||||
|
self.pingTask?.cancel()
|
||||||
|
self.lastPongAt = Date()
|
||||||
|
self.pingTask = Task { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
await self.runPingLoop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func runPingLoop() async {
|
||||||
|
let intervalSeconds = 15.0
|
||||||
|
let timeoutSeconds = 45.0
|
||||||
|
|
||||||
|
while !Task.isCancelled {
|
||||||
|
do {
|
||||||
|
try await Task.sleep(nanoseconds: UInt64(intervalSeconds * 1_000_000_000))
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard self.connection != nil else { return }
|
||||||
|
|
||||||
|
if let last = self.lastPongAt,
|
||||||
|
Date().timeIntervalSince(last) > timeoutSeconds
|
||||||
|
{
|
||||||
|
await self.disconnect()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = UUID().uuidString
|
||||||
|
self.lastPingId = id
|
||||||
|
do {
|
||||||
|
try await self.send(BridgePing(type: "ping", id: id))
|
||||||
|
} catch {
|
||||||
|
await self.disconnect()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func notePong(_ pong: BridgePong) {
|
||||||
|
if pong.id == self.lastPingId || self.lastPingId == nil {
|
||||||
|
self.lastPongAt = Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static func makeStateStream(
|
private static func makeStateStream(
|
||||||
for connection: NWConnection) -> AsyncStream<NWConnection.State>
|
for connection: NWConnection) -> AsyncStream<NWConnection.State>
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user