From 11496a80db5f918edb1af426ed8dd41099d46033 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 1 Apr 2023 13:42:05 +0800 Subject: [PATCH 1/8] misc: fix alpha downloader (cherry picked from commit 33fe7ed2d6d15c9127cfd778318cf7b34a3f50a8) --- ClashX/AppDelegate.swift | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/ClashX/AppDelegate.swift b/ClashX/AppDelegate.swift index 9df4b342a..c82d4d971 100644 --- a/ClashX/AppDelegate.swift +++ b/ClashX/AppDelegate.swift @@ -551,10 +551,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { } } - if !chmodX(corePath.path) { - return (nil, "chmod +x failed.") - } - if let msg = testMetaCore(corePath.path) { Logger.log("version: \(msg.version)") } @@ -609,6 +605,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { } func testMetaCore(_ path: String) -> (version: String, date: Date?)? { + guard chmodX(path) else { return nil } let proc = Process() proc.executableURL = .init(fileURLWithPath: path) @@ -631,7 +628,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { let outs = out.replacingOccurrences(of: "\n", with: "").split(separator: " ").map(String.init) - guard outs.count == 13, + guard outs.count >= 13, outs[0] == "Clash", outs[1] == "Meta", outs[3] == "darwin" else { @@ -640,17 +637,13 @@ class AppDelegate: NSObject, NSApplicationDelegate { let version = outs[2] - let dateString = [outs[7], outs[8], outs[9], outs[10], outs[12]].joined(separator: "-") - let f = DateFormatter() - f.dateFormat = "E-MMM-d-HH:mm:ss-yyyy" - f.timeZone = .init(abbreviation: outs[11]) - let date = f.date(from: dateString) - - return (version: version, date: date) + return (version: version, date: nil) } func validateDefaultCore() -> Bool { - guard let path = Paths.defaultCorePath()?.path else { return false } + guard let path = Paths.defaultCorePath()?.path, + chmodX(path) else { return false } + #if DEBUG return true #endif From 1b064f40c7269b584f3d32858caf4f58aef31c5e Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 1 Apr 2023 13:52:11 +0800 Subject: [PATCH 2/8] misc: fix core date --- ClashX/AppDelegate.swift | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ClashX/AppDelegate.swift b/ClashX/AppDelegate.swift index c82d4d971..99f48f6f6 100644 --- a/ClashX/AppDelegate.swift +++ b/ClashX/AppDelegate.swift @@ -626,9 +626,15 @@ class AppDelegate: NSObject, NSApplicationDelegate { return nil } - let outs = out.replacingOccurrences(of: "\n", with: "").split(separator: " ").map(String.init) - - guard outs.count >= 13, + let outs = out + .split(separator: "\n") + .first { + $0.starts(with: "Clash Meta") + }?.split(separator: " ") + .map(String.init) + + guard let outs, + outs.count == 13, outs[0] == "Clash", outs[1] == "Meta", outs[3] == "darwin" else { @@ -637,7 +643,13 @@ class AppDelegate: NSObject, NSApplicationDelegate { let version = outs[2] - return (version: version, date: nil) + let dateString = [outs[7], outs[8], outs[9], outs[10], outs[12]].joined(separator: "-") + let f = DateFormatter() + f.dateFormat = "E-MMM-d-HH:mm:ss-yyyy" + f.timeZone = .init(abbreviation: outs[11]) + let date = f.date(from: dateString) + + return (version: version, date: date) } func validateDefaultCore() -> Bool { From 0aa471a221369bab6e42b27dcbdeb21781e09f3b Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 1 Apr 2023 15:19:01 +0800 Subject: [PATCH 3/8] misc: temp path --- ClashX/General/Managers/RemoteConfigManager.swift | 2 +- ClashX/Macro/Paths.swift | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ClashX/General/Managers/RemoteConfigManager.swift b/ClashX/General/Managers/RemoteConfigManager.swift index 9aad07097..21b82630b 100755 --- a/ClashX/General/Managers/RemoteConfigManager.swift +++ b/ClashX/General/Managers/RemoteConfigManager.swift @@ -208,7 +208,7 @@ class RemoteConfigManager { } static func createCacheConfig(string: String) -> String? { - let path = NSTemporaryDirectory().appending("com.MetaCubeX.ClashX.meta") + "/cacheConfigs" + let path = Paths.tempPath() + "/cacheConfigs" let confPath = path + "/\(UUID().uuidString).yaml" let fm = FileManager.default diff --git a/ClashX/Macro/Paths.swift b/ClashX/Macro/Paths.swift index f5e49ec61..ff2dab2e0 100644 --- a/ClashX/Macro/Paths.swift +++ b/ClashX/Macro/Paths.swift @@ -47,4 +47,8 @@ struct Paths { .first? .appendingPathComponent("com.metacubex.ClashX.meta") } + + static func tempPath() -> String { + NSTemporaryDirectory().appending("com.MetaCubeX.ClashX.meta") + } } From 360e1ce09fecf42580fdcac77e3551fe75ca6d23 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 1 Apr 2023 15:23:13 +0800 Subject: [PATCH 4/8] chore: AlphaMetaDownloader --- ClashX.xcodeproj/project.pbxproj | 4 + ClashX/AppDelegate.swift | 111 +++------------- ClashX/General/AlphaMetaDownloader.swift | 154 +++++++++++++++++++++++ ClashX/Macro/Paths.swift | 2 +- 4 files changed, 177 insertions(+), 94 deletions(-) create mode 100644 ClashX/General/AlphaMetaDownloader.swift diff --git a/ClashX.xcodeproj/project.pbxproj b/ClashX.xcodeproj/project.pbxproj index 7ad634f77..29b5bf5a8 100644 --- a/ClashX.xcodeproj/project.pbxproj +++ b/ClashX.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 015F1E91288E42A50052B20A /* ClashMetaConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 015F1E90288E42A50052B20A /* ClashMetaConfig.swift */; }; 015F1E92288E60D30052B20A /* MetaTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0162E74E2864B819007218A6 /* MetaTask.swift */; }; 0162E74F2864B819007218A6 /* MetaTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0162E74E2864B819007218A6 /* MetaTask.swift */; }; + 016BEAB029D80103001586C5 /* AlphaMetaDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016BEAAF29D80102001586C5 /* AlphaMetaDownloader.swift */; }; 018F88F9286DD0CB004DD0F7 /* DualTitleMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018F88F8286DD0CB004DD0F7 /* DualTitleMenuItem.swift */; }; 01943259287D19BC008CC51A /* ClashRuleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01943258287D19BC008CC51A /* ClashRuleProvider.swift */; }; 019A239628657A7A00AE5698 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019A239528657A7A00AE5698 /* main.swift */; }; @@ -143,6 +144,7 @@ 015F1E90288E42A50052B20A /* ClashMetaConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashMetaConfig.swift; sourceTree = ""; }; 0162E74D2864B818007218A6 /* com.metacubex.ClashX.ProxyConfigHelper-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "com.metacubex.ClashX.ProxyConfigHelper-Bridging-Header.h"; sourceTree = ""; }; 0162E74E2864B819007218A6 /* MetaTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaTask.swift; sourceTree = ""; }; + 016BEAAF29D80102001586C5 /* AlphaMetaDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlphaMetaDownloader.swift; sourceTree = ""; }; 018F88F8286DD0CB004DD0F7 /* DualTitleMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DualTitleMenuItem.swift; sourceTree = ""; }; 01943258287D19BC008CC51A /* ClashRuleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashRuleProvider.swift; sourceTree = ""; }; 019A239528657A7A00AE5698 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; @@ -344,6 +346,7 @@ 491C250021BD55B900AB5D44 /* Utils */, 492C4868210EE6B9004554A0 /* ApiRequest.swift */, 015F1E90288E42A50052B20A /* ClashMetaConfig.swift */, + 016BEAAF29D80102001586C5 /* AlphaMetaDownloader.swift */, ); path = General; sourceTree = ""; @@ -750,6 +753,7 @@ 49CF3B2120CD7463001EBF94 /* AppDelegate.swift in Sources */, 496BDEE021196F1E00C5207F /* Logger.swift in Sources */, 49722FEF211F338B00650A41 /* FileEvent.swift in Sources */, + 016BEAB029D80103001586C5 /* AlphaMetaDownloader.swift in Sources */, 49D176A72355FE680093DD7B /* NetworkChangeNotifier.swift in Sources */, 4913C82321157D0200F6B87C /* Notification.swift in Sources */, 015F1E91288E42A50052B20A /* ClashMetaConfig.swift in Sources */, diff --git a/ClashX/AppDelegate.swift b/ClashX/AppDelegate.swift index 99f48f6f6..d1794d6c0 100644 --- a/ClashX/AppDelegate.swift +++ b/ClashX/AppDelegate.swift @@ -1305,101 +1305,26 @@ extension AppDelegate { } @IBAction func updateAlphaMeta(_ sender: NSMenuItem) { - guard let helperURL = Paths.alphaCorePath() else { - return - } sender.isEnabled = false - struct ReleasesResp: Decodable { - let assets: [Asset] - struct Asset: Decodable { - let name: String - let downloadUrl: String - let contentType: String - let state: String - - enum CodingKeys: String, CodingKey { - case name, - state, - downloadUrl = "browser_download_url", - contentType = "content_type" - } - } - } - - func GetMachineHardwareName() -> String? { - var sysInfo = utsname() - let retVal = uname(&sysInfo) - guard retVal == EXIT_SUCCESS else { return nil } - - let machineMirror = Mirror(reflecting: sysInfo.machine) - let identifier = machineMirror.children.reduce("") { identifier, element in - guard let value = element.value as? Int8, value != 0 else { return identifier } - return identifier + String(UnicodeScalar(UInt8(value))) - } - return identifier - } - - let assetName: String? = { - switch GetMachineHardwareName() { - case "x86_64": - return "darwin-amd64" - case "arm64": - return "darwin-arm64" - default: - return nil - } - }() - let fm = FileManager.default - - func dlResult(_ info: String) { - sender.isEnabled = true - NSUserNotificationCenter.default.post(title: "Clash Meta Core", info: info) - } - - AF.request("https://api.github.com/repos/MetaCubeX/Clash.Meta/releases/tags/Prerelease-Alpha").responseDecodable(of: ReleasesResp.self) { - guard let assets = $0.value?.assets, - let assetName = assetName, - let asset = assets.first(where: { - $0.name.contains(assetName) && - $0.state == "uploaded" && - $0.contentType == "application/gzip" - }) else { - dlResult("Decode alpha release info failed") - return - } - - if let v = self.testMetaCore(helperURL.path), - asset.name.contains(v.version) { - dlResult("Not found update") - return - } - - self.updateAlphaVersion(nil) - - AF.download(asset.downloadUrl).response { - guard let gzPath = $0.fileURL?.path, - let contentData = fm.contents(atPath: gzPath) - else { - dlResult("Download file failed") - return - } - do { - try? fm.removeItem(at: helperURL) - - try fm.createDirectory(at: helperURL.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil) - try contentData.gunzipped().write(to: helperURL) - guard let version = self.testMetaCore(helperURL.path)?.version else { - dlResult("Test downloaded file failed") - return - } - self.updateAlphaVersion(version) - dlResult(NSLocalizedString("Version: ", comment: "") + version) - } catch let error { - dlResult("Something error \(error.localizedDescription)") - } - } - } + AlphaMetaDownloader.alphaAsset().get { _ in + self.updateAlphaVersion(nil) + }.then { + AlphaMetaDownloader.checkVersion($0) + }.then { + AlphaMetaDownloader.downloadCore($0) + }.then { + AlphaMetaDownloader.replaceCore($0) + }.done { + self.updateAlphaVersion($0) + let msg = NSLocalizedString("Version: ", comment: "") + $0 + NSUserNotificationCenter.default.post(title: "Clash Meta Core", info: msg) + }.ensure { + sender.isEnabled = true + }.catch { + let error = $0 as? AlphaMetaDownloader.errors + NSUserNotificationCenter.default.post(title: "Clash Meta Core", info: error?.des() ?? "") + } } func updateAlphaVersion(_ version: String?) { diff --git a/ClashX/General/AlphaMetaDownloader.swift b/ClashX/General/AlphaMetaDownloader.swift new file mode 100644 index 000000000..fab80fb01 --- /dev/null +++ b/ClashX/General/AlphaMetaDownloader.swift @@ -0,0 +1,154 @@ +// +// AlphaMetaDownloader.swift +// ClashX Meta +// +// Copyright © 2023 west2online. All rights reserved. +// + +import Cocoa +import Alamofire +import PromiseKit + +class AlphaMetaDownloader: NSObject { + + enum errors: Error { + case decodeReleaseInfoFailed + case notFoundUpdate + case downloadFailed + case unknownError + case testFailed + + func des() -> String { + switch self { + case .decodeReleaseInfoFailed: + return "Decode alpha release info failed" + case .notFoundUpdate: + return "Not found update" + case .downloadFailed: + return "Download failed" + case .testFailed: + return "Test downloaded file failed" + case .unknownError: + return "Unknown error" + } + } + } + + struct ReleasesResp: Decodable { + let assets: [Asset] + struct Asset: Decodable { + let name: String + let downloadUrl: String + let contentType: String + let state: String + + enum CodingKeys: String, CodingKey { + case name, + state, + downloadUrl = "browser_download_url", + contentType = "content_type" + } + } + } + + static func assetName() -> String? { + switch GetMachineHardwareName() { + case "x86_64": + return "darwin-amd64" + case "arm64": + return "darwin-arm64" + default: + return nil + } + } + + static func GetMachineHardwareName() -> String? { + var sysInfo = utsname() + let retVal = uname(&sysInfo) + + guard retVal == EXIT_SUCCESS else { return nil } + + let machineMirror = Mirror(reflecting: sysInfo.machine) + let identifier = machineMirror.children.reduce("") { identifier, element in + guard let value = element.value as? Int8, value != 0 else { return identifier } + return identifier + String(UnicodeScalar(UInt8(value))) + } + return identifier + } + + static func alphaAsset() -> Promise { + Promise { resolver in + let assetName = assetName() + AF.request("https://api.github.com/repos/MetaCubeX/Clash.Meta/releases/tags/Prerelease-Alpha").responseDecodable(of: ReleasesResp.self) { + guard let assets = $0.value?.assets, + let assetName, + let asset = assets.first(where: { + $0.name.contains(assetName) && + $0.state == "uploaded" && + $0.contentType == "application/gzip" + }) else { + resolver.reject(errors.decodeReleaseInfoFailed) + return + } + resolver.fulfill(asset) + } + } + } + + static func checkVersion(_ asset: ReleasesResp.Asset) -> Promise { + Promise { resolver in + guard let path = Paths.alphaCorePath()?.path, + let ad = NSApplication.shared.delegate as? AppDelegate else { + resolver.reject(errors.unknownError) + return + } + if let v = ad.testMetaCore(path), + asset.name.contains(v.version) { + resolver.reject(errors.notFoundUpdate) + } + resolver.fulfill(asset) + } + } + + static func downloadCore(_ asset: ReleasesResp.Asset) -> Promise { + Promise { resolver in + let fm = FileManager.default + AF.download(asset.downloadUrl).response { + guard let gzPath = $0.fileURL?.path, + let contentData = fm.contents(atPath: gzPath) + else { + resolver.reject(errors.downloadFailed) + return + } + resolver.fulfill(contentData) + } + } + } + + static func replaceCore(_ gzData: Data) -> Promise { + Promise { resolver in + let fm = FileManager.default + + guard let helperURL = Paths.alphaCorePath(), + let ad = NSApplication.shared.delegate as? AppDelegate else { + resolver.reject(errors.unknownError) + return + } + + try fm.createDirectory(at: helperURL.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil) + + let cachePath = Paths.tempPath().appending("/\(UUID().uuidString).newcore") + try gzData.gunzipped().write(to: .init(fileURLWithPath: cachePath)) + + guard let version = ad.testMetaCore(cachePath)?.version else { + resolver.reject(errors.testFailed) + return + } + + try? fm.removeItem(at: helperURL) + try fm.moveItem(atPath: cachePath, toPath: helperURL.path) + + resolver.fulfill(version) + } + } +} diff --git a/ClashX/Macro/Paths.swift b/ClashX/Macro/Paths.swift index ff2dab2e0..fcf6d6926 100644 --- a/ClashX/Macro/Paths.swift +++ b/ClashX/Macro/Paths.swift @@ -47,7 +47,7 @@ struct Paths { .first? .appendingPathComponent("com.metacubex.ClashX.meta") } - + static func tempPath() -> String { NSTemporaryDirectory().appending("com.MetaCubeX.ClashX.meta") } From 21ed86bd7524977927153a7345bf904cc097d511 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 1 Apr 2023 19:17:15 +0800 Subject: [PATCH 5/8] misc: fix archive --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/xcschemes/ClashX.xcscheme | 20 +------------------ 2 files changed, 9 insertions(+), 19 deletions(-) create mode 100644 ClashX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ClashX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ClashX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/ClashX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ClashX.xcodeproj/xcshareddata/xcschemes/ClashX.xcscheme b/ClashX.xcodeproj/xcshareddata/xcschemes/ClashX.xcscheme index 661fe28dc..bea88c4b1 100644 --- a/ClashX.xcodeproj/xcshareddata/xcschemes/ClashX.xcscheme +++ b/ClashX.xcodeproj/xcshareddata/xcschemes/ClashX.xcscheme @@ -1,28 +1,10 @@ + version = "1.3"> - - - - - - - - - - Date: Sat, 1 Apr 2023 21:13:28 +0800 Subject: [PATCH 6/8] misc: remove cgo --- ClashX/General/AlphaMetaDownloader.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/ClashX/General/AlphaMetaDownloader.swift b/ClashX/General/AlphaMetaDownloader.swift index fab80fb01..6d7d39913 100644 --- a/ClashX/General/AlphaMetaDownloader.swift +++ b/ClashX/General/AlphaMetaDownloader.swift @@ -84,6 +84,7 @@ class AlphaMetaDownloader: NSObject { let assetName, let asset = assets.first(where: { $0.name.contains(assetName) && + !$0.name.contains("cgo") && $0.state == "uploaded" && $0.contentType == "application/gzip" }) else { From 5223994b6ddbe9244ef1b3ea899f991e471bc112 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 1 Apr 2023 21:13:42 +0800 Subject: [PATCH 7/8] misc: fix alpha version --- ClashX/AppDelegate.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ClashX/AppDelegate.swift b/ClashX/AppDelegate.swift index d1794d6c0..65b23a113 100644 --- a/ClashX/AppDelegate.swift +++ b/ClashX/AppDelegate.swift @@ -1307,9 +1307,7 @@ extension AppDelegate { @IBAction func updateAlphaMeta(_ sender: NSMenuItem) { sender.isEnabled = false - AlphaMetaDownloader.alphaAsset().get { _ in - self.updateAlphaVersion(nil) - }.then { + AlphaMetaDownloader.alphaAsset().then { AlphaMetaDownloader.checkVersion($0) }.then { AlphaMetaDownloader.downloadCore($0) From b963eb624898869ac2e8225f2e3dbe392168bf4e Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 1 Apr 2023 22:13:59 +0800 Subject: [PATCH 8/8] misc: core logger --- ClashX/AppDelegate.swift | 3 +++ ClashX/General/AlphaMetaDownloader.swift | 2 ++ 2 files changed, 5 insertions(+) diff --git a/ClashX/AppDelegate.swift b/ClashX/AppDelegate.swift index 65b23a113..f6c0b4940 100644 --- a/ClashX/AppDelegate.swift +++ b/ClashX/AppDelegate.swift @@ -626,6 +626,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { return nil } + Logger.log("test core path: \(path)") + Logger.log("-v out: \(out)") + let outs = out .split(separator: "\n") .first { diff --git a/ClashX/General/AlphaMetaDownloader.swift b/ClashX/General/AlphaMetaDownloader.swift index 6d7d39913..52145bc5c 100644 --- a/ClashX/General/AlphaMetaDownloader.swift +++ b/ClashX/General/AlphaMetaDownloader.swift @@ -140,6 +140,8 @@ class AlphaMetaDownloader: NSObject { let cachePath = Paths.tempPath().appending("/\(UUID().uuidString).newcore") try gzData.gunzipped().write(to: .init(fileURLWithPath: cachePath)) + + Logger.log("save alpha core in \(cachePath)") guard let version = ad.testMetaCore(cachePath)?.version else { resolver.reject(errors.testFailed)