From 4af7fd49b95c7937a7b8023fc626ffb6a01ed0c7 Mon Sep 17 00:00:00 2001 From: yangziy Date: Mon, 17 Sep 2018 22:57:23 +0800 Subject: [PATCH] Rewrite server-relevant API. Update document. --- HTTPAPI.md | 124 +++++++++++++++++++++------- ShadowsocksX-NG/HTTPUserProxy.swift | 54 ++++++++++-- 2 files changed, 141 insertions(+), 37 deletions(-) diff --git a/HTTPAPI.md b/HTTPAPI.md index 0830580af..baa1ee248 100644 --- a/HTTPAPI.md +++ b/HTTPAPI.md @@ -3,13 +3,12 @@ * Check current status (on/off) - Toggle the client - - Get server list - -- Switch server - +- Get current server +- Select server +- Add new server +- Delete server - Get current mode - - Switch mode # Specification @@ -26,60 +25,118 @@ URL: http://localhost:9528/ } ``` -- #### Toggle the client `POST /toggle` +- #### Toggle the client `POST /status` ###### Sample Return ``` { "status": 1 - // 1 for toggle succeed, 0 for fail } ``` -- #### Get server list `GET /servers` +`1` for success, `0` for failure. + +- #### Get server list `GET /server/list` ###### Sample Return ``` [ - { - "active": 1, - "id": "93C547E0-49C9-1234-9CAD-EE8D5C4A1A8F", - "remark": "us1", - // remark: as in Server Preferences Panel of the app. - }, - { - "active" : 0, - "id" : "71552DCD-B298-495E-904E-82DA4B07AEF8", - "remark" : "hk2" - }, - { - "active" : 0, - "id" : "E8879F3D-95AE-4714-BC04-9B271C2BC52D", - "remark" : "jp1" - },... + { + "Id" : "93C127E0-49C9-4332-9CAD-EE6B9A3D1A8F", + "Method" : "chacha20-ietf-poly1305", + "Password" : "password", + "Plugin" : "", + "PluginOptions" : "", + "Remark" : "jp1", + "ServerHost" : "jp1-sta40.somehost.com", + "ServerPort" : 49234 + }, + { + "Id" : "71552DCD-B298-4591-B59A-82DA4B07AEF8", + "Method" : "chacha20-ietf-poly1305", + "Password" : "password", + "Plugin" : "", + "PluginOptions" : "", + "Remark" : "us1", + "ServerHost" : "us1-sta40.somehost.com", + "ServerPort" : 49234 + },... ] ``` -- #### Switch server `POST /servers` +- #### Get current server `GET /server/current` + +###### Sample Return + +``` +{ + "Id" : "93C127E0-49C9-4332-9CAD-EE6B9A3D1A8F" +} +``` + +- #### Select server `POST /server/current` ###### Argument | Name | Description | Sample | | ---- | ----------------------------- | -------------------------------------- | -| id | As returned in `GET /servers` | "E8879F3D-95AE-4714-BC04-9B271C2BC52D" | +| Id | As returned in `GET /servers` | "71552DCD-B298-4591-B59A-82DA4B07AEF8" | ###### Sample Return ``` { "status": 1 - // 1 for succeed, 0 for fail } ``` -If the `id` is invalid or fail to match any `id` in config, "status" = 0. +If the `Id` is invalid or fail to match any id in config, `"status": 0`. + +- #### Add Server `POST /server ` + +###### Argument + +| Name | Sample | +| ------------- | ---------------------- | +| ServerPort | 49234 | +| ServerHost | jp1-sta40.somehost.com | +| Remark | jp1 | +| PluginOptions | | +| Plugin | | +| Password | Password | +| Method | chacha20-ietf-poly1305 | + +For meaning of the arguments, refer to `GET /server/list` and the Server Perferences Panel of the app. + +###### Sample Return + +``` +{ + "status": 1 +} +``` + +- #### Delete Server `DELETE /server` + +###### Argument + +| Name | Description | Sample | +| ---- | ----------------------------- | -------------------------------------- | +| Id | As returned in `GET /servers` | "71552DCD-B298-4591-B59A-82DA4B07AEF8" | + +###### Sample Return + +``` +{ + "status": 1 +} +``` + +If `Id` == id of current server, operation will no effect, `"status":0`. + +If `Id` not match, `"status":0`. - #### Get current mode `GET /mode` @@ -95,6 +152,12 @@ If the `id` is invalid or fail to match any `id` in config, "status" = 0. - #### Switch mode `POST /mode` +###### Argument + +| Name | Description | Sample | +| ---- | -------------------------- | -------- | +| mode | As returned in `GET /mode` | "global" | + ###### Sample Return ``` @@ -104,4 +167,7 @@ If the `id` is invalid or fail to match any `id` in config, "status" = 0. } ``` -If the `mode`∉ {"auto", "global", "manual"}, "status" = 0. \ No newline at end of file +--- + +All json names are case sensitive. Be careful. + diff --git a/ShadowsocksX-NG/HTTPUserProxy.swift b/ShadowsocksX-NG/HTTPUserProxy.swift index 5945a995a..149a04c9b 100644 --- a/ShadowsocksX-NG/HTTPUserProxy.swift +++ b/ShadowsocksX-NG/HTTPUserProxy.swift @@ -35,36 +35,74 @@ class HTTPUserProxy{ return GCDWebServerDataResponse(jsonObject: ["enable":isOn], contentType: "json") }) - apiserver.addHandler(forMethod: "POST", path: "/toggle", request: GCDWebServerRequest.self, processBlock: {request in + apiserver.addHandler(forMethod: "POST", path: "/status", request: GCDWebServerURLEncodedFormRequest.self, processBlock: {request in self.appdeleget.doToggleRunning(showToast: false) return GCDWebServerDataResponse(jsonObject: ["status":1], contentType: "json") }) - apiserver.addHandler(forMethod: "GET", path: "/servers", request: GCDWebServerRequest.self, processBlock: {request in + apiserver.addHandler(forMethod: "GET", path: "/server/list", request: GCDWebServerRequest.self, processBlock: {request in var data = [[String:Any]]() for each in self.SerMgr.profiles{ - data.append(["id":each.uuid,"remark":each.remark, - "active":self.SerMgr.activeProfileId == each.uuid ? 1 : 0]) + data.append(each.toDictionary()) } return GCDWebServerDataResponse(jsonObject: data, contentType: "json") }) - apiserver.addHandler(forMethod: "POST", path: "/servers", request: GCDWebServerURLEncodedFormRequest.self, processBlock: {request in + apiserver.addHandler(forMethod: "GET", path: "/server/current", request: GCDWebServerRequest.self, processBlock: {request in - let uuid = ((request as! GCDWebServerURLEncodedFormRequest).arguments["id"])as? String + return GCDWebServerDataResponse(jsonObject: ["Id":self.SerMgr.activeProfileId], contentType: "json") + }) + + apiserver.addHandler(forMethod: "POST", path: "/server/current", request: GCDWebServerURLEncodedFormRequest.self, processBlock: {request in + + let uuid = ((request as! GCDWebServerURLEncodedFormRequest).arguments["Id"])as? String for each in self.SerMgr.profiles{ if (each.uuid == uuid) { self.appdeleget.changeServer(uuid: uuid!) return GCDWebServerDataResponse(jsonObject: ["status":1], contentType: "json") - + } } return GCDWebServerDataResponse(jsonObject: ["status":0], contentType: "json") }) + apiserver.addHandler(forMethod: "POST", path: "/server", request: GCDWebServerURLEncodedFormRequest.self, processBlock: {request in + + var form = ((request as! GCDWebServerURLEncodedFormRequest).arguments) as! [String: Any] + form["ServerPort"] = Double(form["ServerPort"] as! String) + + self.SerMgr.profiles.append(ServerProfile.fromDictionary(form)) + self.SerMgr.save() + self.appdeleget.updateServersMenu() + + return GCDWebServerDataResponse(jsonObject: ["status":1], contentType: "json") + }) + + apiserver.addHandler(forMethod: "DELETE", path: "/server", request: GCDWebServerRequest.self + , processBlock: {request in + + let uuid = (request.query?["Id"])as! String + + if (uuid == self.SerMgr.activeProfileId) { + return GCDWebServerDataResponse(jsonObject: ["status":0], contentType: "json") + } + + for i in 0..