mirror of
https://github.com/yanue/V2rayU.git
synced 2025-06-27 05:30:09 +00:00
start v2ray at launch
This commit is contained in:
parent
6729f3373d
commit
ebd370d962
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<array/>
|
||||
</plist>
|
@ -8,7 +8,6 @@
|
||||
|
||||
import Cocoa
|
||||
import ServiceManagement
|
||||
import os.log
|
||||
|
||||
let launcherAppIdentifier = "net.yanue.V2rayU.Launcher"
|
||||
|
||||
@ -16,11 +15,9 @@ let launcherAppIdentifier = "net.yanue.V2rayU.Launcher"
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
// bar menu
|
||||
@IBOutlet weak var statusMenu: NSMenu!
|
||||
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
// Insert code here to initialize your application
|
||||
os_log("v2rayu init.")
|
||||
|
||||
// Insert code here to initialize your application
|
||||
let startedAtLogin = NSWorkspace.shared.runningApplications.contains {
|
||||
$0.bundleIdentifier == launcherAppIdentifier
|
||||
}
|
||||
@ -30,9 +27,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
}
|
||||
|
||||
V2rayLaunch.generateLauchAgentPlist()
|
||||
if UserDefaults.getBool(forKey: .v2rayTurnOn) {
|
||||
V2rayLaunch.Start()
|
||||
}
|
||||
|
||||
// auto check updates
|
||||
if UserDefaults.getBool(forKey: .autoCheckVersion) {
|
||||
|
BIN
V2rayU/Assets.xcassets/IconOff.imageset/icon.png
vendored
Normal file
BIN
V2rayU/Assets.xcassets/IconOff.imageset/icon.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 338 B |
BIN
V2rayU/Assets.xcassets/IconOff.imageset/icon@2x.png
vendored
Normal file
BIN
V2rayU/Assets.xcassets/IconOff.imageset/icon@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 575 B |
BIN
V2rayU/Assets.xcassets/IconOff.imageset/icon@3x.png
vendored
Normal file
BIN
V2rayU/Assets.xcassets/IconOff.imageset/icon@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 575 B |
BIN
V2rayU/Assets.xcassets/IconOn.imageset/icon.png
vendored
Executable file
BIN
V2rayU/Assets.xcassets/IconOn.imageset/icon.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 331 B |
BIN
V2rayU/Assets.xcassets/IconOn.imageset/icon@2x.png
vendored
Executable file
BIN
V2rayU/Assets.xcassets/IconOn.imageset/icon@2x.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 553 B |
BIN
V2rayU/Assets.xcassets/IconOn.imageset/icon@3x.png
vendored
Executable file
BIN
V2rayU/Assets.xcassets/IconOn.imageset/icon@3x.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 553 B |
@ -8,14 +8,14 @@
|
||||
|
||||
import Cocoa
|
||||
import WebKit
|
||||
import os.log
|
||||
|
||||
class ConfigWindowController: NSWindowController,NSWindowDelegate {
|
||||
var lastIndex:Int = 0
|
||||
class ConfigWindowController: NSWindowController, NSWindowDelegate {
|
||||
|
||||
override var windowNibName: String? {
|
||||
return "ConfigWindow" // no extension .xib here
|
||||
}
|
||||
let tableViewDragType: String = "ss.server.profile.data"
|
||||
|
||||
let tableViewDragType: String = "v2ray.item"
|
||||
|
||||
@IBOutlet weak var errTip: NSTextField!
|
||||
|
||||
@ -106,7 +106,7 @@ class ConfigWindowController: NSWindowController,NSWindowDelegate {
|
||||
// save
|
||||
V2rayServer.save(idx: self.serversTableView.selectedRow, jsonData: text)
|
||||
|
||||
print("save ok fater")
|
||||
NSLog("save ok fater")
|
||||
// refresh menu
|
||||
menuController.showServers()
|
||||
}
|
||||
@ -118,17 +118,8 @@ class ConfigWindowController: NSWindowController,NSWindowDelegate {
|
||||
NSApp.setActivationPolicy(.accessory)
|
||||
}
|
||||
|
||||
@objc private func onDoubleClicked() {
|
||||
print("onDoubleClicked row \(serversTableView.clickedRow), col \(serversTableView.clickedColumn) clicked")
|
||||
}
|
||||
|
||||
@objc private func onItemClicked() {
|
||||
print("row \(serversTableView.clickedRow), col \(serversTableView.clickedColumn) clicked")
|
||||
}
|
||||
|
||||
func windowShouldClose(_ sender: NSWindow) -> Bool {
|
||||
// NSApp.setActivationPolicy(.accessory)
|
||||
print("close1")
|
||||
self.close()
|
||||
NSApp.terminate(self)
|
||||
return true
|
||||
@ -136,12 +127,12 @@ class ConfigWindowController: NSWindowController,NSWindowDelegate {
|
||||
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
// hide dock icon and close all opened windows
|
||||
print("close")
|
||||
NSLog("close")
|
||||
// NSApp.setActivationPolicy(.accessory)
|
||||
}
|
||||
}
|
||||
|
||||
// NSTableViewDataSource
|
||||
// NSv2rayItemListSource
|
||||
extension ConfigWindowController: NSTableViewDataSource {
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
@ -149,15 +140,15 @@ extension ConfigWindowController: NSTableViewDataSource {
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
|
||||
let tableViewData = V2rayServer.list()
|
||||
let v2rayItemList = V2rayServer.list()
|
||||
// set cell data
|
||||
return tableViewData[row].remark
|
||||
return v2rayItemList[row].remark
|
||||
}
|
||||
|
||||
// edit cell
|
||||
func tableView(_ tableView: NSTableView, setObjectValue: Any?, for forTableColumn: NSTableColumn?, row: Int) {
|
||||
guard let remark = setObjectValue as? String else {
|
||||
os_log("remark is nil")
|
||||
NSLog("remark is nil")
|
||||
return
|
||||
}
|
||||
// edit
|
||||
|
@ -13,22 +13,11 @@ import Preferences
|
||||
|
||||
// menu controller
|
||||
class MenuController:NSObject,NSMenuDelegate {
|
||||
// when menu.xib loaded
|
||||
override func awakeFromNib() {
|
||||
// load server list
|
||||
V2rayServer.loadConfig()
|
||||
self.showServers()
|
||||
statusMenu.delegate = self
|
||||
|
||||
if UserDefaults.getBool(forKey: .v2rayTurnOn) {
|
||||
self.setStatusOn()
|
||||
} else{
|
||||
self.setStatusOff()
|
||||
}
|
||||
|
||||
var configWindow: ConfigWindowController!
|
||||
|
||||
statusItem.menu = statusMenu
|
||||
configWindow = ConfigWindowController()
|
||||
}
|
||||
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||
var statusItemClicked: (() -> Void)?
|
||||
|
||||
let preferencesWindowController = PreferencesWindowController(
|
||||
viewControllers: [
|
||||
@ -36,19 +25,32 @@ class MenuController:NSObject,NSMenuDelegate {
|
||||
]
|
||||
)
|
||||
|
||||
var configWindow: ConfigWindowController!
|
||||
|
||||
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||
var statusItemClicked: (() -> Void)?
|
||||
|
||||
@IBOutlet weak var statusMenu: NSMenu!
|
||||
@IBOutlet weak var toggleV2rayItem: NSMenuItem!
|
||||
@IBOutlet weak var v2rayStatusItem: NSMenuItem!
|
||||
|
||||
// bar menu
|
||||
@IBOutlet weak var statusMenu: NSMenu!
|
||||
// server list items
|
||||
@IBOutlet weak var serverItems: NSMenuItem!
|
||||
|
||||
// when menu.xib loaded
|
||||
override func awakeFromNib() {
|
||||
statusMenu.delegate = self
|
||||
NSLog("start menu")
|
||||
// load server list
|
||||
V2rayServer.loadConfig()
|
||||
// show server list
|
||||
self.showServers()
|
||||
|
||||
if UserDefaults.getBool(forKey: .v2rayTurnOn) {
|
||||
// start
|
||||
self.startV2rayCore()
|
||||
} else{
|
||||
self.setStatusOff()
|
||||
}
|
||||
|
||||
statusItem.menu = statusMenu
|
||||
|
||||
configWindow = ConfigWindowController()
|
||||
}
|
||||
|
||||
@IBAction func openLogs(_ sender: NSMenuItem) {
|
||||
V2rayLaunch.OpenLogs()
|
||||
}
|
||||
@ -60,29 +62,27 @@ class MenuController:NSObject,NSMenuDelegate {
|
||||
if let button = statusItem.button {
|
||||
button.image = NSImage(named:NSImage.Name("IconOff"))
|
||||
}
|
||||
|
||||
// set off
|
||||
UserDefaults.setBool(forKey: .v2rayTurnOn, value: false)
|
||||
}
|
||||
|
||||
func setStatusOn() {
|
||||
v2rayStatusItem.title = "V2ray-Core: Off"
|
||||
toggleV2rayItem.title = "Turn V2ray-Core On"
|
||||
v2rayStatusItem.title = "V2ray-Core: On"
|
||||
toggleV2rayItem.title = "Turn V2ray-Core Off"
|
||||
|
||||
if let button = statusItem.button {
|
||||
button.image = NSImage(named:NSImage.Name("IconOn"))
|
||||
}
|
||||
|
||||
// set on
|
||||
UserDefaults.setBool(forKey: .v2rayTurnOn, value: true)
|
||||
}
|
||||
|
||||
@IBAction func start(_ sender: NSMenuItem) {
|
||||
// turn off
|
||||
if UserDefaults.getBool(forKey: .v2rayTurnOn) {
|
||||
// set off
|
||||
UserDefaults.setBool(forKey: .v2rayTurnOn, value: false)
|
||||
|
||||
// set status
|
||||
self.setStatusOff()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// start v2ray core
|
||||
func startV2rayCore() {
|
||||
NSLog("start v2ray-core begin")
|
||||
|
||||
guard let v2ray = V2rayServer.loadSelectedItem() else {
|
||||
NSLog("v2ray config not fould")
|
||||
return
|
||||
@ -93,14 +93,27 @@ class MenuController:NSObject,NSMenuDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
// set on
|
||||
UserDefaults.setBool(forKey: .v2rayTurnOn, value: true)
|
||||
// create json file
|
||||
V2rayServer.createJsonFile(item: v2ray)
|
||||
|
||||
// set status
|
||||
setStatusOn()
|
||||
|
||||
// launch
|
||||
V2rayLaunch.Start()
|
||||
NSLog("start v2ray-core end.")
|
||||
}
|
||||
|
||||
@IBAction func start(_ sender: NSMenuItem) {
|
||||
// turn off
|
||||
if UserDefaults.getBool(forKey: .v2rayTurnOn) {
|
||||
// set status
|
||||
self.setStatusOff()
|
||||
return
|
||||
}
|
||||
|
||||
// start
|
||||
self.startV2rayCore()
|
||||
}
|
||||
|
||||
@IBAction func quitClicked(_ sender: NSMenuItem) {
|
||||
@ -108,39 +121,25 @@ class MenuController:NSObject,NSMenuDelegate {
|
||||
}
|
||||
|
||||
@IBAction func generateQRCode(_ sender: NSMenuItem) {
|
||||
print("GenerateQRCode")
|
||||
NSLog("GenerateQRCode")
|
||||
}
|
||||
|
||||
@IBAction func scanQRCode(_ sender: NSMenuItem) {
|
||||
print("ScanQRCode")
|
||||
NSLog("ScanQRCode")
|
||||
}
|
||||
|
||||
@IBAction func openPreference(_ sender: NSMenuItem) {
|
||||
print("openPreference ")
|
||||
// let app = NSApplication.shared.delegate as! AppDelegate
|
||||
|
||||
self.preferencesWindowController.showWindow()
|
||||
}
|
||||
|
||||
// switch server
|
||||
@IBAction func switchServer(_ sender: NSMenuItem) {
|
||||
if let obj = sender.representedObject as? v2rayItem {
|
||||
|
||||
// path: /Application/V2rayU.app/Contents/Resources/config.json
|
||||
guard let jsonFile = V2rayServer.getJsonFile() else {
|
||||
print("unable get config file path")
|
||||
return
|
||||
}
|
||||
let jsonText = obj.json
|
||||
do {
|
||||
try jsonText.write(to: URL.init(fileURLWithPath: jsonFile), atomically: true, encoding: String.Encoding.utf8)
|
||||
} catch {
|
||||
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
|
||||
return
|
||||
}
|
||||
|
||||
UserDefaults.set(forKey: .v2rayCurrentServerName,value: obj.name)
|
||||
guard let obj = sender.representedObject as? v2rayItem else {
|
||||
NSLog("switchServer err")
|
||||
return
|
||||
}
|
||||
|
||||
UserDefaults.set(forKey: .v2rayCurrentServerName,value: obj.name)
|
||||
}
|
||||
|
||||
// open config window
|
||||
@ -162,6 +161,7 @@ class MenuController:NSObject,NSMenuDelegate {
|
||||
serverItems.submenu?.removeAllItems()
|
||||
let curSer = UserDefaults.get(forKey: .v2rayCurrentServerName)
|
||||
|
||||
// servers preferences...
|
||||
let menuItem : NSMenuItem = NSMenuItem()
|
||||
menuItem.title = "servers preferences..."
|
||||
menuItem.action = #selector(self.openConfig(_:))
|
||||
@ -169,6 +169,7 @@ class MenuController:NSObject,NSMenuDelegate {
|
||||
menuItem.isEnabled = true
|
||||
serverItems.submenu?.addItem(menuItem)
|
||||
|
||||
// separator
|
||||
serverItems.submenu?.addItem(NSMenuItem.separator())
|
||||
|
||||
// add new
|
||||
@ -184,7 +185,7 @@ class MenuController:NSObject,NSMenuDelegate {
|
||||
menuItem.target = self
|
||||
menuItem.isEnabled = true
|
||||
|
||||
if curSer == item.name {
|
||||
if curSer == item.name || V2rayServer.count() == 1 {
|
||||
menuItem.state = NSControl.StateValue.on
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,17 @@ import Foundation
|
||||
extension UserDefaults {
|
||||
|
||||
enum KEY: String {
|
||||
// v2ray-core version
|
||||
case v2rayCoreVersion
|
||||
// v2ray server item list
|
||||
case v2rayServerList
|
||||
// current v2ray server name
|
||||
case v2rayCurrentServerName
|
||||
// v2ray-core turn on status
|
||||
case v2rayTurnOn
|
||||
// auth check version
|
||||
case autoCheckVersion
|
||||
// auto launch after login
|
||||
case autoLaunch
|
||||
}
|
||||
|
||||
@ -53,22 +59,13 @@ extension UserDefaults {
|
||||
}
|
||||
|
||||
extension String {
|
||||
// version compare
|
||||
func versionToInt() -> [Int] {
|
||||
return self.components(separatedBy: ".")
|
||||
.map { Int.init($0) ?? 0 }
|
||||
}
|
||||
}
|
||||
|
||||
func getApplicationSupportDirectory() -> URL {
|
||||
let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
|
||||
return paths[0]
|
||||
}
|
||||
|
||||
func getApplicationDirectory() -> URL {
|
||||
let paths = FileManager.default.urls(for: .applicationDirectory, in: .userDomainMask)
|
||||
return paths[0]
|
||||
}
|
||||
|
||||
// run custom shell
|
||||
// demo:
|
||||
// shell("/bin/bash",["-c","ls"])
|
||||
|
@ -46,7 +46,7 @@ class V2rayCore {
|
||||
//to get status code
|
||||
if let status = response.response?.statusCode {
|
||||
if status != 200 {
|
||||
print("error with response status: \(status)")
|
||||
NSLog("error with response status: ",status)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -57,20 +57,20 @@ class V2rayCore {
|
||||
|
||||
// get tag_name (verion)
|
||||
guard let tag_name = JSON["tag_name"] else {
|
||||
print("err: no tag_name")
|
||||
NSLog("error: no tag_name")
|
||||
return
|
||||
}
|
||||
|
||||
// get prerelease and draft
|
||||
guard let prerelease = JSON["prerelease"],let draft = JSON["draft"] else {
|
||||
// get
|
||||
print("err: get prerelease or draft")
|
||||
NSLog("error: get prerelease or draft")
|
||||
return
|
||||
}
|
||||
|
||||
// not pre release or draft
|
||||
if prerelease as! Bool == true || draft as! Bool == true {
|
||||
print("this release is a prerelease or draft")
|
||||
NSLog("this release is a prerelease or draft")
|
||||
return
|
||||
}
|
||||
|
||||
@ -122,11 +122,11 @@ class V2rayCore {
|
||||
case .success(_):
|
||||
break
|
||||
case .failure(_):
|
||||
print("error with response status:")
|
||||
NSLog("error with response status:")
|
||||
return
|
||||
}
|
||||
|
||||
if let data = response.result.value {
|
||||
if let _ = response.result.value {
|
||||
// make unzip.sh execable
|
||||
// chmod 777 unzip.sh
|
||||
let execable = "cd "+AppResourcesPath+" && /bin/chmod 777 ./unzip.sh"
|
||||
@ -137,7 +137,7 @@ class V2rayCore {
|
||||
let sh = "cd "+AppResourcesPath+" && ./unzip.sh"
|
||||
// exec shell
|
||||
let res = shell(launchPath:"/bin/bash", arguments: ["-c",sh])
|
||||
print("res",data,res!)
|
||||
NSLog("res:",res!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class V2rayLaunch: NSObject {
|
||||
}
|
||||
|
||||
static func Start() {
|
||||
// cmd: /bin/launchctl load -wF /Library/LaunchAgents/yanue.v2rayu.v2ray-core.plist
|
||||
// cmd: /bin/launchctl load -wF /Users/xxx/Library/LaunchAgents/yanue.v2rayu.v2ray-core.plist
|
||||
let task = Process.launchedProcess(launchPath: "/bin/launchctl", arguments: ["load" ,"-wF",launchAgentPlistFile])
|
||||
task.waitUntilExit()
|
||||
if task.terminationStatus == 0 {
|
||||
|
@ -22,12 +22,12 @@ class V2rayServer: NSObject {
|
||||
}
|
||||
|
||||
// v2ray server list
|
||||
static private var tableViewData:[v2rayItem] = []
|
||||
static private var v2rayItemList:[v2rayItem] = []
|
||||
|
||||
// (init) load v2ray server list from UserDefaults
|
||||
static func loadConfig() {
|
||||
// static reset
|
||||
self.tableViewData = []
|
||||
self.v2rayItemList = []
|
||||
|
||||
// load name list from UserDefaults
|
||||
var list = UserDefaults.getArray(forKey: .v2rayServerList)
|
||||
@ -41,56 +41,55 @@ class V2rayServer: NSObject {
|
||||
|
||||
// load each v2rayItem
|
||||
for item in list! {
|
||||
guard let v2ray = v2rayItem.load(name:item) else {
|
||||
guard let v2ray = v2rayItem.load(name: item) else {
|
||||
// delete from UserDefaults
|
||||
v2rayItem.remove(name: item)
|
||||
continue
|
||||
}
|
||||
|
||||
// append
|
||||
self.tableViewData.append(v2ray)
|
||||
self.v2rayItemList.append(v2ray)
|
||||
}
|
||||
}
|
||||
|
||||
// get list from v2ray server list
|
||||
static func list() -> [v2rayItem] {
|
||||
return self.tableViewData
|
||||
return self.v2rayItemList
|
||||
}
|
||||
|
||||
// get count from v2ray server list
|
||||
static func count() -> Int {
|
||||
return self.tableViewData.count
|
||||
return self.v2rayItemList.count
|
||||
}
|
||||
|
||||
static func edit(rowIndex:Int, remark:String) {
|
||||
if !self.tableViewData.indices.contains(rowIndex) {
|
||||
print("index out of range",rowIndex)
|
||||
if !self.v2rayItemList.indices.contains(rowIndex) {
|
||||
NSLog("index out of range",rowIndex)
|
||||
return
|
||||
}
|
||||
|
||||
// update list
|
||||
self.tableViewData[rowIndex].remark = remark
|
||||
self.v2rayItemList[rowIndex].remark = remark
|
||||
|
||||
// save
|
||||
let v2ray = self.tableViewData[rowIndex]
|
||||
let v2ray = self.v2rayItemList[rowIndex]
|
||||
v2ray.remark = remark
|
||||
v2ray.store()
|
||||
}
|
||||
|
||||
// move item to new index
|
||||
static func move(oldIndex:Int, newIndex:Int) {
|
||||
if !V2rayServer.tableViewData.indices.contains(oldIndex) {
|
||||
print("index out of range",oldIndex)
|
||||
if !V2rayServer.v2rayItemList.indices.contains(oldIndex) {
|
||||
NSLog("index out of range",oldIndex)
|
||||
return
|
||||
}
|
||||
if !V2rayServer.tableViewData.indices.contains(newIndex) {
|
||||
print("index out of range",newIndex)
|
||||
if !V2rayServer.v2rayItemList.indices.contains(newIndex) {
|
||||
NSLog("index out of range",newIndex)
|
||||
return
|
||||
}
|
||||
|
||||
let o = self.tableViewData[oldIndex]
|
||||
self.tableViewData.remove(at: oldIndex)
|
||||
self.tableViewData.insert(o, at: newIndex)
|
||||
let o = self.v2rayItemList[oldIndex]
|
||||
self.v2rayItemList.remove(at: oldIndex)
|
||||
self.v2rayItemList.insert(o, at: newIndex)
|
||||
|
||||
// update server list UserDefaults
|
||||
self.saveItemList()
|
||||
@ -98,8 +97,8 @@ class V2rayServer: NSObject {
|
||||
|
||||
// add v2ray server (tmp)
|
||||
static func add() {
|
||||
if self.tableViewData.count > 20 {
|
||||
print("over max len")
|
||||
if self.v2rayItemList.count > 20 {
|
||||
NSLog("over max len")
|
||||
return
|
||||
}
|
||||
|
||||
@ -116,7 +115,7 @@ class V2rayServer: NSObject {
|
||||
v2ray.store()
|
||||
|
||||
// just add to mem
|
||||
self.tableViewData.append(v2ray)
|
||||
self.v2rayItemList.append(v2ray)
|
||||
|
||||
// update server list UserDefaults
|
||||
self.saveItemList()
|
||||
@ -124,21 +123,27 @@ class V2rayServer: NSObject {
|
||||
|
||||
// remove v2ray server (tmp and UserDefaults and config json file)
|
||||
static func remove(idx: Int) {
|
||||
if !V2rayServer.tableViewData.indices.contains(idx) {
|
||||
print("index out of range",idx)
|
||||
if !V2rayServer.v2rayItemList.indices.contains(idx) {
|
||||
NSLog("index out of range",idx)
|
||||
return
|
||||
}
|
||||
|
||||
let v2ray = V2rayServer.tableViewData[idx]
|
||||
let v2ray = V2rayServer.v2rayItemList[idx]
|
||||
|
||||
// delete from tmp
|
||||
self.tableViewData.remove(at: idx)
|
||||
self.v2rayItemList.remove(at: idx)
|
||||
|
||||
// delete from v2ray UserDefaults
|
||||
v2rayItem.remove(name: v2ray.name)
|
||||
|
||||
// update server list UserDefaults
|
||||
self.saveItemList()
|
||||
|
||||
// if cuerrent item is default
|
||||
let curName = UserDefaults.get(forKey: .v2rayCurrentServerName)
|
||||
if curName != nil && v2ray.name == curName {
|
||||
UserDefaults.del(forKey: .v2rayCurrentServerName)
|
||||
}
|
||||
}
|
||||
|
||||
// update server list UserDefaults
|
||||
@ -158,63 +163,98 @@ class V2rayServer: NSObject {
|
||||
|
||||
// load json file data
|
||||
static func loadV2rayItem(idx:Int) -> v2rayItem? {
|
||||
if !V2rayServer.tableViewData.indices.contains(idx) {
|
||||
print("index out of range",idx)
|
||||
if !V2rayServer.v2rayItemList.indices.contains(idx) {
|
||||
NSLog("index out of range",idx)
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.tableViewData[idx]
|
||||
return self.v2rayItemList[idx]
|
||||
}
|
||||
|
||||
// load selected v2ray item
|
||||
static func loadSelectedItem() -> v2rayItem? {
|
||||
guard let curName = UserDefaults.get(forKey: .v2rayCurrentServerName) else {
|
||||
return nil
|
||||
|
||||
var v2ray:v2rayItem? = nil
|
||||
|
||||
if let curName = UserDefaults.get(forKey: .v2rayCurrentServerName) {
|
||||
v2ray = v2rayItem.load(name: curName)
|
||||
}
|
||||
|
||||
return v2rayItem.load(name: curName)
|
||||
// if default server not fould
|
||||
if v2ray == nil {
|
||||
for item in self.v2rayItemList {
|
||||
if item.usable {
|
||||
v2ray = v2rayItem.load(name: item.name)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v2ray
|
||||
}
|
||||
|
||||
// save json data into local file
|
||||
// create current v2ray server json file
|
||||
static func createJsonFile(item:v2rayItem) {
|
||||
let jsonText = item.json
|
||||
|
||||
// path: /Application/V2rayU.app/Contents/Resources/config.json
|
||||
guard let jsonFile = V2rayServer.getJsonFile() else {
|
||||
NSLog("unable get config file path")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let jsonFilePath = URL.init(fileURLWithPath: jsonFile)
|
||||
|
||||
try! FileManager.default.removeItem(at: jsonFilePath)
|
||||
|
||||
try jsonText.write(to: jsonFilePath, atomically: true, encoding: String.Encoding.utf8)
|
||||
} catch {
|
||||
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
|
||||
NSLog("save json file fail.",item.remark)
|
||||
}
|
||||
}
|
||||
|
||||
// save json data
|
||||
static func save(idx:Int, jsonData:String) {
|
||||
if !self.tableViewData.indices.contains(idx) {
|
||||
print("index out of range",idx)
|
||||
if !self.v2rayItemList.indices.contains(idx) {
|
||||
NSLog("index out of range",idx)
|
||||
return
|
||||
}
|
||||
|
||||
let v2ray = self.tableViewData[idx]
|
||||
let v2ray = self.v2rayItemList[idx]
|
||||
if v2ray.name == "" {
|
||||
print("name is empty")
|
||||
NSLog("name is empty")
|
||||
return
|
||||
}
|
||||
|
||||
guard let json = try? JSON(data: jsonData.data(using: String.Encoding.utf8, allowLossyConversion: false)!) else {
|
||||
print("invalid json")
|
||||
NSLog("invalid json")
|
||||
return
|
||||
}
|
||||
|
||||
if !json.exists(){
|
||||
print("invalid json")
|
||||
NSLog("invalid json")
|
||||
return
|
||||
}
|
||||
|
||||
if !json["dns"].exists() {
|
||||
print("missing inbound")
|
||||
NSLog("missing inbound")
|
||||
return
|
||||
}
|
||||
|
||||
if !json["inbound"].exists() {
|
||||
print("missing inbound")
|
||||
NSLog("missing inbound")
|
||||
return
|
||||
}
|
||||
|
||||
if !json["outbound"].exists() {
|
||||
print("missing outbound")
|
||||
NSLog("missing outbound")
|
||||
return
|
||||
}
|
||||
|
||||
if !json["routing"].exists() {
|
||||
print("missing routing")
|
||||
NSLog("missing routing")
|
||||
return
|
||||
}
|
||||
|
||||
@ -224,7 +264,21 @@ class V2rayServer: NSObject {
|
||||
v2ray.store()
|
||||
|
||||
// update current
|
||||
self.tableViewData[idx].usable = true
|
||||
self.v2rayItemList[idx] = v2ray
|
||||
|
||||
// if just one usable server
|
||||
// set as default server
|
||||
var usableCount = 0
|
||||
for item in v2rayItemList {
|
||||
if item.usable {
|
||||
usableCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
// contain self
|
||||
if usableCount <= 1 {
|
||||
UserDefaults.set(forKey: .v2rayCurrentServerName, value: v2ray.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,11 +286,11 @@ class V2rayServer: NSObject {
|
||||
class v2rayItem: NSObject, NSCoding {
|
||||
var name: String
|
||||
var remark: String
|
||||
var usable: Bool
|
||||
var json: String
|
||||
|
||||
var usable: Bool
|
||||
|
||||
// init
|
||||
required init(name:String="", remark:String="", usable: Bool=false, json:String="") {
|
||||
required init(name: String, remark: String, usable: Bool, json: String="") {
|
||||
self.name = name
|
||||
self.remark = remark
|
||||
self.json = json
|
||||
@ -248,7 +302,7 @@ class v2rayItem: NSObject, NSCoding {
|
||||
self.name = decoder.decodeObject(forKey: "Name") as? String ?? ""
|
||||
self.remark = decoder.decodeObject(forKey: "Remark") as? String ?? ""
|
||||
self.json = decoder.decodeObject(forKey: "Json") as? String ?? ""
|
||||
self.usable = decoder.decodeObject(forKey: "Usable") as? Bool ?? false
|
||||
self.usable = decoder.decodeBool(forKey: "Usable")
|
||||
}
|
||||
|
||||
// object encode
|
||||
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import os.log
|
||||
|
||||
class V2rayULauncherApplication: NSApplication {
|
||||
let strongDelegate = AppDelegate()
|
||||
@ -55,7 +56,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
print("helper app terminated")
|
||||
// Insert code here to tear down your application
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user