fix(mac): harden gateway frame decoding
This commit is contained in:
@@ -7,8 +7,8 @@ enum InstanceIdentity {
|
||||
private static var defaults: UserDefaults {
|
||||
UserDefaults(suiteName: suiteName) ?? .standard
|
||||
}
|
||||
|
||||
static let instanceId: String = {
|
||||
let defaults = Self.defaults
|
||||
if let existing = defaults.string(forKey: instanceIdKey)?
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!existing.isEmpty
|
||||
|
||||
@@ -303,8 +303,12 @@ enum CommandResolver {
|
||||
return false
|
||||
}
|
||||
|
||||
static func clawdisNodeCommand(subcommand: String, extraArgs: [String] = []) -> [String] {
|
||||
let settings = self.connectionSettings()
|
||||
static func clawdisNodeCommand(
|
||||
subcommand: String,
|
||||
extraArgs: [String] = [],
|
||||
defaults: UserDefaults = .standard) -> [String]
|
||||
{
|
||||
let settings = self.connectionSettings(defaults: defaults)
|
||||
if settings.mode == .remote, let ssh = self.sshNodeCommand(
|
||||
subcommand: subcommand,
|
||||
extraArgs: extraArgs,
|
||||
@@ -343,8 +347,12 @@ enum CommandResolver {
|
||||
}
|
||||
}
|
||||
|
||||
static func clawdisMacCommand(subcommand: String, extraArgs: [String] = []) -> [String] {
|
||||
let settings = self.connectionSettings()
|
||||
static func clawdisMacCommand(
|
||||
subcommand: String,
|
||||
extraArgs: [String] = [],
|
||||
defaults: UserDefaults = .standard) -> [String]
|
||||
{
|
||||
let settings = self.connectionSettings(defaults: defaults)
|
||||
if settings.mode == .remote, let ssh = self.sshMacHelperCommand(
|
||||
subcommand: subcommand,
|
||||
extraArgs: extraArgs,
|
||||
@@ -359,8 +367,12 @@ enum CommandResolver {
|
||||
}
|
||||
|
||||
// Existing callers still refer to clawdisCommand; keep it as node alias.
|
||||
static func clawdisCommand(subcommand: String, extraArgs: [String] = []) -> [String] {
|
||||
self.clawdisNodeCommand(subcommand: subcommand, extraArgs: extraArgs)
|
||||
static func clawdisCommand(
|
||||
subcommand: String,
|
||||
extraArgs: [String] = [],
|
||||
defaults: UserDefaults = .standard) -> [String]
|
||||
{
|
||||
self.clawdisNodeCommand(subcommand: subcommand, extraArgs: extraArgs, defaults: defaults)
|
||||
}
|
||||
|
||||
// MARK: - SSH helpers
|
||||
@@ -477,12 +489,12 @@ enum CommandResolver {
|
||||
let projectRoot: String
|
||||
}
|
||||
|
||||
static func connectionSettings() -> RemoteSettings {
|
||||
let modeRaw = UserDefaults.standard.string(forKey: connectionModeKey) ?? "local"
|
||||
static func connectionSettings(defaults: UserDefaults = .standard) -> RemoteSettings {
|
||||
let modeRaw = defaults.string(forKey: connectionModeKey) ?? "local"
|
||||
let mode = AppState.ConnectionMode(rawValue: modeRaw) ?? .local
|
||||
let target = UserDefaults.standard.string(forKey: remoteTargetKey) ?? ""
|
||||
let identity = UserDefaults.standard.string(forKey: remoteIdentityKey) ?? ""
|
||||
let projectRoot = UserDefaults.standard.string(forKey: remoteProjectRootKey) ?? ""
|
||||
let target = defaults.string(forKey: remoteTargetKey) ?? ""
|
||||
let identity = defaults.string(forKey: remoteIdentityKey) ?? ""
|
||||
let projectRoot = defaults.string(forKey: remoteProjectRootKey) ?? ""
|
||||
return RemoteSettings(
|
||||
mode: mode,
|
||||
target: self.sanitizedTarget(target),
|
||||
@@ -494,8 +506,8 @@ enum CommandResolver {
|
||||
UserDefaults.standard.bool(forKey: attachExistingGatewayOnlyKey)
|
||||
}
|
||||
|
||||
static func connectionModeIsRemote() -> Bool {
|
||||
self.connectionSettings().mode == .remote
|
||||
static func connectionModeIsRemote(defaults: UserDefaults = .standard) -> Bool {
|
||||
self.connectionSettings(defaults: defaults).mode == .remote
|
||||
}
|
||||
|
||||
private static func sanitizedTarget(_ raw: String) -> String {
|
||||
|
||||
@@ -545,26 +545,29 @@ public enum GatewayFrame: Codable {
|
||||
case event(EventFrame)
|
||||
case unknown(type: String, raw: [String: AnyCodable])
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
let raw = try container.decode([String: AnyCodable].self)
|
||||
guard let type = raw["type"]?.value as? String else {
|
||||
throw DecodingError.dataCorruptedError(in: container, debugDescription: "missing type")
|
||||
}
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let type = try typeContainer.decode(String.self, forKey: .type)
|
||||
switch type {
|
||||
case "hello":
|
||||
self = .hello(try Self.decodePayload(Hello.self, from: raw))
|
||||
self = .hello(try Hello(from: decoder))
|
||||
case "hello-ok":
|
||||
self = .helloOk(try Self.decodePayload(HelloOk.self, from: raw))
|
||||
self = .helloOk(try HelloOk(from: decoder))
|
||||
case "hello-error":
|
||||
self = .helloError(try Self.decodePayload(HelloError.self, from: raw))
|
||||
self = .helloError(try HelloError(from: decoder))
|
||||
case "req":
|
||||
self = .req(try Self.decodePayload(RequestFrame.self, from: raw))
|
||||
self = .req(try RequestFrame(from: decoder))
|
||||
case "res":
|
||||
self = .res(try Self.decodePayload(ResponseFrame.self, from: raw))
|
||||
self = .res(try ResponseFrame(from: decoder))
|
||||
case "event":
|
||||
self = .event(try Self.decodePayload(EventFrame.self, from: raw))
|
||||
self = .event(try EventFrame(from: decoder))
|
||||
default:
|
||||
let container = try decoder.singleValueContainer()
|
||||
let raw = try container.decode([String: AnyCodable].self)
|
||||
self = .unknown(type: type, raw: raw)
|
||||
}
|
||||
}
|
||||
@@ -583,13 +586,4 @@ public enum GatewayFrame: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static func decodePayload<T: Decodable>(_ type: T.Type, from raw: [String: AnyCodable]) throws -> T {
|
||||
// raw is [String: AnyCodable] which is not directly JSONSerialization-compatible.
|
||||
// Round-trip through JSONEncoder so AnyCodable can encode itself safely.
|
||||
let data = try JSONEncoder().encode(raw)
|
||||
let decoder = JSONDecoder()
|
||||
return try decoder.decode(T.self, from: data)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user