2018-08-05 18:34:12 +08:00
|
|
|
//
|
|
|
|
// ConfigFileFactory.swift
|
|
|
|
// ClashX
|
|
|
|
//
|
|
|
|
// Created by CYC on 2018/8/5.
|
2018-08-08 13:47:38 +08:00
|
|
|
// Copyright © 2018年 yichengchen. All rights reserved.
|
2018-08-05 18:34:12 +08:00
|
|
|
//
|
|
|
|
import Foundation
|
2018-08-05 23:16:58 +08:00
|
|
|
import AppKit
|
2018-08-06 14:17:04 +08:00
|
|
|
import SwiftyJSON
|
2018-10-07 21:03:16 +08:00
|
|
|
import Yams
|
2018-08-05 18:34:12 +08:00
|
|
|
|
2018-12-09 22:00:15 +08:00
|
|
|
class ConfigFileManager {
|
|
|
|
static let shared = ConfigFileManager()
|
2018-08-12 00:10:42 +08:00
|
|
|
var witness:Witness?
|
2018-12-09 22:55:01 +08:00
|
|
|
func watchConfigFile(configName:String) {
|
|
|
|
let path = "\(kConfigFolderPath)/\(configName).yml"
|
2018-08-12 00:10:42 +08:00
|
|
|
witness = Witness(paths: [path], flags: .FileEvents, latency: 0.3) { events in
|
2018-08-19 11:14:16 +08:00
|
|
|
for event in events {
|
|
|
|
if event.flags.contains(.ItemModified) || event.flags.contains(.ItemCreated){
|
2018-12-09 22:55:01 +08:00
|
|
|
NSUserNotificationCenter.default
|
|
|
|
.postConfigFileChangeDetectionNotice()
|
|
|
|
NotificationCenter.default
|
|
|
|
.post(Notification(name: kConfigFileChange))
|
2018-08-19 11:14:16 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2018-08-12 00:10:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-14 22:48:51 +08:00
|
|
|
|
|
|
|
static func saveToClashConfigFile(config:[String:Any]) {
|
|
|
|
// save to ~/.config/clash/config.yml
|
2018-09-22 17:18:25 +08:00
|
|
|
_ = self.backupAndRemoveConfigFile(showAlert: false)
|
2018-10-20 10:31:07 +08:00
|
|
|
var config = config
|
|
|
|
var finalConfigString = ""
|
|
|
|
do {
|
|
|
|
if let proxyConfig = config["Proxy"] {
|
|
|
|
finalConfigString += try
|
|
|
|
Yams.dump(object: ["Proxy":proxyConfig],allowUnicode:true)
|
|
|
|
config["Proxy"] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if let proxyGroupConfig = config["Proxy Group"] {
|
|
|
|
finalConfigString += try
|
|
|
|
Yams.dump(object: ["Proxy Group":proxyGroupConfig]
|
|
|
|
,allowUnicode:true)
|
|
|
|
config["Proxy Group"] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if let rule = config["Rule"] {
|
|
|
|
finalConfigString += try
|
|
|
|
Yams.dump(object: ["Rule":rule],allowUnicode:true)
|
|
|
|
config["Rule"] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
finalConfigString = try Yams.dump(object: config,allowUnicode:true) + finalConfigString
|
|
|
|
|
2018-12-09 22:00:15 +08:00
|
|
|
try finalConfigString.write(toFile: kDefaultConfigFilePath, atomically: true, encoding: .utf8)
|
2018-10-20 10:31:07 +08:00
|
|
|
|
|
|
|
} catch {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-09-01 14:19:53 +08:00
|
|
|
}
|
|
|
|
|
2018-09-27 23:07:05 +08:00
|
|
|
@discardableResult
|
2018-09-05 19:30:38 +08:00
|
|
|
static func backupAndRemoveConfigFile(showAlert:Bool = false) -> Bool {
|
2018-12-09 22:00:15 +08:00
|
|
|
let path = kDefaultConfigFilePath
|
2018-10-14 23:42:53 +08:00
|
|
|
|
2018-08-05 18:34:12 +08:00
|
|
|
if (FileManager.default.fileExists(atPath: path)) {
|
2018-10-14 23:42:53 +08:00
|
|
|
if (showAlert) {
|
|
|
|
if !self.showReplacingConfigFileAlert() {return false}
|
|
|
|
}
|
2018-10-14 22:48:51 +08:00
|
|
|
let newPath = "\(kConfigFolderPath)config_\(Date().timeIntervalSince1970).yml"
|
2018-09-01 14:19:53 +08:00
|
|
|
try? FileManager.default.moveItem(atPath: path, toPath: newPath)
|
2018-08-05 18:34:12 +08:00
|
|
|
}
|
2018-09-05 19:30:38 +08:00
|
|
|
return true
|
2018-08-05 23:16:58 +08:00
|
|
|
}
|
|
|
|
|
2018-10-14 22:48:51 +08:00
|
|
|
static func copySampleConfigIfNeed() {
|
2018-12-09 22:00:15 +08:00
|
|
|
if !FileManager.default.fileExists(atPath: kDefaultConfigFilePath) {
|
2018-10-14 23:42:53 +08:00
|
|
|
_ = replaceConfigWithSampleConfig()
|
2018-10-14 22:48:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static func replaceConfigWithSampleConfig() -> Bool {
|
2018-09-05 19:30:38 +08:00
|
|
|
if (!backupAndRemoveConfigFile(showAlert: true)) {
|
2018-09-05 20:19:47 +08:00
|
|
|
return false
|
2018-09-05 19:30:38 +08:00
|
|
|
}
|
2018-10-14 22:48:51 +08:00
|
|
|
let path = Bundle.main.path(forResource: "sampleConfig", ofType: "yml")!
|
2018-12-09 22:00:15 +08:00
|
|
|
try? FileManager.default.copyItem(atPath: path, toPath: kDefaultConfigFilePath)
|
2018-08-11 23:07:51 +08:00
|
|
|
NSUserNotificationCenter.default.postGenerateSimpleConfigNotice()
|
2018-09-05 20:19:47 +08:00
|
|
|
return true
|
2018-08-11 23:07:51 +08:00
|
|
|
}
|
|
|
|
|
2018-08-05 23:16:58 +08:00
|
|
|
|
2018-10-07 21:03:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-09 22:00:15 +08:00
|
|
|
extension ConfigFileManager {
|
2018-10-27 12:22:45 +08:00
|
|
|
|
|
|
|
static func checkFinalRuleAndShowAlert() {
|
|
|
|
ApiRequest.getRules() {
|
|
|
|
rules in
|
2019-02-19 11:50:23 +08:00
|
|
|
let hasFinal = rules.reversed().contains(){$0.type == "MATCH"}
|
2018-10-27 12:22:45 +08:00
|
|
|
if !hasFinal {
|
|
|
|
showNoFinalRuleAlert()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-10-07 21:03:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-09 22:00:15 +08:00
|
|
|
extension ConfigFileManager {
|
2018-09-05 19:30:38 +08:00
|
|
|
static func showReplacingConfigFileAlert() -> Bool{
|
|
|
|
let alert = NSAlert()
|
|
|
|
alert.messageText = """
|
2018-10-02 12:20:18 +08:00
|
|
|
Can't recognize your config file. We will backup and replace your config file in your config folder.
|
2018-09-05 19:30:38 +08:00
|
|
|
|
|
|
|
Otherwise the functions of ClashX will not work properly. You may need to restart ClashX or reload Config manually.
|
|
|
|
"""
|
|
|
|
alert.alertStyle = .warning
|
|
|
|
alert.addButton(withTitle: "Replace")
|
|
|
|
alert.addButton(withTitle: "Cancel")
|
|
|
|
return alert.runModal() == .alertFirstButtonReturn
|
|
|
|
}
|
2018-10-07 21:03:16 +08:00
|
|
|
|
2018-10-19 13:44:37 +08:00
|
|
|
|
2018-10-27 12:22:45 +08:00
|
|
|
|
|
|
|
static func showNoFinalRuleAlert() {
|
|
|
|
let alert = NSAlert()
|
|
|
|
alert.messageText = """
|
|
|
|
No FINAL rule were found in clash configs,This might caused by incorrect upgradation during earily version of clashX or error setting of FINAL rule.Please check your config file.
|
|
|
|
|
|
|
|
NO FINAL rule would cause traffic send to DIRECT which no match any rules.
|
|
|
|
""".localized()
|
|
|
|
alert.alertStyle = .warning
|
|
|
|
alert.addButton(withTitle: "OK")
|
|
|
|
alert.runModal()
|
|
|
|
}
|
|
|
|
|
2018-08-05 18:34:12 +08:00
|
|
|
}
|