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
}
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))
).slice(0, 32);
},
buildBackendSocketURL() {
let r = "";
buildBackendSocketURLs() {
let r = {
webSocket: "",
keepAlive: "",
};
switch (location.protocol) {
case "https:":
r = "wss://";
r.webSocket = "wss://";
break;
default:
r = "ws://";
r.webSocket = "ws://";
}
r += location.host + socksInterface;
r.webSocket += location.host + socksInterface;
r.keepAlive = location.protocol + "//" + location.host + socksInterface;
return r;
},
buildSocket(key, dialTimeout, heartbeatInterval) {
return new Socket(
this.buildBackendSocketURL(),
this.buildBackendSocketURLs(),
key,
dialTimeout * 1000,
heartbeatInterval * 1000

View File

@@ -19,6 +19,7 @@ import * as crypt from "./crypto.js";
import * as reader from "./stream/reader.js";
import * as sender from "./stream/sender.js";
import * as streams from "./stream/streams.js";
import * as xhr from "./xhr.js";
export const ECHO_FAILED = streams.ECHO_FAILED;
@@ -39,19 +40,22 @@ class Dial {
this.address = address;
this.timeout = timeout;
this.privateKey = privateKey;
this.keepAliveTicker = null;
}
/**
* Connect to the remote server
*
* @param {string} address Target URL address
* @param {number} timeout Connect timeout
*
* @returns {Promise<WebSocket>} When connection is established
*
*/
connect(timeout) {
connect(address, timeout) {
const self = this;
return new Promise((resolve, reject) => {
let ws = new WebSocket(this.address),
let ws = new WebSocket(address.webSocket),
promised = false,
timeoutTimer = setTimeout(() => {
ws.close();
@@ -77,6 +81,12 @@ class Dial {
return reject(e);
};
if (!self.keepAliveTicker) {
self.keepAliveTicker = setInterval(() => {
xhr.options(address.keepAlive, {});
}, self.timeout);
}
ws.addEventListener("open", (_event) => {
myRes(ws);
});
@@ -87,10 +97,14 @@ class Dial {
};
myRej(event);
clearInterval(self.keepAliveTicker);
self.keepAliveTicker = null;
});
ws.addEventListener("error", (_event) => {
ws.close();
clearInterval(self.keepAliveTicker);
self.keepAliveTicker = null;
});
});
}
@@ -123,7 +137,7 @@ class Dial {
*
*/
async dial(callbacks) {
let ws = await this.connect(this.timeout);
let ws = await this.connect(this.address, this.timeout);
try {
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
// 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) => {
let authReq = new XMLHttpRequest();
@@ -35,7 +35,7 @@ export function get(url, headers) {
rej(e);
});
authReq.open("GET", url, true);
authReq.open(method, url, true);
for (let h in headers) {
authReq.setRequestHeader(h, headers[h]);
@@ -44,3 +44,11 @@ export function get(url, headers) {
authReq.send();
});
}
export function get(url, headers) {
return send("GET", url, headers);
}
export function options(url, headers) {
return send("OPTIONS", url, headers);
}