import Foundation import LibXray /// Thin wrapper around LibXray.Invoke (macOS Manager engine.Start for Xray). enum LibXrayCore { struct InvokeError: LocalizedError { var message: String var errorDescription: String? { message } } static func runJSON(_ configJSON: String) throws { let payload: [String: Any] = [ "apiVersion": 1, "method": "runXrayFromJson", "payload": ["configJSON": configJSON], ] try invoke(payload) } static func runFile(_ configPath: String) throws { let payload: [String: Any] = [ "apiVersion": 1, "method": "runXray", "payload": ["configPath": configPath], ] try invoke(payload) } static func stop() { let payload: [String: Any] = [ "apiVersion": 1, "method": "stopXray", "payload": [:] as [String: Any], ] _ = try? invoke(payload) } static func isRunning() -> Bool { let payload: [String: Any] = [ "apiVersion": 1, "method": "getXrayState", "payload": [:] as [String: Any], ] guard let data = try? invokeData(payload), let running = data["running"] as? Bool else { return false } return running } static func version() -> String { let payload: [String: Any] = [ "apiVersion": 1, "method": "xrayVersion", "payload": [:] as [String: Any], ] guard let data = try? invokeData(payload), let v = data["version"] as? String else { return "?" } return v } @discardableResult private static func invoke(_ payload: [String: Any]) throws -> [String: Any]? { let data = try invokeData(payload) return data } private static func invokeData(_ payload: [String: Any]) throws -> [String: Any]? { let reqData = try JSONSerialization.data(withJSONObject: payload) guard let req = String(data: reqData, encoding: .utf8) else { throw InvokeError(message: "encode invoke request") } let respStr = LibXrayInvoke(req) guard let respData = respStr.data(using: .utf8), let obj = try JSONSerialization.jsonObject(with: respData) as? [String: Any] else { throw InvokeError(message: "decode invoke response") } let ok = obj["success"] as? Bool ?? false if !ok { throw InvokeError(message: (obj["error"] as? String) ?? "LibXray error") } return obj["data"] as? [String: Any] } }