Send OPTIONS request to the WebSockets interface once per Timeout interval. This allows some deployment environment to correctly detect the status of the application

This commit is contained in:
NI
2021-04-29 14:02:52 +08:00
parent f982873b4a
commit b87d5437e5
4 changed files with 42 additions and 11 deletions

View File

@@ -156,3 +156,8 @@ func (s socketVerification) Get(
return nil return nil
} }
func (s socketVerification) Options(
w http.ResponseWriter, r *http.Request, l log.Logger) error {
return nil
}

View File

@@ -200,25 +200,29 @@ function startApp(rootEl) {
await cipher.hmac512(enc.encode(finalKey), enc.encode(rTime)) await cipher.hmac512(enc.encode(finalKey), enc.encode(rTime))
).slice(0, 32); ).slice(0, 32);
}, },
buildBackendSocketURL() { buildBackendSocketURLs() {
let r = ""; let r = {
webSocket: "",
keepAlive: "",
};
switch (location.protocol) { switch (location.protocol) {
case "https:": case "https:":
r = "wss://"; r.webSocket = "wss://";
break; break;
default: default:
r = "ws://"; r.webSocket = "ws://";
} }
r += location.host + socksInterface; r.webSocket += location.host + socksInterface;
r.keepAlive = location.protocol + "//" + location.host + socksInterface;
return r; return r;
}, },
buildSocket(key, dialTimeout, heartbeatInterval) { buildSocket(key, dialTimeout, heartbeatInterval) {
return new Socket( return new Socket(
this.buildBackendSocketURL(), this.buildBackendSocketURLs(),
key, key,
dialTimeout * 1000, dialTimeout * 1000,
heartbeatInterval * 1000 heartbeatInterval * 1000

View File

@@ -19,6 +19,7 @@ import * as crypt from "./crypto.js";
import * as reader from "./stream/reader.js"; import * as reader from "./stream/reader.js";
import * as sender from "./stream/sender.js"; import * as sender from "./stream/sender.js";
import * as streams from "./stream/streams.js"; import * as streams from "./stream/streams.js";
import * as xhr from "./xhr.js";
export const ECHO_FAILED = streams.ECHO_FAILED; export const ECHO_FAILED = streams.ECHO_FAILED;
@@ -39,19 +40,22 @@ class Dial {
this.address = address; this.address = address;
this.timeout = timeout; this.timeout = timeout;
this.privateKey = privateKey; this.privateKey = privateKey;
this.keepAliveTicker = null;
} }
/** /**
* Connect to the remote server * Connect to the remote server
* *
* @param {string} address Target URL address
* @param {number} timeout Connect timeout * @param {number} timeout Connect timeout
* *
* @returns {Promise<WebSocket>} When connection is established * @returns {Promise<WebSocket>} When connection is established
* *
*/ */
connect(timeout) { connect(address, timeout) {
const self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let ws = new WebSocket(this.address), let ws = new WebSocket(address.webSocket),
promised = false, promised = false,
timeoutTimer = setTimeout(() => { timeoutTimer = setTimeout(() => {
ws.close(); ws.close();
@@ -77,6 +81,12 @@ class Dial {
return reject(e); return reject(e);
}; };
if (!self.keepAliveTicker) {
self.keepAliveTicker = setInterval(() => {
xhr.options(address.keepAlive, {});
}, self.timeout);
}
ws.addEventListener("open", (_event) => { ws.addEventListener("open", (_event) => {
myRes(ws); myRes(ws);
}); });
@@ -87,10 +97,14 @@ class Dial {
}; };
myRej(event); myRej(event);
clearInterval(self.keepAliveTicker);
self.keepAliveTicker = null;
}); });
ws.addEventListener("error", (_event) => { ws.addEventListener("error", (_event) => {
ws.close(); ws.close();
clearInterval(self.keepAliveTicker);
self.keepAliveTicker = null;
}); });
}); });
} }
@@ -123,7 +137,7 @@ class Dial {
* *
*/ */
async dial(callbacks) { async dial(callbacks) {
let ws = await this.connect(this.timeout); let ws = await this.connect(this.address, this.timeout);
try { try {
let rd = new reader.Reader(new reader.Multiple(() => {}), (data) => { let rd = new reader.Reader(new reader.Multiple(() => {}), (data) => {

View File

@@ -15,7 +15,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export function get(url, headers) { function send(method, url, headers) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
let authReq = new XMLHttpRequest(); let authReq = new XMLHttpRequest();
@@ -35,7 +35,7 @@ export function get(url, headers) {
rej(e); rej(e);
}); });
authReq.open("GET", url, true); authReq.open(method, url, true);
for (let h in headers) { for (let h in headers) {
authReq.setRequestHeader(h, headers[h]); authReq.setRequestHeader(h, headers[h]);
@@ -44,3 +44,11 @@ export function get(url, headers) {
authReq.send(); authReq.send();
}); });
} }
export function get(url, headers) {
return send("GET", url, headers);
}
export function options(url, headers) {
return send("OPTIONS", url, headers);
}