Skip to content

Commit 12d6d48

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

File tree

6 files changed

+282
-34
lines changed

6 files changed

+282
-34
lines changed

ShadowsocksX-NG.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
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+
8EE2EDC2214F6D9F00FB4562 /* HTTPUserProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE2EDBF214F6D9F00FB4562 /* HTTPUserProxy.swift */; };
15+
8EE2EDC3214F6D9F00FB4562 /* AppleScriptUserProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE2EDC1214F6D9F00FB4562 /* AppleScriptUserProxy.swift */; };
16+
8EE2EDC5214F6DA600FB4562 /* AppleScriptDefinition.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 8EE2EDC4214F6DA600FB4562 /* AppleScriptDefinition.sdef */; };
17+
8EE2EDC7214F6F0C00FB4562 /* ShadowsocksX-NG in Resources */ = {isa = PBXBuildFile; fileRef = 8EE2EDC6214F6F0C00FB4562 /* ShadowsocksX-NG */; };
1418
9B07EFA71D048BBB0052D9DF /* ss-local in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA61D048BBB0052D9DF /* ss-local */; };
1519
9B07EFAC1D048E880052D9DF /* menu_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA81D048E880052D9DF /* menu_icon@2x.png */; };
1620
9B07EFAD1D048E880052D9DF /* menu_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA91D048E880052D9DF /* menu_icon.png */; };
@@ -145,6 +149,10 @@
145149
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>"; };
146150
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>"; };
147151
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>"; };
152+
8EE2EDBF214F6D9F00FB4562 /* HTTPUserProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPUserProxy.swift; sourceTree = "<group>"; };
153+
8EE2EDC1214F6D9F00FB4562 /* AppleScriptUserProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleScriptUserProxy.swift; sourceTree = "<group>"; };
154+
8EE2EDC4214F6DA600FB4562 /* AppleScriptDefinition.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = AppleScriptDefinition.sdef; sourceTree = "<group>"; };
155+
8EE2EDC6214F6F0C00FB4562 /* ShadowsocksX-NG */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "ShadowsocksX-NG"; sourceTree = "<group>"; };
148156
9B07EFA61D048BBB0052D9DF /* ss-local */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = "ss-local"; sourceTree = "<group>"; };
149157
9B07EFA81D048E880052D9DF /* menu_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icon@2x.png"; sourceTree = "<group>"; };
150158
9B07EFA91D048E880052D9DF /* menu_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_icon.png; sourceTree = "<group>"; };
@@ -358,10 +366,14 @@
358366
9B0BFFE71D0460A70040E62B /* ShadowsocksX-NG */ = {
359367
isa = PBXGroup;
360368
children = (
369+
8EE2EDC4214F6DA600FB4562 /* AppleScriptDefinition.sdef */,
370+
8EE2EDC6214F6F0C00FB4562 /* ShadowsocksX-NG */,
361371
9BB706A51D1B982300551F0E /* SWBApplication.m */,
362372
9BB706A61D1B982300551F0E /* SWBApplication.h */,
363373
9B3FFF511D09DBA20019A709 /* ShadowsocksX-NG-Bridging-Header.h */,
364374
9B3FFF151D072FDE0019A709 /* LaunchAtLoginController.h */,
375+
8EE2EDC1214F6D9F00FB4562 /* AppleScriptUserProxy.swift */,
376+
8EE2EDBF214F6D9F00FB4562 /* HTTPUserProxy.swift */,
365377
9B3FFF161D072FDE0019A709 /* LaunchAtLoginController.m */,
366378
9B3FFF0B1D05D8B80019A709 /* UI */,
367379
9B07EFB01D048E900052D9DF /* Support Files */,
@@ -626,6 +638,7 @@
626638
C6D429971DA75988002A5711 /* stop_privoxy.sh in Resources */,
627639
C8E42A6E1D4F2CAF0074C7EA /* UserRulesController.xib in Resources */,
628640
9BEEF06A1D04D4D500FC52B3 /* start_ss_local.sh in Resources */,
641+
8EE2EDC7214F6F0C00FB4562 /* ShadowsocksX-NG in Resources */,
629642
9B16E59A1F99FD0700E54DC5 /* icons8-Eye Filled-50.png in Resources */,
630643
9B938D9C1E864B38005F5636 /* menu_m_icon@2x.png in Resources */,
631644
9B3546731E802B1200B510B4 /* ToastWindowController.xib in Resources */,
@@ -635,6 +648,7 @@
635648
9B3FFF341D08CEF70019A709 /* SWBQRCodeWindowController.xib in Resources */,
636649
9B3FFF231D088E8D0019A709 /* abp.js in Resources */,
637650
9B07EFAD1D048E880052D9DF /* menu_icon.png in Resources */,
651+
8EE2EDC5214F6DA600FB4562 /* AppleScriptDefinition.sdef in Resources */,
638652
9BAFE2E21E83ED7F00F71CCE /* PreferencesWinController.xib in Resources */,
639653
9B0BFFEB1D0460A70040E62B /* Assets.xcassets in Resources */,
640654
08FCA0FF1E24BE1A0070984F /* example-gui-config.json in Resources */,
@@ -816,6 +830,7 @@
816830
isa = PBXSourcesBuildPhase;
817831
buildActionMask = 2147483647;
818832
files = (
833+
8EE2EDC2214F6D9F00FB4562 /* HTTPUserProxy.swift in Sources */,
819834
9B3FFF171D072FDE0019A709 /* LaunchAtLoginController.m in Sources */,
820835
9B86459D1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift in Sources */,
821836
9B3FFF4F1D09D9D50019A709 /* ProxyConfHelper.m in Sources */,
@@ -828,6 +843,7 @@
828843
9B3FFF141D0705810019A709 /* Notifications.swift in Sources */,
829844
9BEEF0701D04DDB100FC52B3 /* ServerProfileManager.swift in Sources */,
830845
9BEEF06E1D04DCE400FC52B3 /* ServerProfile.swift in Sources */,
846+
8EE2EDC3214F6D9F00FB4562 /* AppleScriptUserProxy.swift in Sources */,
831847
9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */,
832848
9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */,
833849
9B0BFFE91D0460A70040E62B /* AppDelegate.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)