From b3a509a4999ae91ae69006814c3560a259b17073 Mon Sep 17 00:00:00 2001 From: yicheng Date: Tue, 6 Nov 2018 21:50:59 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90Feature=E3=80=91add=20remote=20config?= =?UTF-8?q?=20file=20fetcher?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClashX.xcodeproj/project.pbxproj | 4 + ClashX/AppDelegate.swift | 7 ++ ClashX/Base.lproj/Main.storyboard | 19 ++++ ClashX/General/RemoteConfigManager.swift | 112 +++++++++++++++++++++++ ClashX/zh-Hans.lproj/Main.strings | 9 ++ 5 files changed, 151 insertions(+) create mode 100644 ClashX/General/RemoteConfigManager.swift diff --git a/ClashX.xcodeproj/project.pbxproj b/ClashX.xcodeproj/project.pbxproj index 3a64e5b..8f8b64e 100644 --- a/ClashX.xcodeproj/project.pbxproj +++ b/ClashX.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 495A44BF20D2660A00888A0A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 495A44BE20D2660A00888A0A /* AppDelegate.swift */; }; 495A44CD20D266BA00888A0A /* ClashXLaunchHelper.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 495A44BC20D2660A00888A0A /* ClashXLaunchHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 495A44D320D267D000888A0A /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 495A44D220D267D000888A0A /* LaunchAtLogin.swift */; }; + 495BFB8821919B9800C8779D /* RemoteConfigManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 495BFB8721919B9800C8779D /* RemoteConfigManager.swift */; }; 4960A6DB2136529200B940C9 /* JSBridgeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4960A6DA2136529200B940C9 /* JSBridgeHandler.swift */; }; 4966E9E32118153A00A391FB /* NSUserNotificationCenter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4966E9E22118153A00A391FB /* NSUserNotificationCenter+Extension.swift */; }; 4966E9E6211824F300A391FB /* NSImage+extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4966E9E5211824F300A391FB /* NSImage+extension.swift */; }; @@ -125,6 +126,7 @@ 495A44C720D2660B00888A0A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 495A44C820D2660B00888A0A /* ClashXLaunchHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ClashXLaunchHelper.entitlements; sourceTree = ""; }; 495A44D220D267D000888A0A /* LaunchAtLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLogin.swift; sourceTree = ""; }; + 495BFB8721919B9800C8779D /* RemoteConfigManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteConfigManager.swift; sourceTree = ""; }; 4960A6DA2136529200B940C9 /* JSBridgeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSBridgeHandler.swift; sourceTree = ""; }; 4966E9E22118153A00A391FB /* NSUserNotificationCenter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserNotificationCenter+Extension.swift"; sourceTree = ""; }; 4966E9E5211824F300A391FB /* NSImage+extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+extension.swift"; sourceTree = ""; }; @@ -211,6 +213,7 @@ 4949D15C2132614B00EF85E6 /* QRCodeUtil.swift */, 4960A6DA2136529200B940C9 /* JSBridgeHandler.swift */, 4931969A21631E5D00A8E6E7 /* SpeedDataRecorder.swift */, + 495BFB8721919B9800C8779D /* RemoteConfigManager.swift */, ); path = General; sourceTree = ""; @@ -618,6 +621,7 @@ 492C4871210EF62E004554A0 /* ClashConfig.swift in Sources */, 492C4869210EE6B9004554A0 /* ApiRequest.swift in Sources */, 49CF3B6520CEE06C001EBF94 /* ConfigManager.swift in Sources */, + 495BFB8821919B9800C8779D /* RemoteConfigManager.swift in Sources */, 49722FF1211F338B00650A41 /* Witness.swift in Sources */, 49722FF0211F338B00650A41 /* EventStream.swift in Sources */, 4952C3BF2115C7CA004A4FA8 /* ProxyMenuItemFactory.swift in Sources */, diff --git a/ClashX/AppDelegate.swift b/ClashX/AppDelegate.swift index 9feebad..5e2f101 100644 --- a/ClashX/AppDelegate.swift +++ b/ClashX/AppDelegate.swift @@ -420,7 +420,14 @@ class AppDelegate: NSObject, NSApplicationDelegate { NSWorkspace.shared.openFile(Logger.shared.logFilePath()) } + @IBAction func actionSetRemoteConfigUrl(_ sender: Any) { + RemoteConfigManager.showUrlInputAlert() + } + + @IBAction func actionUpdateRemoteConfig(_ sender: Any) { + RemoteConfigManager.updateConfigIfNeed() + } } extension AppDelegate:NSMenuDelegate { diff --git a/ClashX/Base.lproj/Main.storyboard b/ClashX/Base.lproj/Main.storyboard index b56921b..f48b6ec 100644 --- a/ClashX/Base.lproj/Main.storyboard +++ b/ClashX/Base.lproj/Main.storyboard @@ -132,6 +132,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ClashX/General/RemoteConfigManager.swift b/ClashX/General/RemoteConfigManager.swift new file mode 100644 index 0000000..c4789b3 --- /dev/null +++ b/ClashX/General/RemoteConfigManager.swift @@ -0,0 +1,112 @@ +// +// RemoteConfigManager.swift +// ClashX +// +// Created by CYC on 2018/11/6. +// Copyright © 2018 west2online. All rights reserved. +// + +import Cocoa +import Alamofire +import Yams + +class RemoteConfigManager: NSObject { + static var configUrl:String? { + get { + return UserDefaults.standard.string(forKey: "kRemoteConfigUrl") + } + + set { + UserDefaults.standard.set(newValue, forKey: "kRemoteConfigUrl") + } + } + + static func showUrlInputAlert() { + let msg = NSAlert() + msg.addButton(withTitle: "OK") + msg.addButton(withTitle: "Cancel") // 2nd button + msg.messageText = "Remote config" + msg.informativeText = "url:" + + let txt = NSTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 24)) + txt.cell?.usesSingleLineMode = true + txt.stringValue = configUrl ?? "" + msg.accessoryView = txt + let response = msg.runModal() + + if response == .alertFirstButtonReturn { + if URL(string: txt.stringValue) != nil { + configUrl = txt.stringValue + updateConfigIfNeed() + }else { + alert(with: "Url Error") + } + } + } + + static func getRemoteConfigString(handler:@escaping (String?)->()) { + guard let url = configUrl else {alert(with: "Not config url set!");return} + request(url, method: .get).responseString { (res) in + if let s = res.result.value { + handler(s) + } else { + handler(nil) + } + } + } + + static func updateConfigIfNeed() { + getRemoteConfigString { (string) in + guard let newConfigString = string else {alert(with: "Download fail"); return} + if FileManager.default.fileExists(atPath: kConfigFilePath) { + do { + let currentConfigStr = try String(contentsOfFile: kConfigFilePath) + if currentConfigStr == newConfigString { + self.alert(with: "Config not updated") + } else { + guard var originConfig = (try Yams.load(yaml: currentConfigStr)) as? [String:Any] else { throw "Can not parse current config"} + guard let newConfig = try Yams.load(yaml: newConfigString) as? [String:Any] else { throw "Can not parse new config"} + + originConfig["Proxy"] = newConfig["Proxy"] + originConfig["Proxy Group"] = newConfig["Proxy Group"] + originConfig["Rule"] = newConfig["Rule"] + + for (k,v) in originConfig { + if v is NSNull { + originConfig[k] = nil + } + } + + let newConfigStringToWrite = try Yams.dump(object: originConfig) + try FileManager.default.removeItem(atPath: kConfigFilePath) + try newConfigStringToWrite.write(toFile: kConfigFilePath, atomically: true, encoding: .utf8) + NotificationCenter.default.post(Notification(name: kShouldUpDateConfig)) + self.alert(with: "Success!") + } + } catch let err { + self.alert(with: err.localizedDescription) + } + + } else { + do { + try string?.write(toFile: kConfigFilePath, atomically: true, encoding: .utf8) + NotificationCenter.default.post(Notification(name: kShouldUpDateConfig)) + self.alert(with: "Success!") + } catch let err { + self.alert(with: err.localizedDescription) + } + } + } + } + + static func alert(with text:String) { + let alert = NSAlert() + alert.messageText = text + alert.alertStyle = .warning + alert.addButton(withTitle: "OK") + alert.runModal() + } +} + + +extension String: Error {} diff --git a/ClashX/zh-Hans.lproj/Main.strings b/ClashX/zh-Hans.lproj/Main.strings index 91cc232..fdf56ec 100644 --- a/ClashX/zh-Hans.lproj/Main.strings +++ b/ClashX/zh-Hans.lproj/Main.strings @@ -20,6 +20,15 @@ /* Class = "NSMenuItem"; title = "Rule"; ObjectID = "89n-bD-JHk"; */ "89n-bD-JHk.title" = "规则判断"; +/* Class = "NSMenuItem"; title = "Remote config"; ObjectID = "h1C-R6-Y9w"; */ +"h1C-R6-Y9w.title" = "托管配置"; + +/* Class = "NSMenuItem"; title = "Set url"; ObjectID = "k1Z-jQ-kAy"; */ +"k1Z-jQ-kAy.title" = "设置地址"; + +/* Class = "NSMenuItem"; title = "Update"; ObjectID = "I2P-Wd-Ns7"; */ +"I2P-Wd-Ns7.title" = "更新"; + /* Class = "NSMenuItem"; title = "Set as system proxy"; ObjectID = "8se-yr-wmp"; */ "8se-yr-wmp.title" = "设置为系统代理";