145 lines
4.3 KiB
Swift
145 lines
4.3 KiB
Swift
//
|
|
// ClashMetaConfig.swift
|
|
// ClashX Meta
|
|
|
|
import Foundation
|
|
import Cocoa
|
|
import Yams
|
|
|
|
class ClashMetaConfig: NSObject {
|
|
|
|
struct Config: Codable {
|
|
var externalUI: String? = {
|
|
guard let htmlPath = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "dashboard") else {
|
|
return nil
|
|
}
|
|
return URL(fileURLWithPath: htmlPath).deletingLastPathComponent().path
|
|
}()
|
|
|
|
var externalController = "127.0.0.1:9090"
|
|
var secret: String?
|
|
|
|
var port: Int?
|
|
var socksPort: Int?
|
|
var mixedPort: Int?
|
|
|
|
var logLevel = ConfigManager.selectLoggingApiLevel.rawValue
|
|
|
|
var path: String {
|
|
get {
|
|
guard let s = try? YAMLEncoder().encode(self),
|
|
let path = RemoteConfigManager.createCacheConfig(string: s) else {
|
|
assertionFailure("Create init config file failed.")
|
|
return ""
|
|
}
|
|
return path
|
|
}
|
|
}
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case externalController = "external-controller",
|
|
externalUI = "external-ui",
|
|
mixedPort = "mixed-port",
|
|
port,
|
|
socksPort = "socks-port",
|
|
logLevel = "log-level",
|
|
secret
|
|
}
|
|
|
|
mutating func loadDefaultConfigFile() {
|
|
let fm = FileManager.default
|
|
guard let data = fm.contents(atPath: kDefaultConfigFilePath),
|
|
let string = String(data: data, encoding: .utf8),
|
|
let yaml = try? Yams.load(yaml: string) as? [String: Any] else {
|
|
return
|
|
}
|
|
|
|
let keys = Config.CodingKeys.self
|
|
if let ec = yaml[keys.externalController.rawValue] as? String {
|
|
externalController = ec
|
|
}
|
|
|
|
if let s = yaml[keys.secret.rawValue] as? String {
|
|
secret = s
|
|
}
|
|
|
|
if let port = yaml[keys.mixedPort.rawValue] as? Int {
|
|
mixedPort = port
|
|
} else {
|
|
if let p = yaml[keys.port.rawValue] as? Int {
|
|
port = p
|
|
}
|
|
if let sp = yaml[keys.socksPort.rawValue] as? Int {
|
|
socksPort = sp
|
|
}
|
|
}
|
|
|
|
if port == nil && mixedPort == nil {
|
|
mixedPort = 7890
|
|
}
|
|
}
|
|
|
|
mutating func updatePorts(_ usedPorts: String) {
|
|
let usedPorts = usedPorts.split(separator: ",").compactMap {
|
|
Int($0)
|
|
}
|
|
|
|
var availablePorts = Set(1..<65534)
|
|
availablePorts.subtract(usedPorts)
|
|
|
|
func update(_ port: Int?) -> Int? {
|
|
guard let p = port, p != 0 else {
|
|
return port
|
|
}
|
|
|
|
if availablePorts.contains(p) {
|
|
availablePorts.remove(p)
|
|
return p
|
|
} else if let p = Set(p..<65534).intersection(availablePorts).min() {
|
|
availablePorts.remove(p)
|
|
return p
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
port = update(port)
|
|
socksPort = update(socksPort)
|
|
mixedPort = update(mixedPort)
|
|
}
|
|
}
|
|
|
|
static func generateInitConfig() -> Config {
|
|
var config = Config()
|
|
config.loadDefaultConfigFile()
|
|
return config
|
|
}
|
|
|
|
static func updateConfigTun(_ config: Data, enable: Bool) -> String? {
|
|
guard let s = String(data: config, encoding: .utf8),
|
|
var yaml = try? Yams.compose(yaml: s) else {
|
|
return nil
|
|
}
|
|
|
|
if yaml["tun"] != nil {
|
|
yaml["tun"]!["enable"] = .init("\(enable)")
|
|
} else {
|
|
yaml["tun"] = [
|
|
"enable": .init("\(enable)"),
|
|
"stack": "system",
|
|
"auto-route": "true",
|
|
"auto-detect-interface": "true",
|
|
"dns-hijack": [
|
|
"any:53"
|
|
]
|
|
]
|
|
}
|
|
|
|
guard let ss = try? Yams.serialize(node: yaml),
|
|
let path = RemoteConfigManager.createCacheConfig(string: ss) else {
|
|
return nil
|
|
}
|
|
return path
|
|
}
|
|
}
|