Add SwiftUI + Network Extension (LibXray/hev), parse Clash Meta YAML from subscription URLs into vless/trojan/hy2 share links, keep the selected server on connect, and ship Navis-3.8.2.13.ipa with versioned changelog. Co-authored-by: Cursor <cursoragent@cursor.com>
86 lines
2.6 KiB
Swift
86 lines
2.6 KiB
Swift
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]
|
|
}
|
|
}
|