Files
ShadowsocksX-NG-R/ShadowsocksX-NG/ServerProfileManager.swift
2017-08-03 12:03:41 +08:00

260 lines
12 KiB
Swift

//
// ServerProfileManager.swift
// ShadowsocksX-NG
//
// Created by 邱宇舟 on 16/6/6. Modified by 秦宇航 17/7/22
// Copyright © 2016年 qiuyuzhou. All rights reserved.
//
import Cocoa
class ServerProfileManager: NSObject {
static let instance:ServerProfileManager = ServerProfileManager()
var profiles:[ServerProfile]
var activeProfileId: String?
fileprivate override init() {
profiles = [ServerProfile]()
let defaults = UserDefaults.standard
activeProfileId = defaults.string(forKey: "ActiveServerProfileId")
var didFindActiveProfileId = false
if let _profiles = defaults.array(forKey: "ServerProfiles") {
for _profile in _profiles {
let profile = ServerProfile.fromDictionary(_profile as! [String : AnyObject])
profiles.append(profile)
if profile.uuid == activeProfileId {
didFindActiveProfileId = true
}
}
}
if profiles.count == 0{
let notice = NSUserNotification()
notice.title = "还没有服务器设定!"
notice.subtitle = "去设置里面填一下吧,填完记得选择呦~"
NSUserNotificationCenter.default.deliver(notice)
return
}
if !didFindActiveProfileId {
activeProfileId = profiles[0].uuid
}
}
func setActiveProfiledId(_ id: String) {
activeProfileId = id
let defaults = UserDefaults.standard
defaults.set(id, forKey: "ActiveServerProfileId")
}
func getActiveProfileId() -> String {
for p in profiles {
if p.uuid == activeProfileId {
return activeProfileId!
}
}
if profiles.count == 0 {return ""}
return profiles[0].uuid
}
func save() {
let defaults = UserDefaults.standard
var _profiles = [AnyObject]()
for profile in profiles {
if profile.isValid() {
let _profile = profile.toDictionary()
_profiles.append(_profile as AnyObject)
}
}
defaults.set(_profiles, forKey: "ServerProfiles")
if getActiveProfile() == nil {
activeProfileId = ""
}
if getActiveProfileId() != "" {
defaults.set(getActiveProfileId(), forKey: "ActiveServerProfileId")
let _ = writeSSLocalConfFile((getActiveProfile()?.toJsonConfig())!)
} else {
defaults.removeObject(forKey: "ActiveServerProfileId")
removeSSLocalConfFile()
}
}
func getActiveProfile() -> ServerProfile? {
if getActiveProfileId() == "" { return nil }
for p in profiles {
if p.uuid == getActiveProfileId() {
return p
}
}
return nil
}
func isExisted(profile: ServerProfile) -> (Bool, Int){
for (index, value) in profiles.enumerated() {
let ret = (value.serverHost == profile.serverHost && value.serverPort == profile.serverPort)
if ret {
return (ret, index)
}
}
return (false, -1)
}
func isDuplicated(profile: ServerProfile) -> (Bool, Int){
for (index, value) in profiles.enumerated() {
let ret = value.serverHost == profile.serverHost
&& value.password == profile.password
&& value.serverPort == profile.serverPort
&& value.ssrProtocol == profile.ssrProtocol
&& value.ssrObfs == profile.ssrObfs
&& value.ssrObfsParam == profile.ssrObfsParam
&& value.ssrProtocolParam == profile.ssrProtocolParam
&& value.remark == profile.remark
if ret {
return (ret, index)
}
}
return (false, -1)
}
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()
openPanel.begin { (result) -> Void in
// TODO not freeze the screen when running import process
if (result == 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"] as! Int))
profile.method = item["method"] as! String
profile.password = item["password"] as! String
profile.remark = item["remarks"] as! String
if(item["group"] != nil){
profile.ssrGroup = item["group"] 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()
}
NotificationCenter.default.post(name: Notification.Name(rawValue: 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 as UInt16), 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")
//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: "protocolparam")
}
}
if profile.ssrGroup != "" {
configProfile.setValue(profile.ssrGroup, forKey: "group")
}
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()
savePanel.begin { (result) -> Void in
if (result == 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)
}
}
}