【Feature】add remote config file fetcher

This commit is contained in:
yicheng 2018-11-06 21:50:59 +08:00
parent 45c73cd80c
commit b3a509a499
5 changed files with 151 additions and 0 deletions

View File

@ -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 = "<group>"; };
495A44C820D2660B00888A0A /* ClashXLaunchHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ClashXLaunchHelper.entitlements; sourceTree = "<group>"; };
495A44D220D267D000888A0A /* LaunchAtLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLogin.swift; sourceTree = "<group>"; };
495BFB8721919B9800C8779D /* RemoteConfigManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteConfigManager.swift; sourceTree = "<group>"; };
4960A6DA2136529200B940C9 /* JSBridgeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSBridgeHandler.swift; sourceTree = "<group>"; };
4966E9E22118153A00A391FB /* NSUserNotificationCenter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserNotificationCenter+Extension.swift"; sourceTree = "<group>"; };
4966E9E5211824F300A391FB /* NSImage+extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+extension.swift"; sourceTree = "<group>"; };
@ -211,6 +213,7 @@
4949D15C2132614B00EF85E6 /* QRCodeUtil.swift */,
4960A6DA2136529200B940C9 /* JSBridgeHandler.swift */,
4931969A21631E5D00A8E6E7 /* SpeedDataRecorder.swift */,
495BFB8721919B9800C8779D /* RemoteConfigManager.swift */,
);
path = General;
sourceTree = "<group>";
@ -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 */,

View File

@ -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 {

View File

@ -132,6 +132,25 @@
</items>
</menu>
</menuItem>
<menuItem title="Remote Config" id="h1C-R6-Y9w">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Remote Config" id="az2-wz-yyy">
<items>
<menuItem title="Set Url" id="k1Z-jQ-kAy">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="actionSetRemoteConfigUrl:" target="Voe-Tx-rLC" id="ZSD-Pg-4xP"/>
</connections>
</menuItem>
<menuItem title="Update" id="I2P-Wd-Ns7">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="actionUpdateRemoteConfig:" target="Voe-Tx-rLC" id="umk-nZ-asT"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Open config Folder" keyEquivalent="o" id="DwE-WX-ETZ">
<connections>
<action selector="openConfigFolder:" target="Voe-Tx-rLC" id="6Ke-Bi-AAZ"/>

View File

@ -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 {}

View File

@ -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" = "设置为系统代理";