Skip to content

Commit 683840b

Browse files
committed
Add HTTP API & AppleScript support.
Refactor in class AppDelegate.
1 parent 9508af2 commit 683840b

File tree

6 files changed

+278
-34
lines changed

6 files changed

+278
-34
lines changed

ShadowsocksX-NG.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
1C82DBA81FA96C7500B32551 /* obfs-local in Resources */ = {isa = PBXBuildFile; fileRef = 1C82DBA51FA96C7400B32551 /* obfs-local */; };
1212
1C82DBAA1FA96FB600B32551 /* install_simple_obfs.sh in Resources */ = {isa = PBXBuildFile; fileRef = 1C82DBA91FA96F0300B32551 /* install_simple_obfs.sh */; };
1313
258E511BA910B0521B24DAB8 /* Pods_ShadowsocksX_NG.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 283ED1A8E9B711AC65670031 /* Pods_ShadowsocksX_NG.framework */; };
14+
8EE2EDD8214F7CEC00FB4562 /* AppleScriptUserProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE2EDD4214F7CEC00FB4562 /* AppleScriptUserProxy.swift */; };
15+
8EE2EDD9214F7CEC00FB4562 /* HTTPUserProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE2EDD6214F7CEC00FB4562 /* HTTPUserProxy.swift */; };
16+
8EE2EDDA214F7CEC00FB4562 /* AppleScriptDefinition.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 8EE2EDD7214F7CEC00FB4562 /* AppleScriptDefinition.sdef */; };
1417
9B07EFA71D048BBB0052D9DF /* ss-local in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA61D048BBB0052D9DF /* ss-local */; };
1518
9B07EFAC1D048E880052D9DF /* menu_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA81D048E880052D9DF /* menu_icon@2x.png */; };
1619
9B07EFAD1D048E880052D9DF /* menu_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA91D048E880052D9DF /* menu_icon.png */; };
@@ -145,6 +148,9 @@
145148
50D54926AA21B0D4D8DD9C4F /* Pods-ShadowsocksX-NGUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShadowsocksX-NGUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ShadowsocksX-NGUITests/Pods-ShadowsocksX-NGUITests.release.xcconfig"; sourceTree = "<group>"; };
146149
58907E7F50405104B42CB189 /* Pods-ShadowsocksX-NGUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShadowsocksX-NGUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ShadowsocksX-NGUITests/Pods-ShadowsocksX-NGUITests.debug.xcconfig"; sourceTree = "<group>"; };
147150
5B6203C1228FCD3D365814AC /* Pods-ShadowsocksX-NGTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShadowsocksX-NGTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ShadowsocksX-NGTests/Pods-ShadowsocksX-NGTests.debug.xcconfig"; sourceTree = "<group>"; };
151+
8EE2EDD4214F7CEC00FB4562 /* AppleScriptUserProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleScriptUserProxy.swift; sourceTree = "<group>"; };
152+
8EE2EDD6214F7CEC00FB4562 /* HTTPUserProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPUserProxy.swift; sourceTree = "<group>"; };
153+
8EE2EDD7214F7CEC00FB4562 /* AppleScriptDefinition.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = AppleScriptDefinition.sdef; sourceTree = "<group>"; };
148154
9B07EFA61D048BBB0052D9DF /* ss-local */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = "ss-local"; sourceTree = "<group>"; };
149155
9B07EFA81D048E880052D9DF /* menu_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icon@2x.png"; sourceTree = "<group>"; };
150156
9B07EFA91D048E880052D9DF /* menu_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_icon.png; sourceTree = "<group>"; };
@@ -359,6 +365,9 @@
359365
isa = PBXGroup;
360366
children = (
361367
9BB706A51D1B982300551F0E /* SWBApplication.m */,
368+
8EE2EDD7214F7CEC00FB4562 /* AppleScriptDefinition.sdef */,
369+
8EE2EDD4214F7CEC00FB4562 /* AppleScriptUserProxy.swift */,
370+
8EE2EDD6214F7CEC00FB4562 /* HTTPUserProxy.swift */,
362371
9BB706A61D1B982300551F0E /* SWBApplication.h */,
363372
9B3FFF511D09DBA20019A709 /* ShadowsocksX-NG-Bridging-Header.h */,
364373
9B3FFF151D072FDE0019A709 /* LaunchAtLoginController.h */,
@@ -635,6 +644,7 @@
635644
9B3FFF341D08CEF70019A709 /* SWBQRCodeWindowController.xib in Resources */,
636645
9B3FFF231D088E8D0019A709 /* abp.js in Resources */,
637646
9B07EFAD1D048E880052D9DF /* menu_icon.png in Resources */,
647+
8EE2EDDA214F7CEC00FB4562 /* AppleScriptDefinition.sdef in Resources */,
638648
9BAFE2E21E83ED7F00F71CCE /* PreferencesWinController.xib in Resources */,
639649
9B0BFFEB1D0460A70040E62B /* Assets.xcassets in Resources */,
640650
08FCA0FF1E24BE1A0070984F /* example-gui-config.json in Resources */,
@@ -823,10 +833,12 @@
823833
9BB706A71D1B982300551F0E /* SWBApplication.m in Sources */,
824834
9B3FFF1E1D0732660019A709 /* Utils.m in Sources */,
825835
9B7297EA214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift in Sources */,
836+
8EE2EDD9214F7CEC00FB4562 /* HTTPUserProxy.swift in Sources */,
826837
9B3FFF321D08CEE40019A709 /* SWBQRCodeWindowController.m in Sources */,
827838
9B3FFF211D08826E0019A709 /* PACUtils.swift in Sources */,
828839
9B3FFF141D0705810019A709 /* Notifications.swift in Sources */,
829840
9BEEF0701D04DDB100FC52B3 /* ServerProfileManager.swift in Sources */,
841+
8EE2EDD8214F7CEC00FB4562 /* AppleScriptUserProxy.swift in Sources */,
830842
9BEEF06E1D04DCE400FC52B3 /* ServerProfile.swift in Sources */,
831843
9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */,
832844
9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */,

ShadowsocksX-NG/AppDelegate.swift

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
4040

4141
@IBOutlet weak var lanchAtLoginMenuItem: NSMenuItem!
4242

43+
4344
@IBOutlet weak var hudWindow: NSPanel!
4445
@IBOutlet weak var panelView: NSView!
4546
@IBOutlet weak var isNameTextField: NSTextField!
46-
47+
4748
let kProfileMenuItemIndexBase = 100
48-
49+
4950
var statusItem: NSStatusItem!
5051
static let StatusItemIconWidth: CGFloat = NSStatusItem.variableLength
5152

@@ -133,7 +134,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
133134
self.updateServersMenu()
134135
self.updateRunningModeMenu()
135136
SyncSSLocal()
136-
}
137+
}
137138
)
138139
_ = notifyCenter.rx.notification(NOTIFY_TOGGLE_RUNNING_SHORTCUT)
139140
.subscribe(onNext: { noti in
@@ -180,9 +181,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
180181
ProxyConfHelper.install()
181182
ProxyConfHelper.startMonitorPAC()
182183
applyConfig()
183-
184+
184185
// Register global hotkey
185186
ShortcutsController.bindShortcuts()
187+
188+
// Start API Server
189+
HTTPUserProxy.shard.start()
186190
}
187191

188192
func applicationWillTerminate(_ aNotification: Notification) {
@@ -191,7 +195,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
191195
StopPrivoxy()
192196
ProxyConfHelper.disableProxy()
193197
}
194-
198+
195199
func applyConfig() {
196200
SyncSSLocal()
197201

@@ -211,7 +215,21 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
211215
ProxyConfHelper.disableProxy()
212216
}
213217
}
214-
218+
219+
func changeMode(mode:String!) {
220+
let defaults = UserDefaults.standard
221+
222+
switch mode{
223+
case "auto":defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
224+
case "global":defaults.setValue("global", forKey: "ShadowsocksRunningMode")
225+
case "manual":defaults.setValue("manual", forKey: "ShadowsocksRunningMode")
226+
default: fatalError()
227+
}
228+
229+
updateRunningModeMenu()
230+
applyConfig()
231+
}
232+
215233
// MARK: - UI Methods
216234
@IBAction func toggleRunning(_ sender: NSMenuItem) {
217235
self.doToggleRunning(showToast: false)
@@ -324,26 +342,17 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
324342
])
325343
}
326344
}
327-
345+
328346
@IBAction func selectPACMode(_ sender: NSMenuItem) {
329-
let defaults = UserDefaults.standard
330-
defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
331-
updateRunningModeMenu()
332-
applyConfig()
347+
changeMode(mode: "auto")
333348
}
334349

335350
@IBAction func selectGlobalMode(_ sender: NSMenuItem) {
336-
let defaults = UserDefaults.standard
337-
defaults.setValue("global", forKey: "ShadowsocksRunningMode")
338-
updateRunningModeMenu()
339-
applyConfig()
351+
changeMode(mode: "global")
340352
}
341353

342354
@IBAction func selectManualMode(_ sender: NSMenuItem) {
343-
let defaults = UserDefaults.standard
344-
defaults.setValue("manual", forKey: "ShadowsocksRunningMode")
345-
updateRunningModeMenu()
346-
applyConfig()
355+
changeMode(mode: "manual")
347356
}
348357

349358
@IBAction func editServerPreferences(_ sender: NSMenuItem) {
@@ -369,19 +378,27 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
369378
allInOnePreferencesWinCtrl.window?.makeKeyAndOrderFront(self)
370379
}
371380

372-
@IBAction func selectServer(_ sender: NSMenuItem) {
373-
let index = sender.tag - kProfileMenuItemIndexBase
381+
func changeServer(@objc uuid: String) {
374382
let spMgr = ServerProfileManager.instance
375-
let newProfile = spMgr.profiles[index]
376-
if newProfile.uuid != spMgr.activeProfileId {
377-
spMgr.setActiveProfiledId(newProfile.uuid)
383+
384+
if uuid != spMgr.activeProfileId {
385+
spMgr.setActiveProfiledId(uuid)
378386
updateServersMenu()
379387
SyncSSLocal()
380388
applyConfig()
381389
}
390+
382391
updateRunningModeMenu()
383392
}
384393

394+
@IBAction func selectServer(_ sender: NSMenuItem) {
395+
let index = sender.tag - kProfileMenuItemIndexBase
396+
let spMgr = ServerProfileManager.instance
397+
let newProfileId = spMgr.profiles[index].uuid
398+
399+
changeServer(uuid:newProfileId)
400+
}
401+
385402
@IBAction func copyExportCommand(_ sender: NSMenuItem) {
386403
// Get the Http proxy config.
387404
let defaults = UserDefaults.standard
@@ -427,7 +444,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
427444

428445
func updateRunningModeMenu() {
429446
let defaults = UserDefaults.standard
430-
let mode = defaults.string(forKey: "ShadowsocksRunningMode")
447+
let mode = defaults.string(forKey: "ShadowsocksRunningMosde")
431448

432449
var serverMenuText = "Servers".localized
433450

@@ -468,12 +485,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
468485
if isOn {
469486
if let m = mode {
470487
switch m {
471-
case "auto":
472-
statusItem.image = NSImage(named: NSImage.Name(rawValue: "menu_p_icon"))
473-
case "global":
474-
statusItem.image = NSImage(named: NSImage.Name(rawValue: "menu_g_icon"))
475-
case "manual":
476-
statusItem.image = NSImage(named: NSImage.Name(rawValue: "menu_m_icon"))
488+
case "auto":
489+
statusItem.image = NSImage(named: NSImage.Name(rawValue: "menu_p_icon"))
490+
case "global":
491+
statusItem.image = NSImage(named: NSImage.Name(rawValue: "menu_g_icon"))
492+
case "manual":
493+
statusItem.image = NSImage(named: NSImage.Name(rawValue: "menu_m_icon"))
477494
default: break
478495
}
479496
statusItem.image?.isTemplate = true
@@ -512,17 +529,17 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
512529
func updateServersMenu() {
513530
guard let menu = serversMenuItem.submenu else { return }
514531

532+
515533
let mgr = ServerProfileManager.instance
516534
let profiles = mgr.profiles
517-
518535
// Remove all profile menu items
519536
let beginIndex = menu.index(of: serverProfilesBeginSeparatorMenuItem) + 1
520537
let endIndex = menu.index(of: serverProfilesEndSeparatorMenuItem)
521538
// Remove from end to begin, so the index won't change :)
522539
for index in (beginIndex..<endIndex).reversed() {
523540
menu.removeItem(at: index)
524541
}
525-
542+
526543
// Insert all profile menu items
527544
for (i, profile) in profiles.enumerated().reversed() {
528545
let item = NSMenuItem()
@@ -534,7 +551,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
534551

535552
menu.insertItem(item, at: beginIndex)
536553
}
537-
554+
538555
// End separator is redundant if profile section is empty
539556
serverProfilesEndSeparatorMenuItem.isHidden = profiles.isEmpty
540557
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
3+
4+
<dictionary title="ShadowsocksX-NG">
5+
6+
<suite name="ShadowsocksX-NG Suite" code="sktc">
7+
<enumeration name="Mode" code="mode">
8+
<enumerator name="auto" code="auto">
9+
<cocoa string-value="auto"/>
10+
</enumerator>
11+
<enumerator name="manual" code="manu">
12+
<cocoa string-value="manual"/>
13+
</enumerator>
14+
<enumerator name="global" code="glbl">
15+
<cocoa string-value="global"/>
16+
</enumerator>
17+
</enumeration>
18+
19+
<command name="isRunning" code="isruning">
20+
<cocoa class="ShadowsocksX_NG.AppleScriptUserProxy"/>
21+
<result type="boolean"/>
22+
</command>
23+
24+
<command name="toggle" code="sstoggle" description="Turn on/off the client.">
25+
<cocoa class="ShadowsocksX_NG.AppleScriptUserProxy"/>
26+
</command>
27+
28+
<command name="mode" code="currmode">
29+
<cocoa class="ShadowsocksX_NG.AppleScriptUserProxy"/>
30+
<result type="Mode"/>
31+
</command>
32+
33+
<command name="change mode" code="chagmode">
34+
<cocoa class="ShadowsocksX_NG.AppleScriptUserProxy"/>
35+
<direct-parameter type="Mode"/>
36+
</command>
37+
38+
<command name="servers" code="sevrlist">
39+
<cocoa class="ShadowsocksX_NG.AppleScriptUserProxy"/>
40+
<result>
41+
<type type="text" list="yes"/>
42+
</result>
43+
</command>
44+
45+
<command name="change server" code="chagServ">
46+
<cocoa class="ShadowsocksX_NG.AppleScriptUserProxy"/>
47+
<direct-parameter type="text"/>
48+
</command>
49+
</suite>
50+
51+
</dictionary>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//
2+
// AppleScriptCommand.swift
3+
// ShadowsocksX-NG
4+
//
5+
// Created by melonEater on 2018/9/6.
6+
// Copyright © 2018 qiuyuzhou. All rights reserved.
7+
//
8+
9+
import Cocoa
10+
11+
12+
class AppleScriptUserProxy: NSScriptCommand {
13+
let appdeleget = NSApplication.shared.delegate as! AppDelegate
14+
let SerMgr = ServerProfileManager.instance
15+
16+
override func performDefaultImplementation() -> Any? {
17+
switch(self.commandDescription.commandName) {
18+
case "isRunning":
19+
return isRunning()
20+
case "toggle":
21+
toggle()
22+
case "mode":
23+
return getMode()
24+
case "change mode":
25+
changeMode(mode: self.directParameter as! String)
26+
case "servers":
27+
return getServerList();
28+
case "change server":
29+
setServer(remark: self.directParameter as! String)
30+
default:
31+
return nil;
32+
}
33+
return nil
34+
}
35+
36+
func toggle() {
37+
self.appdeleget.doToggleRunning(showToast: false)
38+
}
39+
40+
func isRunning() -> Bool {
41+
let isOn = UserDefaults.standard.bool(forKey: "ShadowsocksOn")
42+
return isOn
43+
}
44+
45+
func getMode() -> String {
46+
return UserDefaults.standard.string(forKey: "ShadowsocksRunningMode") as! String
47+
}
48+
49+
func changeMode(mode:String) {
50+
appdeleget.changeMode(mode: mode)
51+
}
52+
53+
func getServerList() -> [String] {
54+
var data = [String]()
55+
56+
for each in self.SerMgr.profiles{
57+
data.append(each.remark)
58+
}
59+
60+
return data
61+
}
62+
63+
func setServer(remark: String) {
64+
for each in self.SerMgr.profiles{
65+
if (each.remark == remark) {
66+
self.appdeleget.changeServer(uuid: each.uuid)
67+
return
68+
}
69+
}
70+
}
71+
}
72+

0 commit comments

Comments
 (0)