From ba9aebab4e60bb6795791f3eccc055ae171b4bd3 Mon Sep 17 00:00:00 2001 From: qinyuhang Date: Mon, 12 Sep 2016 15:38:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 代码重构,将导入导出功能移动到ServerProfileManager类下,移除BunchImportUtils.swift --- ShadowsocksX-NG.xcodeproj/project.pbxproj | 4 - ShadowsocksX-NG/AppDelegate.swift | 6 +- ShadowsocksX-NG/BunchImportUtils.swift | 12 +- ShadowsocksX-NG/ServerProfileManager.swift | 131 +++++++++++++++++++++ 4 files changed, 141 insertions(+), 12 deletions(-) diff --git a/ShadowsocksX-NG.xcodeproj/project.pbxproj b/ShadowsocksX-NG.xcodeproj/project.pbxproj index 109aa48..4f450e8 100644 --- a/ShadowsocksX-NG.xcodeproj/project.pbxproj +++ b/ShadowsocksX-NG.xcodeproj/project.pbxproj @@ -13,7 +13,6 @@ 083BF8391D82759600831C68 /* StatusItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 083BF8381D82759600831C68 /* StatusItemView.swift */; }; 083BF83B1D8275A800831C68 /* SystemThemeChangeHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 083BF83A1D8275A800831C68 /* SystemThemeChangeHelper.swift */; }; 0880CE401D6FE6D900BD39E2 /* example-gui-config.json in Resources */ = {isa = PBXBuildFile; fileRef = 0880CE3F1D6FE6D900BD39E2 /* example-gui-config.json */; }; - 0880CE421D6FF7F600BD39E2 /* BunchImportUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0880CE411D6FF7F600BD39E2 /* BunchImportUtils.swift */; }; 088EC3971D5F5B8600E40791 /* whitelist.pac in Resources */ = {isa = PBXBuildFile; fileRef = 088EC3961D5F5B8600E40791 /* whitelist.pac */; }; 088EC3991D5F5BA300E40791 /* whiteiplist.pac in Resources */ = {isa = PBXBuildFile; fileRef = 088EC3981D5F5BA300E40791 /* whiteiplist.pac */; }; 258E511BA910B0521B24DAB8 /* Pods_ShadowsocksX_NG.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 283ED1A8E9B711AC65670031 /* Pods_ShadowsocksX_NG.framework */; }; @@ -106,7 +105,6 @@ 085641E91D7188C400116B27 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; 085641EB1D71A48700116B27 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/MainMenu.strings"; sourceTree = ""; }; 0880CE3F1D6FE6D900BD39E2 /* example-gui-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "example-gui-config.json"; sourceTree = ""; }; - 0880CE411D6FF7F600BD39E2 /* BunchImportUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BunchImportUtils.swift; sourceTree = ""; }; 088EC3961D5F5B8600E40791 /* whitelist.pac */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = whitelist.pac; sourceTree = ""; }; 088EC3981D5F5BA300E40791 /* whiteiplist.pac */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = whiteiplist.pac; sourceTree = ""; }; 08AF56C01D6AFA7C00DC4F46 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/PreferencesWindowController.strings"; sourceTree = ""; }; @@ -312,7 +310,6 @@ 083BF83A1D8275A800831C68 /* SystemThemeChangeHelper.swift */, 9BEEF0771D04FE8A00FC52B3 /* LaunchAgentUtils.swift */, 9B3FFF0C1D05FEB30019A709 /* Utils.swift */, - 0880CE411D6FF7F600BD39E2 /* BunchImportUtils.swift */, 9B3FFF201D08826E0019A709 /* PACUtils.swift */, 083BF8341D82742200831C68 /* NetWorkMonitor.swift */, 083BF8351D82742200831C68 /* PingClient.swift */, @@ -675,7 +672,6 @@ 083BF83B1D8275A800831C68 /* SystemThemeChangeHelper.swift in Sources */, 9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */, 9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */, - 0880CE421D6FF7F600BD39E2 /* BunchImportUtils.swift in Sources */, 9B0BFFE91D0460A70040E62B /* AppDelegate.swift in Sources */, 9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */, 9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */, diff --git a/ShadowsocksX-NG/AppDelegate.swift b/ShadowsocksX-NG/AppDelegate.swift index 947b850..6d671b1 100644 --- a/ShadowsocksX-NG/AppDelegate.swift +++ b/ShadowsocksX-NG/AppDelegate.swift @@ -306,16 +306,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele } @IBAction func showBunchJsonExampleFile(sender: NSMenuItem) { - showExampleConfigFile() + ServerProfileManager.showExampleConfigFile() } @IBAction func importBunchJsonFile(sender: NSMenuItem) { - importConfigFile() + ServerProfileManager.instance.importConfigFile() //updateServersMenu()//not working } @IBAction func exportAllServerProfile(sender: NSMenuItem) { - exportConfigFile() + ServerProfileManager.instance.exportConfigFile() } @IBAction func toggleLaunghAtLogin(sender: NSMenuItem) { diff --git a/ShadowsocksX-NG/BunchImportUtils.swift b/ShadowsocksX-NG/BunchImportUtils.swift index 7e9d3a6..a3df16f 100644 --- a/ShadowsocksX-NG/BunchImportUtils.swift +++ b/ShadowsocksX-NG/BunchImportUtils.swift @@ -8,8 +8,6 @@ import Foundation -var profileMgr: ServerProfileManager! - //Todo: function 1 showExampleFile, 调用fileManager 拷贝 json 到Downloads文件夹,然后打开Downloads文件夹 //拷贝json配置文件到~/Downloads文件夹 @@ -50,8 +48,7 @@ func importConfigFile() { for item in jsonArr1.objectForKey("configs") as! [[String: AnyObject]]{ let profile = ServerProfile() - var profileMgr: ServerProfileManager! - profileMgr = ServerProfileManager.instance + let profileMgr = ServerProfileManager.instance profile.serverHost = item["server"] as! String profile.serverPort = UInt16((item["server_port"]?.integerValue)!) profile.method = item["method"] as! String @@ -91,7 +88,7 @@ func importConfigFile() { func exportConfigFile() { //读取example文件,删掉configs里面的配置,再用NSDictionary填充到configs里面 - profileMgr = ServerProfileManager.instance + let profileMgr = ServerProfileManager.instance let fileManager = NSFileManager.defaultManager() let filePath:String = NSBundle.mainBundle().bundlePath + "/Contents/Resources/example-gui-config.json" @@ -139,6 +136,11 @@ func exportConfigFile() { //write jsonArr1 back to file try! jsonString.writeToFile((savePanel.URL?.path)!, atomically: true, encoding: NSUTF8StringEncoding) NSWorkspace.sharedWorkspace().selectFile((savePanel.URL?.path)!, inFileViewerRootedAtPath: (savePanel.directoryURL?.path)!) + let notification = NSUserNotification() + notification.title = "Export Server Profile succeed!".localized + notification.informativeText = "Successful Export \(profileMgr.profiles.count) items".localized + NSUserNotificationCenter.defaultUserNotificationCenter() + .deliverNotification(notification) } } } diff --git a/ShadowsocksX-NG/ServerProfileManager.swift b/ShadowsocksX-NG/ServerProfileManager.swift index f3be6c8..b368c78 100644 --- a/ShadowsocksX-NG/ServerProfileManager.swift +++ b/ShadowsocksX-NG/ServerProfileManager.swift @@ -70,4 +70,135 @@ class ServerProfileManager: NSObject { 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.becomeKeyWindow() + openPanel.beginWithCompletionHandler { (result) -> Void in + if (result == NSFileHandlingPanelOKButton && (openPanel.URL) != nil) { + let fileManager = NSFileManager.defaultManager() + let filePath:String = (openPanel.URL?.path!)! + if (fileManager.fileExistsAtPath(filePath) && filePath.hasSuffix("json")) { + let data = fileManager.contentsAtPath(filePath) + let readString = NSString(data: data!, encoding: NSUTF8StringEncoding)! + let readStringData = readString.dataUsingEncoding(NSUTF8StringEncoding) + + let jsonArr1 = try! NSJSONSerialization.JSONObjectWithData(readStringData!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary + + for item in jsonArr1.objectForKey("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 + if (item["obfs"] != nil) { + profile.ssrObfs = item["obfs"] as! String + profile.ssrProtocol = item["protocol"] as! String + if (item["obfsparam"] != nil){ + profile.ssrObfsParam = item["obfsparam"] as! String + } + if (item["protocolparam"] != nil){ + profile.ssrProtocolParam = item["protocolparam"] as! String + } + } + self.profiles.append(profile) + self.save() + NSNotificationCenter.defaultCenter().postNotificationName(NOTIFY_SERVER_PROFILES_CHANGED, object: nil) + } + let configsCount = jsonArr1.objectForKey("configs")?.count + let notification = NSUserNotification() + notification.title = "Import Server Profile succeed!".localized + notification.informativeText = "Successful import \(configsCount!) items".localized + NSUserNotificationCenter.defaultUserNotificationCenter() + .deliverNotification(notification) + }else{ + let notification = NSUserNotification() + notification.title = "Import Server Profile failed!".localized + notification.informativeText = "Invalid config file!".localized + NSUserNotificationCenter.defaultUserNotificationCenter() + .deliverNotification(notification) + return + } + } + } + } + + func exportConfigFile() { + //读取example文件,删掉configs里面的配置,再用NSDictionary填充到configs里面 + let fileManager = NSFileManager.defaultManager() + + let filePath:String = NSBundle.mainBundle().bundlePath + "/Contents/Resources/example-gui-config.json" + let data = fileManager.contentsAtPath(filePath) + let readString = NSString(data: data!, encoding: NSUTF8StringEncoding)! + let readStringData = readString.dataUsingEncoding(NSUTF8StringEncoding) + let jsonArr1 = try! NSJSONSerialization.JSONObjectWithData(readStringData!, options: NSJSONReadingOptions.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(unsignedShort: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.dataUsingEncoding(NSUTF8StringEncoding)?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)), forKey: "remarks_base64") + //ssr + if profile.ssrObfs != "" { + configProfile.setValue(profile.ssrObfs, forKey: "obfs") + configProfile.setValue(profile.ssrProtocol, forKey: "protocol") + if profile.ssrObfsParam != "" { + configProfile.setValue(profile.ssrObfsParam, forKey: "obfsparam") + } + if profile.ssrProtocolParam != "" { + configProfile.setValue(profile.ssrProtocolParam, forKey: "protoclparam") + } + } + configsArray.addObject(configProfile) + } + jsonArr1.setValue(configsArray, forKey: "configs") + let jsonData = try! NSJSONSerialization.dataWithJSONObject(jsonArr1, options: NSJSONWritingOptions.PrettyPrinted) + let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)! as String + let savePanel = NSSavePanel() + savePanel.title = "Export Config Json File".localized + savePanel.canCreateDirectories = true + savePanel.allowedFileTypes = ["json"] + savePanel.nameFieldStringValue = "export.json" + savePanel.becomeKeyWindow() + savePanel.beginWithCompletionHandler { (result) -> Void in + if (result == NSFileHandlingPanelOKButton && (savePanel.URL) != nil) { + //write jsonArr1 back to file + try! jsonString.writeToFile((savePanel.URL?.path)!, atomically: true, encoding: NSUTF8StringEncoding) + NSWorkspace.sharedWorkspace().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.defaultUserNotificationCenter() + .deliverNotification(notification) + } + } + } + + class func showExampleConfigFile() { + //copy file to ~/Downloads folder + let filePath:String = NSBundle.mainBundle().bundlePath + "/Contents/Resources/example-gui-config.json" + let fileMgr = NSFileManager.defaultManager() + let dataPath = NSHomeDirectory() + "/Downloads" + let destPath = dataPath + "/example-gui-config.json" + //检测文件是否已经存在,如果存在直接用sharedWorkspace显示 + if fileMgr.fileExistsAtPath(destPath) { + NSWorkspace.sharedWorkspace().selectFile(destPath, inFileViewerRootedAtPath: dataPath) + }else{ + try! fileMgr.copyItemAtPath(filePath, toPath: destPath) + NSWorkspace.sharedWorkspace().selectFile(destPath, inFileViewerRootedAtPath: dataPath) + } + } }