import Foundation public enum FrameCodec { public static let maximumFrameSize = 1_200_000 public static func encode(_ value: T) throws -> Data { let encoder = PropertyListEncoder(); encoder.outputFormat = .binary let body = try encoder.encode(value) guard body.count <= maximumFrameSize else { throw UMNError.invalidFrame } var size = UInt32(body.count).bigEndian return withUnsafeBytes(of: &size) { Data($0) } + body } public static func decode(_ type: T.Type, body: Data) throws -> T { guard body.count <= maximumFrameSize else { throw UMNError.invalidFrame } return try PropertyListDecoder().decode(type, from: body) } public static func bodyLength(from prefix: Data) throws -> Int { guard prefix.count == 4 else { throw UMNError.invalidFrame } let value = prefix.reduce(UInt32(0)) { ($0 << 8) | UInt32($1) } guard value > 0, value <= maximumFrameSize else { throw UMNError.invalidFrame } return Int(value) } } public enum IPCOperation: String, Codable, Sendable { case status, address, peers, routes, ping, interfaceStatus case aliasSet, aliasRemove, aliasList case firewallAllow, firewallRevoke, firewallList case textSend, bindText, bindStream, openStream, streamData, streamClose } public struct IPCMessage: Codable, Sendable { public var version: UInt16 public var operation: IPCOperation public var requestID: UUID public var target: String? public var source: String? public var name: String? public var port: UInt16? public var firewallProtocol: FirewallProtocol? public var interfaceName: String? public var interfaceAddress: String? public var interfaceMTU: UInt16? public var helperState: String? public var synchronizedRouteCount: Int? public var dnsState: String? public var streamID: UInt64? public var data: Data? public var ok: Bool? public var message: String? public var values: [String]? public init(operation: IPCOperation, requestID: UUID = UUID()) { self.version = 2; self.operation = operation; self.requestID = requestID } }