Skip to content

Commit

Permalink
feat: add basic iCloud support
Browse files Browse the repository at this point in the history
  • Loading branch information
yichengchen committed May 23, 2020
1 parent d7ba907 commit 0461db8
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 71 deletions.
6 changes: 6 additions & 0 deletions ClashX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
49B445162457CDF000B27E3E /* ClashStatusTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49B445152457CDF000B27E3E /* ClashStatusTool.swift */; };
49B4575D244F4A2A00463C39 /* PrivilegedHelperManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49B4575C244F4A2A00463C39 /* PrivilegedHelperManager.swift */; };
49B4575F244FD4D100463C39 /* PrivilegedHelperManager+Legacy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49B4575E244FD4D100463C39 /* PrivilegedHelperManager+Legacy.swift */; };
49BB31E7246853EA008A4CB0 /* iCloudManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BB31E6246853EA008A4CB0 /* iCloudManager.swift */; };
49BC061C212931F4005A0FE7 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BC061B212931F4005A0FE7 /* AboutViewController.swift */; };
49C9EF64223E78F5005D8B6A /* ClashProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C9EF63223E78F5005D8B6A /* ClashProxy.swift */; };
49CF3B2120CD7463001EBF94 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49CF3B2020CD7463001EBF94 /* AppDelegate.swift */; };
Expand Down Expand Up @@ -159,6 +160,7 @@
49B445152457CDF000B27E3E /* ClashStatusTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashStatusTool.swift; sourceTree = "<group>"; };
49B4575C244F4A2A00463C39 /* PrivilegedHelperManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivilegedHelperManager.swift; sourceTree = "<group>"; };
49B4575E244FD4D100463C39 /* PrivilegedHelperManager+Legacy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PrivilegedHelperManager+Legacy.swift"; sourceTree = "<group>"; };
49BB31E6246853EA008A4CB0 /* iCloudManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iCloudManager.swift; sourceTree = "<group>"; };
49BC061B212931F4005A0FE7 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
49C9EF63223E78F5005D8B6A /* ClashProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashProxy.swift; sourceTree = "<group>"; };
49CF3B1D20CD7463001EBF94 /* ClashX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ClashX.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -275,6 +277,7 @@
F9E754CF239CC21F00CEE7CC /* WebPortalManager.swift */,
49B4575C244F4A2A00463C39 /* PrivilegedHelperManager.swift */,
49B4575E244FD4D100463C39 /* PrivilegedHelperManager+Legacy.swift */,
49BB31E6246853EA008A4CB0 /* iCloudManager.swift */,
);
path = Managers;
sourceTree = "<group>";
Expand Down Expand Up @@ -698,6 +701,7 @@
F976275C23634DF8000EDEFE /* LoginServiceKit.swift in Sources */,
4966E9E6211824F300A391FB /* NSImage+extension.swift in Sources */,
F92D0B2E236D35C000575E15 /* ProxyItemView.swift in Sources */,
49BB31E7246853EA008A4CB0 /* iCloudManager.swift in Sources */,
49B1086A216A356D0064FFCE /* String+Extension.swift in Sources */,
F92D0B2C236C7C3600575E15 /* MenuItemBaseView.swift in Sources */,
4960A6DB2136529200B940C9 /* JSBridgeHandler.swift in Sources */,
Expand Down Expand Up @@ -873,6 +877,7 @@
baseConfigurationReference = 5217C006C5A22A1CEA24BFC1 /* Pods-ClashX.debug.xcconfig */;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = ClashX/ClashX.entitlements;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
Expand Down Expand Up @@ -914,6 +919,7 @@
baseConfigurationReference = A1485BCE642059532D01B8BA /* Pods-ClashX.release.xcconfig */;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = ClashX/ClashX.entitlements;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
Expand Down
18 changes: 11 additions & 7 deletions ClashX/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
statusItemView.frame = CGRect(x: 0, y: 0, width: statusItemLengthWithSpeed, height: 22)
statusMenu.delegate = self
setupStatusMenuItemData()

DispatchQueue.main.async {
self.postFinishLaunching()
}
Expand All @@ -83,6 +82,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
defer {
statusItem.menu = statusMenu
}
iCloudManager.shared.setup()
setupExperimentalMenuItem()

// install proxy helper
Expand Down Expand Up @@ -323,12 +323,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {

func updateConfigFiles() {
guard let menu = configSeparatorLine.menu else { return }
let lineIndex = menu.items.firstIndex(of: configSeparatorLine)!
for _ in 0..<lineIndex {
menu.removeItem(at: 0)
}
for item in MenuItemFactory.generateSwitchConfigMenuItems().reversed() {
menu.insertItem(item, at: 0)
MenuItemFactory.generateSwitchConfigMenuItems {
items in
let lineIndex = menu.items.firstIndex(of: self.configSeparatorLine)!
for _ in 0..<lineIndex {
menu.removeItem(at: 0)
}
for item in items.reversed() {
menu.insertItem(item, at: 0)
}
}
}

Expand Down Expand Up @@ -432,6 +435,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
if WebPortalManager.hasWebProtal {
WebPortalManager.shared.addWebProtalMenuItem(&statusMenu)
}
iCloudManager.shared.addEnableMenuItem(&experimentalMenu)
AutoUpgardeManager.shared.setup()
AutoUpgardeManager.shared.addChanelMenuItem(&experimentalMenu)
updateExperimentalFeatureStatus()
Expand Down
25 changes: 22 additions & 3 deletions ClashX/General/ApiRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,35 @@ class ApiRequest {
}

static func requestConfigUpdate(configName: String, callback: @escaping ((ErrorString?) -> Void)) {
let filePath = Paths.configPath(for: configName)
if iCloudManager.shared.isICloudEnable() {
iCloudManager.shared.getUrl { url in
guard let url = url else {
callback("icloud error")
return
}
let configPath = url.appendingPathComponent(Paths.configFileName(for: configName)).path
requestConfigUpdate(configPath: configPath, callback: callback)
}
} else {
let filePath = Paths.localConfigPath(for: configName)
requestConfigUpdate(configPath: filePath, callback: callback)
}

}

static func requestConfigUpdate(configPath: String, callback: @escaping ((ErrorString?) -> Void)) {
let placeHolderErrorDesp = "Error occoured, Please try to fix it by restarting ClashX. "

// DEV MODE: Use API
if !ConfigManager.builtInApiMode {
req("/configs", method: .put, parameters: ["Path": filePath], encoding: JSONEncoding.default).responseJSON { res in
req("/configs", method: .put, parameters: ["Path": configPath], encoding: JSONEncoding.default).responseJSON { res in
if res.response?.statusCode == 204 {
ConfigManager.shared.isRunning = true
callback(nil)
} else {
let errorJson = try? res.result.get()
let err = JSON(errorJson ?? "")["message"].string ?? placeHolderErrorDesp
Logger.log(err)
callback(err)
}
}
Expand All @@ -116,11 +133,12 @@ class ApiRequest {

// NORMAL MODE: Use internal api
clashRequestQueue.async {
let res = clashUpdateConfig(filePath.goStringBuffer())?.toString() ?? placeHolderErrorDesp
let res = clashUpdateConfig(configPath.goStringBuffer())?.toString() ?? placeHolderErrorDesp
DispatchQueue.main.async {
if res == "success" {
callback(nil)
} else {
Logger.log(res)
callback(res)
}
}
Expand Down Expand Up @@ -174,6 +192,7 @@ class ApiRequest {
}

static func updateAllowLan(allow: Bool, completeHandler: (() -> Void)? = nil) {
Logger.log("update allow lan:\(allow)", level: .debug)
req("/configs",
method: .patch,
parameters: ["allow-lan": allow],
Expand Down
7 changes: 6 additions & 1 deletion ClashX/General/Managers/ConfigFileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ConfigFileManager {
}

func watchConfigFile(configName: String) {
let path = Paths.configPath(for: configName)
let path = Paths.localConfigPath(for: configName)
witness = Witness(paths: [path], flags: .FileEvents, latency: 0.3) {
[weak self] events in
guard let self = self else { return }
Expand All @@ -39,6 +39,11 @@ class ConfigFileManager {
}
}
}

func stopWatchConfigFile() {
witness = nil
pause = false
}

@discardableResult
static func backupAndRemoveConfigFile() -> Bool {
Expand Down
6 changes: 5 additions & 1 deletion ClashX/General/Managers/ConfigManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ class ConfigManager {
}
set {
UserDefaults.standard.set(newValue, forKey: "selectConfigName")
ConfigFileManager.shared.watchConfigFile(configName: newValue)
if iCloudManager.shared.isICloudEnable() {
iCloudManager.shared.watchConfigFile(name: newValue)
} else {
ConfigFileManager.shared.watchConfigFile(configName: newValue)
}
}
}

Expand Down
17 changes: 12 additions & 5 deletions ClashX/General/Managers/MenuItemFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,22 @@ class MenuItemFactory {
updateProxyList(withMenus: items)
}

static func generateSwitchConfigMenuItems() -> [NSMenuItem] {
var items = [NSMenuItem]()
for config in ConfigManager.getConfigFilesList() {
static func generateSwitchConfigMenuItems(complete: @escaping (([NSMenuItem]) -> Void)) {
let generateMenuItem: ((String) -> NSMenuItem) = {
config in
let item = NSMenuItem(title: config, action: #selector(MenuItemFactory.actionSelectConfig(sender:)), keyEquivalent: "")
item.target = MenuItemFactory.self
item.state = ConfigManager.selectConfigName == config ? .on : .off
items.append(item)
return item
}

if iCloudManager.shared.isICloudEnable() {
iCloudManager.shared.getConfigFilesList {
complete($0.map { generateMenuItem($0) })
}
} else {
complete(ConfigManager.getConfigFilesList().map { generateMenuItem($0) })
}
return items
}

// MARK: - Private
Expand Down
36 changes: 26 additions & 10 deletions ClashX/General/Managers/RemoteConfigManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,23 +172,39 @@ class RemoteConfigManager {
}
config.isPlaceHolderName = false

let savePath = Paths.configPath(for: config.name)

if config.name == ConfigManager.selectConfigName {
if iCloudManager.shared.isICloudEnable() {
ConfigFileManager.shared.stopWatchConfigFile()
} else if config.name == ConfigManager.selectConfigName {
ConfigFileManager.shared.pauseForNextChange()
}

do {
if FileManager.default.fileExists(atPath: savePath) {
try FileManager.default.removeItem(atPath: savePath)

let saveAction:((String)->Void) = {
savePath in
do {
if FileManager.default.fileExists(atPath: savePath) {
try FileManager.default.removeItem(atPath: savePath)
}
try newConfig.write(to: URL(fileURLWithPath: savePath), atomically: true, encoding: .utf8)
complete?(nil)
} catch let err {
complete?(err.localizedDescription)
}
try newConfig.write(to: URL(fileURLWithPath: savePath), atomically: true, encoding: .utf8)
complete?(nil)
} catch let err {
complete?(err.localizedDescription)
}

if iCloudManager.shared.isICloudEnable() {
iCloudManager.shared.getUrl { url in
guard let url = url else {return}
let saveUrl = url.appendingPathComponent(Paths.configFileName(for: config.name))
saveAction(saveUrl.path)
}
} else {
let savePath = Paths.localConfigPath(for: config.name)
saveAction(savePath)
}
}
}


static func verifyConfig(string: String) -> ErrorString? {
let res = verifyClashConfig(string.goStringBuffer())?.toString() ?? "unknown error"
Expand Down
Loading

0 comments on commit 0461db8

Please sign in to comment.