Auto fix config ports.

This commit is contained in:
mrFq1 2022-07-28 16:46:07 +08:00
parent 6ef8415c94
commit 9e5fb51ec4
5 changed files with 76 additions and 46 deletions

View File

@ -539,10 +539,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let log: String?
}
let config = ClashMetaConfig.generateInitConfig()
Logger.log("Trying start meta core")
startMeta(config).map { string -> String in
generateInitConfig().then {
self.startMeta($0)
}.map { string -> String in
guard let jsonData = string.data(using: .utf8),
let res = try? JSONDecoder().decode(StartProxyResp.self, from: jsonData) else {
return string == "" ? "unknown error" : string
@ -577,6 +578,18 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}.catch { _ in }
}
func generateInitConfig() -> Promise<ClashMetaConfig.Config> {
var config = ClashMetaConfig.generateInitConfig()
return Promise { resolver in
PrivilegedHelperManager.shared.helper {
resolver.fulfill(config)
}?.getUsedPorts {
config.updatePorts($0 ?? "")
resolver.fulfill(config)
}
}
}
func startMeta(_ config: ClashMetaConfig.Config) -> Promise<String> {
.init { resolver in
PrivilegedHelperManager.shared.helper {

View File

@ -78,6 +78,35 @@ class ClashMetaConfig: NSObject {
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 {

View File

@ -82,17 +82,6 @@ class MetaTask: NSObject {
return
}
let port = serverResult.externalController.components(separatedBy: ":").last ?? "9090"
if let p = Int(port) {
let newPort = self.updateExternalControllerPort(p)
let ec = "127.0.0.1:\(newPort)"
args.append(contentsOf: [
"-ext-ctl",
ec
])
serverResult.externalController = ec
}
self.proc.arguments = args
let pipe = Pipe()
var logs = [String]()
@ -253,6 +242,31 @@ class MetaTask: NSObject {
proc.waitUntilExit()
}
@objc func getUsedPorts(_ result: @escaping stringReplyBlock) {
let proc = Process()
let pipe = Pipe()
proc.standardOutput = pipe
proc.executableURL = .init(fileURLWithPath: "/bin/bash")
proc.arguments = ["-c", "lsof -nP -iTCP -sTCP:LISTEN | grep LISTEN"]
try? proc.run()
proc.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let str = String(data: data, encoding: .utf8) else {
result("")
return
}
let usedPorts = str.split(separator: "\n").compactMap { str -> Int? in
let line = str.split(separator: " ").map(String.init)
guard line.count == 10,
let port = line[8].components(separatedBy: ":").last else { return nil }
return Int(port)
}.map(String.init).joined(separator: ",")
result(usedPorts)
}
func testListenPort(_ port: Int) -> (pid: Int32, addr: String) {
let proc = Process()
let pipe = Pipe()
@ -275,38 +289,6 @@ class MetaTask: NSObject {
return (Int32(pid) ?? 0, addr)
}
func updateExternalControllerPort(_ port: Int) -> Int {
let proc = Process()
let pipe = Pipe()
proc.standardOutput = pipe
proc.executableURL = .init(fileURLWithPath: "/bin/bash")
proc.arguments = ["-c", "lsof -nP -iTCP -sTCP:LISTEN | grep LISTEN"]
try? proc.run()
proc.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let str = String(data: data, encoding: .utf8) else {
return port
}
let ports = str.split(separator: "\n").map {
String($0).split(separator: " ")
}.compactMap { re -> Int? in
guard re.count == 10,
let range = re[8].range(of: ":", options: .backwards) else { return nil }
let s = re[8]
let p = s[range.upperBound..<s.endIndex]
return Int(p)
}
guard ports.contains(port) else {
return port
}
var aPorts = Set(port..<65534)
aPorts.subtract(ports)
return aPorts.min() ?? port
}
func testExternalController(_ server: MetaServer) -> Bool {
let proc = Process()
let pipe = Pipe()

View File

@ -154,4 +154,8 @@ ProxyConfigRemoteProcessProtocol
[self.metaTask stop];
}
- (void)getUsedPorts:(stringReplyBlock)reply {
[self.metaTask getUsedPorts:reply];
}
@end

View File

@ -25,6 +25,8 @@ typedef void(^dictReplyBlock)(NSDictionary *);
ConfFilePath:(NSString *)confFilePath
result:(stringReplyBlock)reply;
- (void)getUsedPorts:(stringReplyBlock)reply;
- (void)stopMeta;
- (void)getVersion:(stringReplyBlock)reply;