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:
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
16
ui/app.js
16
ui/app.js
@@ -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
|
||||||
|
|||||||
20
ui/socket.js
20
ui/socket.js
@@ -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) => {
|
||||||
|
|||||||
12
ui/xhr.js
12
ui/xhr.js
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user