Can export diagnosis to file.
This commit is contained in:
@ -53,6 +53,7 @@
|
|||||||
9B7297E7214D69C300FD24AA /* libmbedcrypto.2.12.0.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7297E5214D68F800FD24AA /* libmbedcrypto.2.12.0.dylib */; };
|
9B7297E7214D69C300FD24AA /* libmbedcrypto.2.12.0.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7297E5214D68F800FD24AA /* libmbedcrypto.2.12.0.dylib */; };
|
||||||
9B7297EA214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7297E8214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift */; };
|
9B7297EA214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7297E8214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift */; };
|
||||||
9B7297EC214DA88A00FD24AA /* ShareServerProfilesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7297EE214DA88A00FD24AA /* ShareServerProfilesWindowController.xib */; };
|
9B7297EC214DA88A00FD24AA /* ShareServerProfilesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7297EE214DA88A00FD24AA /* ShareServerProfilesWindowController.xib */; };
|
||||||
|
9B84DAED2163A72F00DFF068 /* Diagnose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B84DAEC2163A72F00DFF068 /* Diagnose.swift */; };
|
||||||
9B86459D1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */; };
|
9B86459D1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */; };
|
||||||
9B938D991E864B38005F5636 /* menu_g_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B938D931E864B38005F5636 /* menu_g_icon.png */; };
|
9B938D991E864B38005F5636 /* menu_g_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B938D931E864B38005F5636 /* menu_g_icon.png */; };
|
||||||
9B938D9A1E864B38005F5636 /* menu_g_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B938D941E864B38005F5636 /* menu_g_icon@2x.png */; };
|
9B938D9A1E864B38005F5636 /* menu_g_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B938D941E864B38005F5636 /* menu_g_icon@2x.png */; };
|
||||||
@ -208,6 +209,7 @@
|
|||||||
9B7297E8214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareServerProfilesWindowController.swift; sourceTree = "<group>"; };
|
9B7297E8214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareServerProfilesWindowController.swift; sourceTree = "<group>"; };
|
||||||
9B7297ED214DA88A00FD24AA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ShareServerProfilesWindowController.xib; sourceTree = "<group>"; };
|
9B7297ED214DA88A00FD24AA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ShareServerProfilesWindowController.xib; sourceTree = "<group>"; };
|
||||||
9B7297F0214DA89000FD24AA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ShareServerProfilesWindowController.strings"; sourceTree = "<group>"; };
|
9B7297F0214DA89000FD24AA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ShareServerProfilesWindowController.strings"; sourceTree = "<group>"; };
|
||||||
|
9B84DAEC2163A72F00DFF068 /* Diagnose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Diagnose.swift; sourceTree = "<group>"; };
|
||||||
9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyInterfacesViewCtrl.swift; sourceTree = "<group>"; };
|
9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyInterfacesViewCtrl.swift; sourceTree = "<group>"; };
|
||||||
9B938D931E864B38005F5636 /* menu_g_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_g_icon.png; sourceTree = "<group>"; };
|
9B938D931E864B38005F5636 /* menu_g_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_g_icon.png; sourceTree = "<group>"; };
|
||||||
9B938D941E864B38005F5636 /* menu_g_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_g_icon@2x.png"; sourceTree = "<group>"; };
|
9B938D941E864B38005F5636 /* menu_g_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_g_icon@2x.png"; sourceTree = "<group>"; };
|
||||||
@ -389,6 +391,7 @@
|
|||||||
9BA04B221D23D5A5005AAD7F /* ProxyConfTool.m */,
|
9BA04B221D23D5A5005AAD7F /* ProxyConfTool.m */,
|
||||||
9B5831F41E7302F8009D5B7D /* ShortcutsController.h */,
|
9B5831F41E7302F8009D5B7D /* ShortcutsController.h */,
|
||||||
9B5831F51E7302F8009D5B7D /* ShortcutsController.m */,
|
9B5831F51E7302F8009D5B7D /* ShortcutsController.m */,
|
||||||
|
9B84DAEC2163A72F00DFF068 /* Diagnose.swift */,
|
||||||
);
|
);
|
||||||
path = "ShadowsocksX-NG";
|
path = "ShadowsocksX-NG";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -847,6 +850,7 @@
|
|||||||
9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */,
|
9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */,
|
||||||
9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */,
|
9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */,
|
||||||
9B0BFFE91D0460A70040E62B /* AppDelegate.swift in Sources */,
|
9B0BFFE91D0460A70040E62B /* AppDelegate.swift in Sources */,
|
||||||
|
9B84DAED2163A72F00DFF068 /* Diagnose.swift in Sources */,
|
||||||
9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */,
|
9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */,
|
||||||
9B5831FF1E741969009D5B7D /* PreferencesWinController.swift in Sources */,
|
9B5831FF1E741969009D5B7D /* PreferencesWinController.swift in Sources */,
|
||||||
9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */,
|
9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */,
|
||||||
|
@ -386,6 +386,29 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
|||||||
NSWorkspace.shared.open(URL(string: "https://github.com/shadowsocks/ShadowsocksX-NG/releases")!)
|
NSWorkspace.shared.open(URL(string: "https://github.com/shadowsocks/ShadowsocksX-NG/releases")!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBAction func exportDiagnosis(_ sender: NSMenuItem) {
|
||||||
|
let savePanel = NSSavePanel()
|
||||||
|
savePanel.title = "Save All Server URLs To File".localized
|
||||||
|
savePanel.canCreateDirectories = true
|
||||||
|
savePanel.allowedFileTypes = ["txt"]
|
||||||
|
savePanel.isExtensionHidden = false
|
||||||
|
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateFormat = "yyyyMMdd_HHmmss"
|
||||||
|
let dateString = formatter.string(from: Date())
|
||||||
|
|
||||||
|
savePanel.nameFieldStringValue = "ShadowsocksX-NG_diagnose_\(dateString)"
|
||||||
|
|
||||||
|
savePanel.becomeKey()
|
||||||
|
let result = savePanel.runModal()
|
||||||
|
if (result.rawValue == NSFileHandlingPanelOKButton) {
|
||||||
|
if let url = savePanel.url {
|
||||||
|
let diagnosisText = diagnose()
|
||||||
|
try! diagnosisText.write(to: url, atomically: false, encoding: String.Encoding.utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@IBAction func showHelp(_ sender: NSMenuItem) {
|
@IBAction func showHelp(_ sender: NSMenuItem) {
|
||||||
NSWorkspace.shared.open(URL(string: "https://github.com/shadowsocks/ShadowsocksX-NG/wiki")!)
|
NSWorkspace.shared.open(URL(string: "https://github.com/shadowsocks/ShadowsocksX-NG/wiki")!)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.18"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
@ -123,6 +123,12 @@
|
|||||||
<action selector="showLogs:" target="Voe-Tx-rLC" id="5FZ-Xo-DGb"/>
|
<action selector="showLogs:" target="Voe-Tx-rLC" id="5FZ-Xo-DGb"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem title="Export Diagnosis..." id="eNh-vY-utd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="exportDiagnosis:" target="Voe-Tx-rLC" id="YM9-l3-PHa"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
<menuItem title="Check for Updates..." id="hLv-bp-doM">
|
<menuItem title="Check for Updates..." id="hLv-bp-doM">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
93
ShadowsocksX-NG/Diagnose.swift
Normal file
93
ShadowsocksX-NG/Diagnose.swift
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
//
|
||||||
|
// diagnose.swift
|
||||||
|
// ShadowsocksX-NG
|
||||||
|
//
|
||||||
|
// Created by 邱宇舟 on 2018/10/2.
|
||||||
|
// Copyright © 2018 qiuyuzhou. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
func shell(_ args: String...) -> String {
|
||||||
|
let task = Process()
|
||||||
|
task.launchPath = "/usr/bin/env"
|
||||||
|
task.arguments = args
|
||||||
|
|
||||||
|
let pipe = Pipe()
|
||||||
|
task.standardOutput = pipe
|
||||||
|
|
||||||
|
task.launch()
|
||||||
|
task.waitUntilExit()
|
||||||
|
|
||||||
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
let output = String(data: data, encoding: String.Encoding.utf8)
|
||||||
|
|
||||||
|
return output ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func diagnose() -> String {
|
||||||
|
var strs = [String]()
|
||||||
|
|
||||||
|
strs.append("\n-----------------------------------\n")
|
||||||
|
let infoDict = Bundle.main.infoDictionary!
|
||||||
|
let infoDictJsonData = try! JSONSerialization.data(withJSONObject: infoDict, options: JSONSerialization.WritingOptions.prettyPrinted)
|
||||||
|
|
||||||
|
strs.append(String(data: infoDictJsonData, encoding: String.Encoding.utf8)!)
|
||||||
|
strs.append("\n-----------------------------------\n")
|
||||||
|
|
||||||
|
let defaults = UserDefaults.standard
|
||||||
|
let keys = [
|
||||||
|
"ShadowsocksOn",
|
||||||
|
"ShadowsocksRunningMode",
|
||||||
|
"LocalSocks5.ListenPort",
|
||||||
|
"LocalSocks5.ListenAddress",
|
||||||
|
"PacServer.ListenPort",
|
||||||
|
"LocalSocks5.Timeout",
|
||||||
|
"LocalSocks5.EnableUDPRelay",
|
||||||
|
"LocalSocks5.EnableVerboseMode",
|
||||||
|
"GFWListURL",
|
||||||
|
"LocalHTTP.ListenAddress",
|
||||||
|
"LocalHTTP.ListenPort",
|
||||||
|
"LocalHTTPOn",
|
||||||
|
"LocalHTTP.FollowGlobal",
|
||||||
|
"ProxyExceptions",
|
||||||
|
]
|
||||||
|
|
||||||
|
strs.append("Preferences:\n")
|
||||||
|
for key in keys {
|
||||||
|
if let obj = defaults.object(forKey: key) {
|
||||||
|
strs.append("\(key)=\(obj)\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
strs.append("Active server profile: \n")
|
||||||
|
|
||||||
|
if let profile = ServerProfileManager.instance.getActiveProfile() {
|
||||||
|
strs.append(profile.debugString())
|
||||||
|
} else {
|
||||||
|
strs.append("No actived server profile!")
|
||||||
|
}
|
||||||
|
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
strs.append("$ ls -l ~/Library/Application Support/ShadowsocksX-NG/\n")
|
||||||
|
strs.append(shell("ls", "-l", NSHomeDirectory() + "/Library/Application Support/ShadowsocksX-NG/"))
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
strs.append("$ ls -l ~/Library/LaunchAgents/\n")
|
||||||
|
strs.append(shell("ls", "-l", NSHomeDirectory() + "/Library/LaunchAgents/"))
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
strs.append("$ ls -l ~/.ShadowsocksX-NG/\n")
|
||||||
|
strs.append(shell("ls", "-l", NSHomeDirectory() + "/.ShadowsocksX-NG/"))
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
strs.append("$ ls -l /Library/Application Support/ShadowsocksX-NG/")
|
||||||
|
strs.append(shell("ls", "-l", "/Library/Application Support/ShadowsocksX-NG/"))
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
strs.append("$ lsof -PiTCP -sTCP:LISTEN")
|
||||||
|
strs.append(shell("lsof", "-PiTCP", "-sTCP:LISTEN"))
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
strs.append("$ ifconfig")
|
||||||
|
strs.append(shell("ifconfig"))
|
||||||
|
strs.append("-----------------------------------\n")
|
||||||
|
|
||||||
|
let output = strs.joined()
|
||||||
|
return output
|
||||||
|
}
|
@ -194,6 +194,17 @@ class ServerProfile: NSObject, NSCopying {
|
|||||||
|
|
||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func debugString() -> String {
|
||||||
|
var buf = ""
|
||||||
|
print("ServerHost=\(String(repeating: "*", count: serverHost.count))", to: &buf)
|
||||||
|
print("ServerPort=\(serverPort)", to: &buf)
|
||||||
|
print("Method=\(method)", to: &buf)
|
||||||
|
print("Password=\(String(repeating: "*", count: password.count))", to: &buf)
|
||||||
|
print("Plugin=\(plugin)", to: &buf)
|
||||||
|
print("PluginOptions=\(pluginOptions)", to: &buf)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
func isValid() -> Bool {
|
func isValid() -> Bool {
|
||||||
func validateIpAddress(_ ipToValidate: String) -> Bool {
|
func validateIpAddress(_ ipToValidate: String) -> Bool {
|
||||||
|
Reference in New Issue
Block a user