Remove feature Export/Import configure file
.
This commit is contained in:
@ -43,7 +43,6 @@ From [here](https://github.com/shadowsocks/ShadowsocksX-NG/releases/)
|
|||||||
- Support for [AEAD Ciphers](https://shadowsocks.org/en/spec/AEAD-Ciphers.html)
|
- Support for [AEAD Ciphers](https://shadowsocks.org/en/spec/AEAD-Ciphers.html)
|
||||||
- HTTP Proxy by [privoxy](http://www.privoxy.org/)
|
- HTTP Proxy by [privoxy](http://www.privoxy.org/)
|
||||||
- Over [kcptun](https://github.com/xtaci/kcptun). Version 20170322. [Deprecated - Please use kcptun by SIP003 plugin.This would be removed in future.]
|
- Over [kcptun](https://github.com/xtaci/kcptun). Version 20170322. [Deprecated - Please use kcptun by SIP003 plugin.This would be removed in future.]
|
||||||
- Export/Import configure file.
|
|
||||||
- An advanced preferences panel for configuring:
|
- An advanced preferences panel for configuring:
|
||||||
- Local SOCKS5 listen address.
|
- Local SOCKS5 listen address.
|
||||||
- Local SOCKS5 listen port.
|
- Local SOCKS5 listen port.
|
||||||
|
@ -285,19 +285,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
|||||||
ScanQRCodeOnScreen()
|
ScanQRCodeOnScreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func showBunchJsonExampleFile(sender: NSMenuItem) {
|
|
||||||
ServerProfileManager.showExampleConfigFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func importBunchJsonFile(sender: NSMenuItem) {
|
|
||||||
ServerProfileManager.instance.importConfigFile()
|
|
||||||
//updateServersMenu()//not working
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func exportAllServerProfile(sender: NSMenuItem) {
|
|
||||||
ServerProfileManager.instance.exportConfigFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func selectPACMode(_ sender: NSMenuItem) {
|
@IBAction func selectPACMode(_ sender: NSMenuItem) {
|
||||||
let defaults = UserDefaults.standard
|
let defaults = UserDefaults.standard
|
||||||
defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
|
defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14109" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14109"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
@ -72,27 +72,6 @@
|
|||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="4iN-w2-but"/>
|
<menuItem isSeparatorItem="YES" id="4iN-w2-but"/>
|
||||||
<menuItem isSeparatorItem="YES" id="3cf-dF-7dx"/>
|
<menuItem isSeparatorItem="YES" id="3cf-dF-7dx"/>
|
||||||
<menuItem title="Show Bunch Json Example File..." id="pdy-JE-50Q">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="showBunchJsonExampleFileWithSender:" target="Voe-Tx-rLC" id="lMy-Lo-OyB"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Import Bunch Json File..." id="T9g-gy-gvv">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="importBunchJsonFileWithSender:" target="Voe-Tx-rLC" id="bRk-cg-9yn"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Export All Server To Json..." id="6k0-gn-DQv">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="exportAllServerProfileWithSender:" target="Voe-Tx-rLC" id="0ip-dJ-juc"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Scan QR Code From Screen ..." id="Qe6-bF-paT">
|
<menuItem title="Scan QR Code From Screen ..." id="Qe6-bF-paT">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
@ -105,6 +84,9 @@
|
|||||||
<action selector="showQRCodeForCurrentServer:" target="Voe-Tx-rLC" id="t45-Zk-cai"/>
|
<action selector="showQRCodeForCurrentServer:" target="Voe-Tx-rLC" id="t45-Zk-cai"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="vwY-hQ-ZIz"/>
|
<menuItem isSeparatorItem="YES" id="vwY-hQ-ZIz"/>
|
||||||
<menuItem title="Preferences..." keyEquivalent="," id="4CS-qD-zW5">
|
<menuItem title="Preferences..." keyEquivalent="," id="4CS-qD-zW5">
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -62,124 +62,4 @@ class ServerProfileManager: NSObject {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func importConfigFile() {
|
|
||||||
let openPanel = NSOpenPanel()
|
|
||||||
openPanel.title = "Choose Config Json File".localized
|
|
||||||
openPanel.allowsMultipleSelection = false
|
|
||||||
openPanel.canChooseDirectories = false
|
|
||||||
openPanel.canCreateDirectories = false
|
|
||||||
openPanel.canChooseFiles = true
|
|
||||||
openPanel.becomeKey()
|
|
||||||
let result = openPanel.runModal()
|
|
||||||
if (result.rawValue == NSFileHandlingPanelOKButton && (openPanel.url) != nil) {
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let filePath:String = (openPanel.url?.path)!
|
|
||||||
if (fileManager.fileExists(atPath: filePath) && filePath.hasSuffix("json")) {
|
|
||||||
let data = fileManager.contents(atPath: filePath)
|
|
||||||
let readString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)!
|
|
||||||
let readStringData = readString.data(using: String.Encoding.utf8.rawValue)
|
|
||||||
|
|
||||||
let jsonArr1 = try! JSONSerialization.jsonObject(with: readStringData!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
|
|
||||||
|
|
||||||
for item in jsonArr1.object(forKey: "configs") as! [[String: AnyObject]]{
|
|
||||||
let profile = ServerProfile()
|
|
||||||
profile.serverHost = item["server"] as! String
|
|
||||||
profile.serverPort = UInt16((item["server_port"]?.integerValue)!)
|
|
||||||
profile.method = item["method"] as! String
|
|
||||||
profile.password = item["password"] as! String
|
|
||||||
profile.remark = item["remarks"] as! String
|
|
||||||
|
|
||||||
// Kcptun
|
|
||||||
profile.enabledKcptun = item["enabled_kcptun"]?.boolValue ?? false
|
|
||||||
if let kcptun = item["kcptun"] {
|
|
||||||
profile.kcptunProfile = KcptunProfile.fromDictionary(kcptun as! [String : Any?])
|
|
||||||
}
|
|
||||||
|
|
||||||
self.profiles.append(profile)
|
|
||||||
self.save()
|
|
||||||
}
|
|
||||||
NotificationCenter.default.post(name: NOTIFY_SERVER_PROFILES_CHANGED, object: nil)
|
|
||||||
let configsCount = (jsonArr1.object(forKey: "configs") as! [[String: AnyObject]]).count
|
|
||||||
let notification = NSUserNotification()
|
|
||||||
notification.title = "Import Server Profile succeed!".localized
|
|
||||||
notification.informativeText = "Successful import \(configsCount) items".localized
|
|
||||||
NSUserNotificationCenter.default
|
|
||||||
.deliver(notification)
|
|
||||||
}else{
|
|
||||||
let notification = NSUserNotification()
|
|
||||||
notification.title = "Import Server Profile failed!".localized
|
|
||||||
notification.informativeText = "Invalid config file!".localized
|
|
||||||
NSUserNotificationCenter.default
|
|
||||||
.deliver(notification)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func exportConfigFile() {
|
|
||||||
//读取example文件,删掉configs里面的配置,再用NSDictionary填充到configs里面
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
|
|
||||||
let filePath:String = Bundle.main.path(forResource: "example-gui-config", ofType: "json")!
|
|
||||||
let data = fileManager.contents(atPath: filePath)
|
|
||||||
let readString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)!
|
|
||||||
let readStringData = readString.data(using: String.Encoding.utf8.rawValue)
|
|
||||||
let jsonArr1 = try! JSONSerialization.jsonObject(with: readStringData!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
|
|
||||||
|
|
||||||
let configsArray:NSMutableArray = [] //not using var?
|
|
||||||
|
|
||||||
for profile in profiles{
|
|
||||||
let configProfile:NSMutableDictionary = [:] //not using var?
|
|
||||||
//standard ss profile
|
|
||||||
configProfile.setValue(true, forKey: "enable")
|
|
||||||
configProfile.setValue(profile.serverHost, forKey: "server")
|
|
||||||
configProfile.setValue(NSNumber(value:profile.serverPort), forKey: "server_port")//not work
|
|
||||||
configProfile.setValue(profile.password, forKey: "password")
|
|
||||||
configProfile.setValue(profile.method, forKey: "method")
|
|
||||||
configProfile.setValue(profile.remark, forKey: "remarks")
|
|
||||||
configProfile.setValue(profile.remark.data(using: String.Encoding.utf8)?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0)), forKey: "remarks_base64")
|
|
||||||
|
|
||||||
// Kcptun
|
|
||||||
configProfile.setValue(profile.enabledKcptun, forKey: "enabled_kcptun")
|
|
||||||
configProfile.setValue(profile.kcptunProfile.toDictionary(), forKey: "kcptun")
|
|
||||||
|
|
||||||
configsArray.add(configProfile)
|
|
||||||
}
|
|
||||||
jsonArr1.setValue(configsArray, forKey: "configs")
|
|
||||||
let jsonData = try! JSONSerialization.data(withJSONObject: jsonArr1, options: JSONSerialization.WritingOptions.prettyPrinted)
|
|
||||||
let jsonString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)! as String
|
|
||||||
let savePanel = NSSavePanel()
|
|
||||||
savePanel.title = "Export Config Json File".localized
|
|
||||||
savePanel.canCreateDirectories = true
|
|
||||||
savePanel.allowedFileTypes = ["json"]
|
|
||||||
savePanel.nameFieldStringValue = "export.json"
|
|
||||||
savePanel.becomeKey()
|
|
||||||
let result = savePanel.runModal()
|
|
||||||
if (result.rawValue == NSFileHandlingPanelOKButton && (savePanel.url) != nil) {
|
|
||||||
//write jsonArr1 back to file
|
|
||||||
try! jsonString.write(toFile: (savePanel.url?.path)!, atomically: true, encoding: String.Encoding.utf8)
|
|
||||||
NSWorkspace.shared.selectFile((savePanel.url?.path)!, inFileViewerRootedAtPath: (savePanel.directoryURL?.path)!)
|
|
||||||
let notification = NSUserNotification()
|
|
||||||
notification.title = "Export Server Profile succeed!".localized
|
|
||||||
notification.informativeText = "Successful Export \(self.profiles.count) items".localized
|
|
||||||
NSUserNotificationCenter.default
|
|
||||||
.deliver(notification)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class func showExampleConfigFile() {
|
|
||||||
//copy file to ~/Downloads folder
|
|
||||||
let filePath:String = Bundle.main.path(forResource: "example-gui-config", ofType: "json")!
|
|
||||||
let fileMgr = FileManager.default
|
|
||||||
let dataPath = NSHomeDirectory() + "/Downloads"
|
|
||||||
let destPath = dataPath + "/example-gui-config.json"
|
|
||||||
//检测文件是否已经存在,如果存在直接用sharedWorkspace显示
|
|
||||||
if fileMgr.fileExists(atPath: destPath) {
|
|
||||||
NSWorkspace.shared.selectFile(destPath, inFileViewerRootedAtPath: dataPath)
|
|
||||||
}else{
|
|
||||||
try! fileMgr.copyItem(atPath: filePath, toPath: destPath)
|
|
||||||
NSWorkspace.shared.selectFile(destPath, inFileViewerRootedAtPath: dataPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user