2018-06-13 10:44:30 +08:00
|
|
|
//
|
|
|
|
// AppDelegate.swift
|
|
|
|
// ClashX
|
|
|
|
//
|
2018-08-08 13:47:38 +08:00
|
|
|
// Created by CYC on 2018/6/10.
|
|
|
|
// Copyright © 2018年 yichengchen. All rights reserved.
|
2018-06-13 10:44:30 +08:00
|
|
|
//
|
|
|
|
|
2019-10-20 13:40:50 +08:00
|
|
|
import Alamofire
|
2018-06-13 10:44:30 +08:00
|
|
|
import Cocoa
|
2018-06-23 14:37:00 +08:00
|
|
|
import LetsMove
|
2018-08-04 14:33:47 +08:00
|
|
|
import RxCocoa
|
|
|
|
import RxSwift
|
2018-06-14 12:56:07 +08:00
|
|
|
|
2018-12-09 00:06:43 +08:00
|
|
|
import Crashlytics
|
2019-10-20 13:40:50 +08:00
|
|
|
import Fabric
|
2018-12-09 00:06:43 +08:00
|
|
|
|
2019-10-20 13:40:50 +08:00
|
|
|
private let statusItemLengthWithSpeed: CGFloat = 70
|
2019-05-11 11:49:57 +08:00
|
|
|
|
2018-06-13 10:44:30 +08:00
|
|
|
@NSApplicationMain
|
|
|
|
class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
|
var statusItem: NSStatusItem!
|
2019-10-20 13:40:50 +08:00
|
|
|
|
|
|
|
@IBOutlet var statusMenu: NSMenu!
|
|
|
|
@IBOutlet var proxySettingMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var autoStartMenuItem: NSMenuItem!
|
|
|
|
|
|
|
|
@IBOutlet var proxyModeGlobalMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var proxyModeDirectMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var proxyModeRuleMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var allowFromLanMenuItem: NSMenuItem!
|
|
|
|
|
|
|
|
@IBOutlet var proxyModeMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var showNetSpeedIndicatorMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var dashboardMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var separatorLineTop: NSMenuItem!
|
|
|
|
@IBOutlet var sepatatorLineEndProxySelect: NSMenuItem!
|
|
|
|
@IBOutlet var configSeparatorLine: NSMenuItem!
|
|
|
|
@IBOutlet var logLevelMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var httpPortMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var socksPortMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var apiPortMenuItem: NSMenuItem!
|
2019-11-30 19:29:57 +08:00
|
|
|
@IBOutlet var ipMenuItem: NSMenuItem!
|
2019-10-20 13:40:50 +08:00
|
|
|
@IBOutlet var remoteConfigAutoupdateMenuItem: NSMenuItem!
|
|
|
|
@IBOutlet var buildApiModeMenuitem: NSMenuItem!
|
|
|
|
@IBOutlet var showProxyGroupCurrentMenuItem: NSMenuItem!
|
2019-10-25 22:22:07 +08:00
|
|
|
@IBOutlet var copyExportCommandMenuItem: NSMenuItem!
|
2019-10-28 10:48:22 +08:00
|
|
|
@IBOutlet var experimentalMenu: NSMenu!
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-04 16:30:10 +08:00
|
|
|
var disposeBag = DisposeBag()
|
2019-10-20 13:40:50 +08:00
|
|
|
var statusItemView: StatusItemView!
|
2019-02-19 09:45:23 +08:00
|
|
|
var isSpeedTesting = false
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2020-02-05 21:45:11 +08:00
|
|
|
lazy var dashboardWindowController: NSWindowController = ClashWindowController.create()
|
|
|
|
|
2018-10-09 22:07:44 +08:00
|
|
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
2018-06-14 12:56:07 +08:00
|
|
|
signal(SIGPIPE, SIG_IGN)
|
2019-10-15 22:40:02 +08:00
|
|
|
checkOnlyOneClashX()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 00:06:43 +08:00
|
|
|
// setup menu item first
|
2019-10-20 13:40:50 +08:00
|
|
|
statusItem = NSStatusBar.system.statusItem(withLength: statusItemLengthWithSpeed)
|
2018-12-09 00:06:43 +08:00
|
|
|
statusItem.menu = statusMenu
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 00:06:43 +08:00
|
|
|
statusItemView = StatusItemView.create(statusItem: statusItem)
|
2019-05-11 11:49:57 +08:00
|
|
|
statusItemView.frame = CGRect(x: 0, y: 0, width: statusItemLengthWithSpeed, height: 22)
|
2018-12-09 00:06:43 +08:00
|
|
|
statusMenu.delegate = self
|
2019-10-28 10:48:22 +08:00
|
|
|
setupExperimentalMenuItem()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 00:06:43 +08:00
|
|
|
// crash recorder
|
2018-08-12 18:03:55 +08:00
|
|
|
failLaunchProtect()
|
2018-10-27 12:59:46 +08:00
|
|
|
registCrashLogger()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-21 22:52:50 +08:00
|
|
|
// install proxy helper
|
2019-08-17 13:47:43 +08:00
|
|
|
_ = ClashResourceManager.check()
|
|
|
|
SystemProxyManager.shared.checkInstall()
|
2018-12-09 22:00:15 +08:00
|
|
|
ConfigFileManager.copySampleConfigIfNeed()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-10-14 23:42:53 +08:00
|
|
|
PFMoveToApplicationsFolderIfNecessary()
|
2019-11-02 11:55:18 +08:00
|
|
|
|
2019-11-01 20:47:55 +08:00
|
|
|
// claer not existed selected model
|
|
|
|
removeUnExistProxyGroups()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 00:06:43 +08:00
|
|
|
// start proxy
|
2018-08-04 16:30:10 +08:00
|
|
|
setupData()
|
2019-08-18 13:23:28 +08:00
|
|
|
updateConfig(showNotification: false)
|
2018-08-26 13:25:29 +08:00
|
|
|
updateLoggingLevel()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-07-28 17:37:59 +08:00
|
|
|
// start watch config file change
|
|
|
|
ConfigFileManager.shared.watchConfigFile(configName: ConfigManager.selectConfigName)
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-07-28 17:08:10 +08:00
|
|
|
RemoteConfigManager.shared.autoUpdateCheck()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
NSAppleEventManager.shared()
|
|
|
|
.setEventHandler(self,
|
|
|
|
andSelector: #selector(handleURL(event:reply:)),
|
|
|
|
forEventClass: AEEventClass(kInternetEventClass),
|
|
|
|
andEventID: AEEventID(kAEGetURL))
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-15 22:40:02 +08:00
|
|
|
setupNetworkNotifier()
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-06-13 10:44:30 +08:00
|
|
|
func applicationWillTerminate(_ aNotification: Notification) {
|
2019-10-20 00:10:27 +08:00
|
|
|
if ConfigManager.shared.proxyPortAutoSet && !ConfigManager.shared.isProxySetByOtherVariable.value {
|
2019-08-18 11:20:11 +08:00
|
|
|
let port = ConfigManager.shared.currentConfig?.port ?? 0
|
|
|
|
let socketPort = ConfigManager.shared.currentConfig?.socketPort ?? 0
|
|
|
|
SystemProxyManager.shared.disableProxy(port: port, socksPort: socketPort)
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-11-09 11:50:51 +08:00
|
|
|
UserDefaults.standard.set(0, forKey: "launch_fail_times")
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-04 16:30:10 +08:00
|
|
|
func setupData() {
|
2019-04-08 15:45:20 +08:00
|
|
|
remoteConfigAutoupdateMenuItem.state = RemoteConfigManager.autoUpdateEnable ? .on : .off
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-05 01:17:27 +08:00
|
|
|
ConfigManager.shared
|
|
|
|
.showNetSpeedIndicatorObservable
|
2019-10-20 13:40:50 +08:00
|
|
|
.bind { [weak self] show in
|
|
|
|
guard let self = self else { return }
|
2018-08-06 16:54:41 +08:00
|
|
|
self.showNetSpeedIndicatorMenuItem.state = (show ?? true) ? .on : .off
|
2019-10-20 13:40:50 +08:00
|
|
|
let statusItemLength: CGFloat = (show ?? true) ? statusItemLengthWithSpeed : 25
|
2018-10-08 23:08:08 +08:00
|
|
|
self.statusItem.length = statusItemLength
|
2018-11-04 00:36:24 +08:00
|
|
|
self.statusItemView.frame.size.width = statusItemLength
|
2019-10-20 13:40:50 +08:00
|
|
|
self.statusItemView.showSpeedContainer(show: show ?? true)
|
2018-11-03 15:53:44 +08:00
|
|
|
self.statusItemView.updateStatusItemView()
|
2019-10-20 13:40:50 +08:00
|
|
|
}.disposed(by: disposeBag)
|
|
|
|
|
2019-10-15 22:40:02 +08:00
|
|
|
Observable
|
|
|
|
.merge([ConfigManager.shared.proxyPortAutoSetObservable,
|
|
|
|
ConfigManager.shared.isProxySetByOtherVariable.asObservable()])
|
|
|
|
.map { _ -> NSControl.StateValue in
|
2019-10-20 13:40:50 +08:00
|
|
|
if ConfigManager.shared.isProxySetByOtherVariable.value && ConfigManager.shared.proxyPortAutoSet {
|
2019-10-15 22:40:02 +08:00
|
|
|
return .mixed
|
|
|
|
}
|
|
|
|
return ConfigManager.shared.proxyPortAutoSet ? .on : .off
|
2019-10-20 13:40:50 +08:00
|
|
|
}.distinctUntilChanged()
|
2019-10-15 22:40:02 +08:00
|
|
|
.bind { [weak self] status in
|
2019-10-20 13:40:50 +08:00
|
|
|
guard let self = self else { return }
|
2019-10-15 22:40:02 +08:00
|
|
|
self.proxySettingMenuItem.state = status
|
|
|
|
self.statusItemView.updateViewStatus(enableProxy: status == .on)
|
2019-10-20 13:40:50 +08:00
|
|
|
}.disposed(by: disposeBag)
|
|
|
|
|
2018-08-19 11:30:03 +08:00
|
|
|
let configObservable = ConfigManager.shared
|
2018-08-05 01:17:27 +08:00
|
|
|
.currentConfigVariable
|
2018-08-04 16:30:10 +08:00
|
|
|
.asObservable()
|
2019-10-20 13:40:50 +08:00
|
|
|
Observable.zip(configObservable, configObservable.skip(1))
|
|
|
|
.filter { _, new in return new != nil }
|
|
|
|
.bind { [weak self] old, config in
|
|
|
|
guard let self = self, let config = config else { return }
|
2018-08-04 16:30:10 +08:00
|
|
|
self.proxyModeDirectMenuItem.state = .off
|
|
|
|
self.proxyModeGlobalMenuItem.state = .off
|
|
|
|
self.proxyModeRuleMenuItem.state = .off
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-01 21:42:21 +08:00
|
|
|
switch config.mode {
|
2019-10-20 13:40:50 +08:00
|
|
|
case .direct: self.proxyModeDirectMenuItem.state = .on
|
|
|
|
case .global: self.proxyModeGlobalMenuItem.state = .on
|
|
|
|
case .rule: self.proxyModeRuleMenuItem.state = .on
|
2018-08-04 16:30:10 +08:00
|
|
|
}
|
2018-12-01 21:42:21 +08:00
|
|
|
self.allowFromLanMenuItem.state = config.allowLan ? .on : .off
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-07-28 12:39:49 +08:00
|
|
|
self.proxyModeMenuItem.title = "\(NSLocalizedString("Proxy Mode", comment: "")) (\(config.mode.name))"
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-04 23:41:28 +08:00
|
|
|
self.updateProxyList()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
|
|
|
if old?.port != config.port && ConfigManager.shared.proxyPortAutoSet {
|
2019-08-17 13:47:43 +08:00
|
|
|
SystemProxyManager.shared.enableProxy(port: config.port, socksPort: config.socketPort)
|
2018-08-06 23:06:50 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-11-30 19:29:57 +08:00
|
|
|
self.httpPortMenuItem.title = "Http Port: \(config.port)"
|
|
|
|
self.socksPortMenuItem.title = "Socks Port: \(config.socketPort)"
|
|
|
|
self.apiPortMenuItem.title = "Api Port: \(ConfigManager.shared.apiPort)"
|
|
|
|
self.ipMenuItem.title = "IP: \(NetworkChangeNotifier.getPrimaryIPAddress() ?? "")"
|
|
|
|
|
|
|
|
if config.port == 0 || config.socketPort == 0 {
|
|
|
|
self.showClashPortErrorAlert()
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
|
|
|
}.disposed(by: disposeBag)
|
|
|
|
|
2018-10-20 13:53:01 +08:00
|
|
|
ConfigManager
|
|
|
|
.shared
|
|
|
|
.isRunningVariable
|
|
|
|
.asObservable()
|
|
|
|
.distinctUntilChanged()
|
2018-12-22 21:00:54 +08:00
|
|
|
.bind { [weak self] _ in
|
2019-10-20 13:40:50 +08:00
|
|
|
guard let self = self else { return }
|
2018-10-20 13:53:01 +08:00
|
|
|
self.updateProxyList()
|
2019-10-20 13:40:50 +08:00
|
|
|
}.disposed(by: disposeBag)
|
|
|
|
|
2018-08-05 01:17:27 +08:00
|
|
|
LaunchAtLogin.shared
|
|
|
|
.isEnableVirable
|
2018-08-04 16:30:10 +08:00
|
|
|
.asObservable()
|
2019-03-24 13:59:12 +08:00
|
|
|
.subscribe(onNext: { [weak self] enable in
|
2019-10-20 13:40:50 +08:00
|
|
|
guard let self = self else { return }
|
2018-08-04 16:30:10 +08:00
|
|
|
self.autoStartMenuItem.state = enable ? .on : .off
|
|
|
|
}).disposed(by: disposeBag)
|
2019-10-15 22:40:02 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-15 22:40:02 +08:00
|
|
|
func checkOnlyOneClashX() {
|
|
|
|
if NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.bundleIdentifier ?? "").count > 1 {
|
|
|
|
assertionFailure()
|
|
|
|
NSApp.terminate(nil)
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-15 22:40:02 +08:00
|
|
|
func setupNetworkNotifier() {
|
2020-02-05 21:45:11 +08:00
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
|
|
Thread {
|
|
|
|
NetworkChangeNotifier.start()
|
|
|
|
}.start()
|
2019-10-15 22:40:02 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-15 22:40:02 +08:00
|
|
|
NotificationCenter
|
|
|
|
.default
|
|
|
|
.rx
|
|
|
|
.notification(kSystemNetworkStatusDidChange)
|
|
|
|
.observeOn(MainScheduler.instance)
|
2019-12-10 17:19:07 +08:00
|
|
|
.delay(.milliseconds(200), scheduler: MainScheduler.instance)
|
2019-10-20 13:40:50 +08:00
|
|
|
.bind { _ in
|
2019-11-21 22:54:07 +08:00
|
|
|
guard NetworkChangeNotifier.getPrimaryInterface() != nil else { return }
|
2019-10-22 21:56:56 +08:00
|
|
|
let (http, https, socks) = NetworkChangeNotifier.currentSystemProxySetting()
|
|
|
|
let currentPort = ConfigManager.shared.currentConfig?.port ?? 0
|
|
|
|
let currentSocks = ConfigManager.shared.currentConfig?.socketPort ?? 0
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-15 22:40:02 +08:00
|
|
|
let proxySetted = http == currentPort && https == currentPort && socks == currentSocks
|
|
|
|
ConfigManager.shared.isProxySetByOtherVariable.accept(!proxySetted)
|
2019-10-20 13:40:50 +08:00
|
|
|
}.disposed(by: disposeBag)
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-04 22:09:11 +08:00
|
|
|
func updateProxyList() {
|
2018-10-20 13:53:01 +08:00
|
|
|
if ConfigManager.shared.isRunning {
|
2019-10-20 13:40:50 +08:00
|
|
|
MenuItemFactory.menuItems { [weak self] items in
|
2019-10-09 20:33:57 +08:00
|
|
|
self?.updateProxyList(withMenus: items)
|
|
|
|
}
|
2018-10-20 13:53:01 +08:00
|
|
|
} else {
|
|
|
|
updateProxyList(withMenus: [])
|
|
|
|
}
|
2018-11-30 22:14:20 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
|
|
|
func updateProxyList(withMenus menus: [NSMenuItem]) {
|
|
|
|
let startIndex = statusMenu.items.firstIndex(of: separatorLineTop)! + 1
|
|
|
|
let endIndex = statusMenu.items.firstIndex(of: sepatatorLineEndProxySelect)!
|
2019-10-20 00:10:27 +08:00
|
|
|
sepatatorLineEndProxySelect.isHidden = menus.count == 0
|
2019-10-20 13:40:50 +08:00
|
|
|
for _ in 0..<endIndex - startIndex {
|
2019-10-20 00:10:27 +08:00
|
|
|
statusMenu.removeItem(at: startIndex)
|
2019-03-24 13:59:12 +08:00
|
|
|
}
|
2019-10-20 00:10:27 +08:00
|
|
|
for each in menus {
|
|
|
|
statusMenu.insertItem(each, at: startIndex)
|
2019-03-24 13:59:12 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-11-30 22:14:20 +08:00
|
|
|
func updateConfigFiles() {
|
2019-10-20 13:40:50 +08:00
|
|
|
guard let menu = configSeparatorLine.menu else { return }
|
2019-10-20 00:10:27 +08:00
|
|
|
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)
|
|
|
|
}
|
2018-08-04 21:49:32 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-12 11:29:51 +08:00
|
|
|
func updateLoggingLevel() {
|
2019-10-20 13:28:40 +08:00
|
|
|
ApiRequest.updateLogLevel(level: ConfigManager.selectLoggingApiLevel)
|
2019-10-20 13:40:50 +08:00
|
|
|
for item in logLevelMenuItem.submenu?.items ?? [] {
|
2018-08-12 11:29:51 +08:00
|
|
|
item.state = item.title.lowercased() == ConfigManager.selectLoggingApiLevel.rawValue ? .on : .off
|
|
|
|
}
|
2019-12-29 14:48:39 +08:00
|
|
|
NotificationCenter.default.post(name: kReloadDashboard, object: nil)
|
2018-08-12 11:29:51 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-06-13 10:44:30 +08:00
|
|
|
func startProxy() {
|
2019-10-20 13:40:50 +08:00
|
|
|
if ConfigManager.shared.isRunning { return }
|
|
|
|
|
2019-10-02 21:43:18 +08:00
|
|
|
struct StartProxyResp: Codable {
|
|
|
|
let externalController: String
|
|
|
|
let secret: String
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-21 10:18:01 +08:00
|
|
|
// setup ui config first
|
2019-01-13 10:27:44 +08:00
|
|
|
if let htmlPath = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "dashboard") {
|
|
|
|
let uiPath = URL(fileURLWithPath: htmlPath).deletingLastPathComponent().path
|
2019-10-02 21:43:18 +08:00
|
|
|
setUIPath(uiPath.goStringBuffer())
|
2018-12-21 10:18:01 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-29 21:28:43 +08:00
|
|
|
Logger.log("Trying start proxy")
|
2019-10-13 22:42:25 +08:00
|
|
|
let string = run(ConfigManager.builtInApiMode.goObject())?.toString() ?? ""
|
2019-10-02 21:43:18 +08:00
|
|
|
let jsonData = string.data(using: .utf8) ?? Data()
|
2019-10-20 13:40:50 +08:00
|
|
|
if let res = try? JSONDecoder().decode(StartProxyResp.self, from: jsonData) {
|
2019-10-02 21:43:18 +08:00
|
|
|
let port = res.externalController.components(separatedBy: ":").last ?? "9090"
|
|
|
|
ConfigManager.shared.apiPort = port
|
|
|
|
ConfigManager.shared.apiSecret = res.secret
|
|
|
|
ConfigManager.shared.isRunning = true
|
|
|
|
proxyModeMenuItem.isEnabled = true
|
|
|
|
dashboardMenuItem.isEnabled = true
|
|
|
|
} else {
|
|
|
|
ConfigManager.shared.isRunning = false
|
|
|
|
proxyModeMenuItem.isEnabled = false
|
2019-10-20 13:40:50 +08:00
|
|
|
NSUserNotificationCenter.default.postConfigErrorNotice(msg: string)
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2018-08-04 14:33:47 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
|
|
|
func syncConfig(completeHandler: (() -> Void)? = nil) {
|
|
|
|
ApiRequest.requestConfig { config in
|
2018-08-04 16:30:10 +08:00
|
|
|
ConfigManager.shared.currentConfig = config
|
2018-08-26 21:21:09 +08:00
|
|
|
completeHandler?()
|
2018-06-23 21:43:33 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-07 15:09:25 +08:00
|
|
|
func resetStreamApi() {
|
2019-09-29 21:28:43 +08:00
|
|
|
ApiRequest.shared.delegate = self
|
|
|
|
ApiRequest.shared.resetStreamApis()
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-28 14:47:47 +08:00
|
|
|
func updateConfig(configName: String? = nil, showNotification: Bool = true, completeHandler: ((ErrorString?) -> Void)? = nil) {
|
2019-08-18 13:23:28 +08:00
|
|
|
startProxy()
|
2019-10-20 13:40:50 +08:00
|
|
|
guard ConfigManager.shared.isRunning else { return }
|
|
|
|
|
2019-10-25 23:30:11 +08:00
|
|
|
let config = configName ?? ConfigManager.selectConfigName
|
|
|
|
|
|
|
|
ApiRequest.requestConfigUpdate(configName: config) {
|
2019-10-09 20:33:57 +08:00
|
|
|
[weak self] err in
|
2019-10-20 13:40:50 +08:00
|
|
|
guard let self = self else { return }
|
2019-10-28 14:47:47 +08:00
|
|
|
|
|
|
|
defer {
|
|
|
|
completeHandler?(err)
|
|
|
|
}
|
|
|
|
|
2019-10-09 20:33:57 +08:00
|
|
|
if let error = err {
|
2019-10-25 20:50:24 +08:00
|
|
|
NSUserNotificationCenter.default
|
|
|
|
.post(title: NSLocalizedString("Reload Config Fail", comment: ""),
|
|
|
|
info: error)
|
2019-10-09 20:33:57 +08:00
|
|
|
} else {
|
|
|
|
self.syncConfig()
|
|
|
|
self.resetStreamApi()
|
|
|
|
self.selectOutBoundModeWithMenory()
|
|
|
|
self.selectAllowLanWithMenory()
|
|
|
|
if showNotification {
|
|
|
|
NSUserNotificationCenter.default
|
|
|
|
.post(title: NSLocalizedString("Reload Config Succeed", comment: ""),
|
|
|
|
info: NSLocalizedString("Succees", comment: ""))
|
|
|
|
}
|
2019-10-25 23:30:11 +08:00
|
|
|
|
|
|
|
if let newConfigName = configName {
|
|
|
|
ConfigManager.selectConfigName = newConfigName
|
|
|
|
}
|
2019-11-01 20:47:55 +08:00
|
|
|
self.selectProxyGroupWithMemory()
|
2019-12-29 14:48:39 +08:00
|
|
|
NotificationCenter.default.post(name: kReloadDashboard, object: nil)
|
2019-08-18 13:23:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-28 10:48:22 +08:00
|
|
|
func setupExperimentalMenuItem() {
|
2019-10-28 14:47:47 +08:00
|
|
|
ConnectionManager.addCloseOptionMenuItem(&experimentalMenu)
|
2019-10-28 10:48:22 +08:00
|
|
|
AutoUpgardeManager.shared.setup()
|
|
|
|
AutoUpgardeManager.shared.addChanelMenuItem(&experimentalMenu)
|
2019-12-31 21:41:52 +08:00
|
|
|
ClashResourceManager.addUpdateMMDBMenuItem(&experimentalMenu)
|
2019-12-08 13:38:18 +08:00
|
|
|
if WebPortalManager.hasWebProtal {
|
|
|
|
WebPortalManager.shared.addWebProtalMenuItem(&statusMenu)
|
|
|
|
}
|
2019-10-28 10:48:22 +08:00
|
|
|
updateExperimentalFeatureStatus()
|
|
|
|
}
|
|
|
|
|
2019-10-13 22:42:25 +08:00
|
|
|
func updateExperimentalFeatureStatus() {
|
|
|
|
buildApiModeMenuitem.state = ConfigManager.builtInApiMode ? .on : .off
|
2019-10-19 11:44:39 +08:00
|
|
|
showProxyGroupCurrentMenuItem.state = ConfigManager.shared.disableShowCurrentProxyInMenu ? .off : .on
|
2019-10-13 22:42:25 +08:00
|
|
|
}
|
2018-12-09 01:15:53 +08:00
|
|
|
}
|
2018-08-04 16:30:10 +08:00
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
// MARK: Main actions
|
|
|
|
|
|
|
|
extension AppDelegate {
|
2020-02-05 21:45:11 +08:00
|
|
|
@IBAction func actionDashboard(_ sender: NSMenuItem) {
|
|
|
|
dashboardWindowController.showWindow(sender)
|
|
|
|
}
|
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
@IBAction func actionAllowFromLan(_ sender: NSMenuItem) {
|
|
|
|
ApiRequest.updateAllowLan(allow: !ConfigManager.allowConnectFromLan) {
|
2018-12-22 21:00:54 +08:00
|
|
|
[weak self] in
|
2019-10-20 13:40:50 +08:00
|
|
|
guard let self = self else { return }
|
2018-12-09 01:15:53 +08:00
|
|
|
self.syncConfig()
|
|
|
|
ConfigManager.allowConnectFromLan = !ConfigManager.allowConnectFromLan
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
@IBAction func actionStartAtLogin(_ sender: NSMenuItem) {
|
|
|
|
LaunchAtLogin.shared.isEnabled = !LaunchAtLogin.shared.isEnabled
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
@IBAction func actionSwitchProxyMode(_ sender: NSMenuItem) {
|
2019-10-20 13:40:50 +08:00
|
|
|
let mode: ClashProxyMode
|
2018-12-09 01:15:53 +08:00
|
|
|
switch sender {
|
|
|
|
case proxyModeGlobalMenuItem:
|
|
|
|
mode = .global
|
|
|
|
case proxyModeDirectMenuItem:
|
|
|
|
mode = .direct
|
|
|
|
case proxyModeRuleMenuItem:
|
|
|
|
mode = .rule
|
|
|
|
default:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
let config = ConfigManager.shared.currentConfig?.copy()
|
|
|
|
config?.mode = mode
|
2019-10-20 13:40:50 +08:00
|
|
|
ApiRequest.updateOutBoundMode(mode: mode) { success in
|
2018-12-09 01:15:53 +08:00
|
|
|
ConfigManager.shared.currentConfig = config
|
|
|
|
ConfigManager.selectOutBoundMode = mode
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
@IBAction func actionShowNetSpeedIndicator(_ sender: NSMenuItem) {
|
|
|
|
ConfigManager.shared.showNetSpeedIndicator = !(sender.state == .on)
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-06-13 10:44:30 +08:00
|
|
|
@IBAction func actionSetSystemProxy(_ sender: Any) {
|
2019-10-28 16:15:10 +08:00
|
|
|
if ConfigManager.shared.isProxySetByOtherVariable.value {
|
2019-10-15 22:40:02 +08:00
|
|
|
// should reset proxy to clashx
|
2019-10-22 21:56:56 +08:00
|
|
|
ConfigManager.shared.isProxySetByOtherVariable.accept(false)
|
2019-10-28 16:15:10 +08:00
|
|
|
ConfigManager.shared.proxyPortAutoSet = true
|
2019-10-15 22:40:02 +08:00
|
|
|
} else {
|
|
|
|
ConfigManager.shared.proxyPortAutoSet = !ConfigManager.shared.proxyPortAutoSet
|
|
|
|
}
|
2019-08-18 11:20:11 +08:00
|
|
|
let port = ConfigManager.shared.currentConfig?.port ?? 0
|
|
|
|
let socketPort = ConfigManager.shared.currentConfig?.socketPort ?? 0
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-04 16:30:10 +08:00
|
|
|
if ConfigManager.shared.proxyPortAutoSet {
|
2019-08-18 11:20:11 +08:00
|
|
|
SystemProxyManager.shared.saveProxy()
|
2019-08-17 13:47:43 +08:00
|
|
|
SystemProxyManager.shared.enableProxy(port: port, socksPort: socketPort)
|
2018-06-13 10:44:30 +08:00
|
|
|
} else {
|
2019-08-18 11:20:11 +08:00
|
|
|
SystemProxyManager.shared.disableProxy(port: port, socksPort: socketPort)
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-12-17 21:04:11 +08:00
|
|
|
@IBAction func actionCopyExportCommand(_ sender: NSMenuItem) {
|
2018-06-13 10:44:30 +08:00
|
|
|
let pasteboard = NSPasteboard.general
|
|
|
|
pasteboard.clearContents()
|
2018-08-04 16:30:10 +08:00
|
|
|
let port = ConfigManager.shared.currentConfig?.port ?? 0
|
2018-10-02 14:20:19 +08:00
|
|
|
let socksport = ConfigManager.shared.currentConfig?.socketPort ?? 0
|
2019-10-25 22:22:07 +08:00
|
|
|
let localhost = "127.0.0.1"
|
2019-12-17 21:04:11 +08:00
|
|
|
let isLocalhostCopy = sender == copyExportCommandMenuItem
|
|
|
|
let ip = isLocalhostCopy ? localhost :
|
|
|
|
NetworkChangeNotifier.getPrimaryIPAddress() ?? localhost
|
2019-11-06 19:25:29 +08:00
|
|
|
pasteboard.setString("export https_proxy=http://\(ip):\(port) http_proxy=http://\(ip):\(port) all_proxy=socks5://\(ip):\(socksport)", forType: .string)
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-09-23 21:37:11 +08:00
|
|
|
@IBAction func actionSpeedTest(_ sender: Any) {
|
2019-03-01 17:39:17 +08:00
|
|
|
if isSpeedTesting {
|
|
|
|
NSUserNotificationCenter.default.postSpeedTestingNotice()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
NSUserNotificationCenter.default.postSpeedTestBeginNotice()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-02-19 09:45:23 +08:00
|
|
|
isSpeedTesting = true
|
|
|
|
ApiRequest.getAllProxyList { [weak self] proxies in
|
|
|
|
let testGroup = DispatchGroup()
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-02-19 09:45:23 +08:00
|
|
|
for proxyName in proxies {
|
|
|
|
testGroup.enter()
|
|
|
|
ApiRequest.getProxyDelay(proxyName: proxyName) { delay in
|
|
|
|
testGroup.leave()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
testGroup.notify(queue: DispatchQueue.main, execute: {
|
|
|
|
NSUserNotificationCenter.default.postSpeedTestFinishNotice()
|
2019-03-01 17:39:17 +08:00
|
|
|
self?.isSpeedTesting = false
|
2019-02-19 09:45:23 +08:00
|
|
|
})
|
|
|
|
}
|
2018-08-26 21:21:09 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
@IBAction func actionQuit(_ sender: Any) {
|
|
|
|
NSApplication.shared.terminate(self)
|
2018-06-14 16:16:00 +08:00
|
|
|
}
|
2018-12-09 01:15:53 +08:00
|
|
|
}
|
|
|
|
|
2019-09-29 21:28:43 +08:00
|
|
|
// MARK: Streaming Info
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-29 21:28:43 +08:00
|
|
|
extension AppDelegate: ApiRequestStreamDelegate {
|
|
|
|
func didUpdateTraffic(up: Int, down: Int) {
|
2019-11-21 22:39:10 +08:00
|
|
|
statusItemView.updateSpeedLabel(up: up, down: down)
|
2019-09-29 21:28:43 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-29 21:28:43 +08:00
|
|
|
func didGetLog(log: String, level: String) {
|
|
|
|
Logger.log(log, level: ClashLogLevel(rawValue: level) ?? .unknow)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
// MARK: Help actions
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
extension AppDelegate {
|
|
|
|
@IBAction func actionShowLog(_ sender: Any) {
|
|
|
|
NSWorkspace.shared.openFile(Logger.shared.logFilePath())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: Config actions
|
|
|
|
|
|
|
|
extension AppDelegate {
|
2018-06-13 10:44:30 +08:00
|
|
|
@IBAction func openConfigFolder(_ sender: Any) {
|
2018-10-14 23:42:53 +08:00
|
|
|
NSWorkspace.shared.openFile(kConfigFolderPath)
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-08-18 13:23:28 +08:00
|
|
|
@IBAction func actionUpdateConfig(_ sender: AnyObject) {
|
|
|
|
updateConfig()
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-08-12 11:29:51 +08:00
|
|
|
@IBAction func actionSetLogLevel(_ sender: NSMenuItem) {
|
|
|
|
let level = ClashLogLevel(rawValue: sender.title.lowercased()) ?? .unknow
|
|
|
|
ConfigManager.selectLoggingApiLevel = level
|
|
|
|
updateLoggingLevel()
|
|
|
|
resetStreamApi()
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-04-08 15:45:20 +08:00
|
|
|
@IBAction func actionAutoUpdateRemoteConfig(_ sender: Any) {
|
|
|
|
RemoteConfigManager.autoUpdateEnable = !RemoteConfigManager.autoUpdateEnable
|
|
|
|
remoteConfigAutoupdateMenuItem.state = RemoteConfigManager.autoUpdateEnable ? .on : .off
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
@IBAction func actionUpdateRemoteConfig(_ sender: Any) {
|
2019-08-18 13:23:28 +08:00
|
|
|
RemoteConfigManager.shared.updateCheck(ignoreTimeLimit: true, showNotification: true)
|
2018-08-04 16:30:10 +08:00
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-13 22:42:25 +08:00
|
|
|
@IBAction func actionSetUseApiMode(_ sender: Any) {
|
|
|
|
let alert = NSAlert()
|
2019-10-20 13:40:50 +08:00
|
|
|
alert.informativeText = NSLocalizedString("Need to Restart the ClashX to Take effect, Please start clashX manually", comment: "")
|
|
|
|
alert.addButton(withTitle: NSLocalizedString("Apply and Quit", comment: ""))
|
2019-10-13 22:42:25 +08:00
|
|
|
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
|
|
|
|
if alert.runModal() == .alertFirstButtonReturn {
|
|
|
|
ConfigManager.builtInApiMode = !ConfigManager.builtInApiMode
|
|
|
|
NSApp.terminate(nil)
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-19 11:44:39 +08:00
|
|
|
@IBAction func actionUpdateProxyGroupMenu(_ sender: Any) {
|
|
|
|
ConfigManager.shared.disableShowCurrentProxyInMenu = !ConfigManager.shared.disableShowCurrentProxyInMenu
|
|
|
|
updateExperimentalFeatureStatus()
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-17 19:38:04 +08:00
|
|
|
@IBAction func actionSetBenchmarkUrl(_ sender: Any) {
|
|
|
|
let alert = NSAlert()
|
|
|
|
let textfiled = NSTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 20))
|
|
|
|
textfiled.stringValue = ConfigManager.shared.benchMarkUrl
|
|
|
|
alert.messageText = NSLocalizedString("Benchmark", comment: "")
|
|
|
|
alert.accessoryView = textfiled
|
|
|
|
alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
|
|
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-10-17 19:38:04 +08:00
|
|
|
if alert.runModal() == .alertFirstButtonReturn {
|
|
|
|
if textfiled.stringValue.isUrlVaild() {
|
|
|
|
ConfigManager.shared.benchMarkUrl = textfiled.stringValue
|
|
|
|
} else {
|
|
|
|
let err = NSAlert()
|
|
|
|
err.messageText = NSLocalizedString("URL is not valid", comment: "")
|
|
|
|
err.runModal()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-09 00:06:43 +08:00
|
|
|
}
|
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
// MARK: crash hanlder
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 00:06:43 +08:00
|
|
|
extension AppDelegate {
|
|
|
|
func registCrashLogger() {
|
2019-12-14 17:52:44 +08:00
|
|
|
#if DEBUG
|
|
|
|
return
|
|
|
|
#endif
|
2018-12-09 00:06:43 +08:00
|
|
|
Fabric.with([Crashlytics.self])
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
|
|
|
func failLaunchProtect() {
|
2019-12-14 17:52:44 +08:00
|
|
|
#if DEBUG
|
|
|
|
return
|
|
|
|
#endif
|
2018-12-09 00:06:43 +08:00
|
|
|
let x = UserDefaults.standard
|
2019-10-20 13:40:50 +08:00
|
|
|
var launch_fail_times: Int = 0
|
|
|
|
if let xx = x.object(forKey: "launch_fail_times") as? Int { launch_fail_times = xx }
|
2018-12-09 00:06:43 +08:00
|
|
|
launch_fail_times += 1
|
|
|
|
x.set(launch_fail_times, forKey: "launch_fail_times")
|
2018-12-09 01:04:14 +08:00
|
|
|
if launch_fail_times > 3 {
|
2019-10-20 13:40:50 +08:00
|
|
|
// 发生连续崩溃
|
2018-12-09 22:00:15 +08:00
|
|
|
ConfigFileManager.backupAndRemoveConfigFile()
|
2018-12-09 00:06:43 +08:00
|
|
|
try? FileManager.default.removeItem(atPath: kConfigFolderPath + "Country.mmdb")
|
2019-11-04 22:51:23 +08:00
|
|
|
if let domain = Bundle.main.bundleIdentifier {
|
|
|
|
UserDefaults.standard.removePersistentDomain(forName: domain)
|
|
|
|
UserDefaults.standard.synchronize()
|
|
|
|
}
|
2018-12-09 00:06:43 +08:00
|
|
|
NSUserNotificationCenter.default.post(title: "Fail on launch protect", info: "You origin Config has been renamed")
|
|
|
|
}
|
2019-11-09 11:50:51 +08:00
|
|
|
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + Double(Int64(5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {
|
2018-12-09 00:06:43 +08:00
|
|
|
x.set(0, forKey: "launch_fail_times")
|
2019-10-20 13:40:50 +08:00
|
|
|
})
|
2018-12-09 00:06:43 +08:00
|
|
|
}
|
2018-06-13 10:44:30 +08:00
|
|
|
}
|
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
// MARK: Memory
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:00:09 +08:00
|
|
|
extension AppDelegate {
|
2019-10-20 13:40:50 +08:00
|
|
|
func selectProxyGroupWithMemory() {
|
2019-11-02 00:04:42 +08:00
|
|
|
let copy = [SavedProxyModel](ConfigManager.selectedProxyRecords)
|
2019-11-01 20:47:55 +08:00
|
|
|
for item in copy {
|
2019-11-02 11:55:18 +08:00
|
|
|
guard item.config == ConfigManager.selectConfigName else { continue }
|
2019-12-11 20:27:17 +08:00
|
|
|
Logger.log("Auto selecting \(item.group) \(item.selected)", level: .debug)
|
2019-11-01 20:47:55 +08:00
|
|
|
ApiRequest.updateProxyGroup(group: item.group, selectProxy: item.selected) { success in
|
2019-10-20 13:40:50 +08:00
|
|
|
if !success {
|
2019-11-02 00:04:42 +08:00
|
|
|
ConfigManager.selectedProxyRecords.removeAll { model -> Bool in
|
2019-12-11 20:27:17 +08:00
|
|
|
return model.key == item.key
|
2019-11-01 20:47:55 +08:00
|
|
|
}
|
2018-12-09 01:00:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-02 11:55:18 +08:00
|
|
|
|
2019-11-01 20:47:55 +08:00
|
|
|
func removeUnExistProxyGroups() {
|
|
|
|
let list = ConfigManager.getConfigFilesList()
|
2019-11-02 00:04:42 +08:00
|
|
|
let unexists = ConfigManager.selectedProxyRecords.filter {
|
2019-11-01 20:47:55 +08:00
|
|
|
!list.contains($0.config)
|
|
|
|
}
|
2019-11-02 00:04:42 +08:00
|
|
|
ConfigManager.selectedProxyRecords.removeAll {
|
2019-11-01 20:47:55 +08:00
|
|
|
unexists.contains($0)
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:00:09 +08:00
|
|
|
func selectOutBoundModeWithMenory() {
|
2019-10-20 13:40:50 +08:00
|
|
|
ApiRequest.updateOutBoundMode(mode: ConfigManager.selectOutBoundMode) {
|
2019-03-24 13:59:12 +08:00
|
|
|
[weak self] _ in
|
2019-11-21 22:43:46 +08:00
|
|
|
ConnectionManager.closeAllConnection()
|
2019-03-24 13:59:12 +08:00
|
|
|
self?.syncConfig()
|
2018-12-09 01:00:09 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2018-12-09 01:00:09 +08:00
|
|
|
func selectAllowLanWithMenory() {
|
2019-10-20 13:40:50 +08:00
|
|
|
ApiRequest.updateAllowLan(allow: ConfigManager.allowConnectFromLan) {
|
2019-03-24 13:59:12 +08:00
|
|
|
[weak self] in
|
|
|
|
self?.syncConfig()
|
2018-12-09 01:00:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-09 01:15:53 +08:00
|
|
|
// MARK: NSMenuDelegate
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
extension AppDelegate: NSMenuDelegate {
|
2019-01-11 16:09:06 +08:00
|
|
|
func menuNeedsUpdate(_ menu: NSMenu) {
|
|
|
|
syncConfig()
|
|
|
|
updateConfigFiles()
|
|
|
|
}
|
2019-09-14 18:05:36 +08:00
|
|
|
}
|
2019-01-11 16:09:06 +08:00
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
// MARK: URL Scheme
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
extension AppDelegate {
|
|
|
|
@objc func handleURL(event: NSAppleEventDescriptor, reply: NSAppleEventDescriptor) {
|
|
|
|
guard let url = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue else {
|
|
|
|
return
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
guard let components = URLComponents(string: url),
|
|
|
|
let scheme = components.scheme,
|
|
|
|
scheme.hasPrefix("clash"),
|
|
|
|
let host = components.host
|
2019-10-20 13:40:50 +08:00
|
|
|
else { return }
|
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
if host == "install-config" {
|
|
|
|
guard let url = components.queryItems?.first(where: { item in
|
|
|
|
item.name == "url"
|
2019-10-20 13:40:50 +08:00
|
|
|
})?.value else { return }
|
|
|
|
|
|
|
|
var userInfo = ["url": url]
|
2019-09-14 18:05:36 +08:00
|
|
|
if let name = components.queryItems?.first(where: { item in
|
|
|
|
item.name == "name"
|
|
|
|
})?.value {
|
|
|
|
userInfo["name"] = name
|
|
|
|
}
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
remoteConfigAutoupdateMenuItem.menu?.performActionForItem(at: 0)
|
2019-10-20 13:40:50 +08:00
|
|
|
|
2019-09-14 18:05:36 +08:00
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
|
|
|
NotificationCenter.default.post(name: Notification.Name(rawValue: "didGetUrl"), object: nil, userInfo: userInfo)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-04 00:36:24 +08:00
|
|
|
}
|
2019-11-30 19:29:57 +08:00
|
|
|
|
|
|
|
// MARK: - Alerts
|
|
|
|
|
|
|
|
extension AppDelegate {
|
|
|
|
func showClashPortErrorAlert() {
|
|
|
|
let alert = NSAlert()
|
|
|
|
alert.messageText = NSLocalizedString("ClashX Start Error!", comment: "")
|
|
|
|
alert.informativeText = NSLocalizedString("Ports Open Fail, Please try to restart ClashX", comment: "")
|
|
|
|
}
|
|
|
|
}
|