macOS: fix gateway strict-concurrency issues
This commit is contained in:
@@ -328,39 +328,35 @@ actor BridgeServer {
|
||||
}
|
||||
|
||||
private func beaconPresence(nodeId: String, reason: String) async {
|
||||
do {
|
||||
let paired = await self.store?.find(nodeId: nodeId)
|
||||
let host = paired?.displayName?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
|
||||
?? nodeId
|
||||
let version = paired?.version?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
|
||||
let platform = paired?.platform?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
|
||||
let ip = await self.connections[nodeId]?.remoteAddress()
|
||||
let paired = await self.store?.find(nodeId: nodeId)
|
||||
let host = paired?.displayName?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
|
||||
?? nodeId
|
||||
let version = paired?.version?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
|
||||
let platform = paired?.platform?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
|
||||
let ip = await self.connections[nodeId]?.remoteAddress()
|
||||
|
||||
var tags: [String] = ["node", "ios"]
|
||||
if let platform { tags.append(platform) }
|
||||
var tags: [String] = ["node", "ios"]
|
||||
if let platform { tags.append(platform) }
|
||||
|
||||
let summary = [
|
||||
"Node: \(host)\(ip.map { " (\($0))" } ?? "")",
|
||||
platform.map { "platform \($0)" },
|
||||
version.map { "app \($0)" },
|
||||
"mode node",
|
||||
"reason \(reason)",
|
||||
].compactMap(\.self).joined(separator: " · ")
|
||||
let summary = [
|
||||
"Node: \(host)\(ip.map { " (\($0))" } ?? "")",
|
||||
platform.map { "platform \($0)" },
|
||||
version.map { "app \($0)" },
|
||||
"mode node",
|
||||
"reason \(reason)",
|
||||
].compactMap(\.self).joined(separator: " · ")
|
||||
|
||||
var params: [String: AnyCodable] = [
|
||||
"text": AnyCodable(summary),
|
||||
"instanceId": AnyCodable(nodeId),
|
||||
"host": AnyCodable(host),
|
||||
"mode": AnyCodable("node"),
|
||||
"reason": AnyCodable(reason),
|
||||
"tags": AnyCodable(tags),
|
||||
]
|
||||
if let ip { params["ip"] = AnyCodable(ip) }
|
||||
if let version { params["version"] = AnyCodable(version) }
|
||||
await GatewayConnection.shared.sendSystemEvent(params)
|
||||
} catch {
|
||||
// Best-effort only.
|
||||
}
|
||||
var params: [String: AnyCodable] = [
|
||||
"text": AnyCodable(summary),
|
||||
"instanceId": AnyCodable(nodeId),
|
||||
"host": AnyCodable(host),
|
||||
"mode": AnyCodable("node"),
|
||||
"reason": AnyCodable(reason),
|
||||
"tags": AnyCodable(tags),
|
||||
]
|
||||
if let ip { params["ip"] = AnyCodable(ip) }
|
||||
if let version { params["version"] = AnyCodable(version) }
|
||||
await GatewayConnection.shared.sendSystemEvent(params)
|
||||
}
|
||||
|
||||
private func startPresenceTask(nodeId: String) {
|
||||
@@ -469,10 +465,3 @@ enum BridgePairingApprover {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
fileprivate var nonEmpty: String? {
|
||||
let trimmed = trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return trimmed.isEmpty ? nil : trimmed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,9 +215,3 @@ final class CanvasManager {
|
||||
return FileManager.default.fileExists(atPath: index.path)
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
var nonEmpty: String? {
|
||||
isEmpty ? nil : self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@ final class CronJobsStore {
|
||||
|
||||
func setJobEnabled(id: String, enabled: Bool) async {
|
||||
do {
|
||||
try await GatewayConnection.shared.cronUpdate(jobId: id, patch: ["enabled": enabled])
|
||||
try await GatewayConnection.shared.cronUpdate(
|
||||
jobId: id,
|
||||
patch: ["enabled": AnyCodable(enabled)])
|
||||
await self.refreshJobs()
|
||||
} catch {
|
||||
self.lastError = error.localizedDescription
|
||||
@@ -127,7 +129,7 @@ final class CronJobsStore {
|
||||
|
||||
func upsertJob(
|
||||
id: String?,
|
||||
payload: [String: Any]) async throws
|
||||
payload: [String: AnyCodable]) async throws
|
||||
{
|
||||
if let id {
|
||||
try await GatewayConnection.shared.cronUpdate(jobId: id, patch: payload)
|
||||
|
||||
@@ -454,7 +454,7 @@ struct CronSettings: View {
|
||||
return "in \(days)d"
|
||||
}
|
||||
|
||||
private func save(payload: [String: Any]) async {
|
||||
private func save(payload: [String: AnyCodable]) async {
|
||||
guard !self.isSaving else { return }
|
||||
self.isSaving = true
|
||||
self.editorError = nil
|
||||
@@ -494,7 +494,7 @@ struct CronJobEditor: View {
|
||||
@Binding var isSaving: Bool
|
||||
@Binding var error: String?
|
||||
let onCancel: () -> Void
|
||||
let onSave: ([String: Any]) -> Void
|
||||
let onSave: ([String: AnyCodable]) -> Void
|
||||
|
||||
private let labelColumnWidth: CGFloat = 160
|
||||
private static let introText =
|
||||
@@ -879,7 +879,7 @@ struct CronJobEditor: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func buildPayload() throws -> [String: Any] {
|
||||
private func buildPayload() throws -> [String: AnyCodable] {
|
||||
let name = self.name.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let schedule: [String: Any]
|
||||
switch self.scheduleKind {
|
||||
@@ -969,7 +969,7 @@ struct CronJobEditor: View {
|
||||
]
|
||||
}
|
||||
|
||||
return root
|
||||
return root.mapValues { AnyCodable($0) }
|
||||
}
|
||||
|
||||
private func buildAgentTurnPayload() -> [String: Any] {
|
||||
|
||||
@@ -418,13 +418,13 @@ extension GatewayConnection {
|
||||
try await self.requestVoid(method: .cronRemove, params: ["id": AnyCodable(jobId)])
|
||||
}
|
||||
|
||||
func cronUpdate(jobId: String, patch: [String: Any]) async throws {
|
||||
func cronUpdate(jobId: String, patch: [String: AnyCodable]) async throws {
|
||||
try await self.requestVoid(
|
||||
method: .cronUpdate,
|
||||
params: ["id": AnyCodable(jobId), "patch": AnyCodable(patch)])
|
||||
}
|
||||
|
||||
func cronAdd(payload: [String: Any]) async throws {
|
||||
try await self.requestVoid(method: .cronAdd, params: payload.mapValues { AnyCodable($0) })
|
||||
func cronAdd(payload: [String: AnyCodable]) async throws {
|
||||
try await self.requestVoid(method: .cronAdd, params: payload)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,22 +152,27 @@ final class GatewayProcessManager {
|
||||
private func attachExistingGatewayIfAvailable() async -> Bool {
|
||||
let port = GatewayEnvironment.gatewayPort()
|
||||
do {
|
||||
let data = try await GatewayConnection.shared.requestRaw(method: .health, timeoutMs: 2000)
|
||||
let snap = decodeHealthSnapshot(from: data)
|
||||
|
||||
let instance = await PortGuardian.shared.describe(port: port)
|
||||
let instanceText: String
|
||||
if let instance {
|
||||
let path = instance.executablePath ?? "path unknown"
|
||||
instanceText = "pid \(instance.pid) \(instance.command) @ \(path)"
|
||||
} else {
|
||||
instanceText = "pid unknown"
|
||||
}
|
||||
|
||||
let details: String
|
||||
if let snap = try? await GatewayConnection.shared.healthSnapshot() {
|
||||
if let snap {
|
||||
let linked = snap.web.linked ? "linked" : "not linked"
|
||||
let authAge = snap.web.authAgeMs.flatMap(msToAge) ?? "unknown age"
|
||||
let instance = await PortGuardian.shared.describe(port: port)
|
||||
let instanceText: String
|
||||
if let instance {
|
||||
let path = instance.executablePath ?? "path unknown"
|
||||
instanceText = "pid \(instance.pid) \(instance.command) @ \(path)"
|
||||
} else {
|
||||
instanceText = "pid unknown"
|
||||
}
|
||||
details = "port \(port), \(linked), auth \(authAge), \(instanceText)"
|
||||
} else {
|
||||
details = "port \(port), health probe succeeded"
|
||||
details = "port \(port), health probe succeeded, \(instanceText)"
|
||||
}
|
||||
|
||||
self.existingGatewayDetails = details
|
||||
self.status = .attachedExisting(details: details)
|
||||
self.appendLog("[gateway] using existing instance: \(details)\n")
|
||||
|
||||
9
apps/macos/Sources/Clawdis/String+NonEmpty.swift
Normal file
9
apps/macos/Sources/Clawdis/String+NonEmpty.swift
Normal file
@@ -0,0 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
extension String {
|
||||
var nonEmpty: String? {
|
||||
let trimmed = self.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return trimmed.isEmpty ? nil : trimmed
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user