mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
webshare websocket implementation
This commit is contained in:
@@ -18,7 +18,7 @@ type OArr<V> = mobx.IObservableArray<V>;
|
||||
type OMap<K,V> = mobx.ObservableMap<K,V>;
|
||||
|
||||
// TODO selection
|
||||
// TODO remotevars
|
||||
// TODO websocket
|
||||
|
||||
function makeFullRemoteRef(ownerName : string, remoteRef : string, name : string) : string {
|
||||
if (isBlank(ownerName) && isBlank(name)) {
|
||||
|
||||
+23
-5
@@ -6,6 +6,7 @@ import * as T from "./types";
|
||||
import {TermWrap} from "./term";
|
||||
import * as lineutil from "./lineutil";
|
||||
import {windowWidthToCols, windowHeightToRows, termWidthFromCols, termHeightFromRows} from "./textmeasure";
|
||||
import {WebShareWSControl} from "./webshare-ws";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
type OArr<V> = mobx.IObservableArray<V>;
|
||||
@@ -20,6 +21,10 @@ function getBaseUrl() {
|
||||
return "https://ot2e112zx5.execute-api.us-west-2.amazonaws.com/dev";
|
||||
}
|
||||
|
||||
function getBaseWSUrl() {
|
||||
return "wss://5lfzlg5crl.execute-api.us-west-2.amazonaws.com/dev";
|
||||
}
|
||||
|
||||
class WebShareModelClass {
|
||||
viewKey : string;
|
||||
screenId : string;
|
||||
@@ -29,13 +34,14 @@ class WebShareModelClass {
|
||||
renderers : Record<string, T.RendererModel> = {}; // lineid => RendererModel
|
||||
contentHeightCache : Record<string, number> = {}; // lineid => height
|
||||
selectedLine : OV<number> = mobx.observable.box(0, {name: "selectedLine"});
|
||||
wsControl : WebShareWSControl;
|
||||
|
||||
constructor() {
|
||||
let urlParams = new URLSearchParams(window.location.search);
|
||||
this.viewKey = urlParams.get("viewkey");
|
||||
this.screenId = urlParams.get("screenid");
|
||||
setTimeout(() => this.loadFullScreenData(), 10);
|
||||
|
||||
this.wsControl = new WebShareWSControl(getBaseWSUrl(), this.screenId, this.viewKey, this.wsMessageCallback.bind(this));
|
||||
}
|
||||
|
||||
setErrMessage(msg : string) : void {
|
||||
@@ -52,6 +58,21 @@ class WebShareModelClass {
|
||||
return 12;
|
||||
}
|
||||
|
||||
wsMessageCallback(msg : any) {
|
||||
console.log("ws message", msg);
|
||||
}
|
||||
|
||||
setWebFullScreen(screen : T.WebFullScreen) {
|
||||
mobx.action(() => {
|
||||
this.screen.set(screen);
|
||||
if (screen.lines != null && screen.lines.length > 0) {
|
||||
this.selectedLine.set(screen.lines[screen.lines.length-1].linenum);
|
||||
}
|
||||
this.wsControl.reconnect(true);
|
||||
})();
|
||||
|
||||
}
|
||||
|
||||
loadTerminalRenderer(elem : Element, line : T.WebLine, cmd : T.WebCmd, width : number) : void {
|
||||
let lineId = cmd.lineid;
|
||||
let termWrap = this.getTermWrap(lineId);
|
||||
@@ -181,10 +202,7 @@ class WebShareModelClass {
|
||||
fetch(url, {method: "GET", mode: "cors", cache: "no-cache"}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
mobx.action(() => {
|
||||
let screen : T.WebFullScreen = data;
|
||||
this.screen.set(screen);
|
||||
if (screen.lines != null && screen.lines.length > 0) {
|
||||
this.selectedLine.set(screen.lines[screen.lines.length-1].linenum);
|
||||
}
|
||||
this.setWebFullScreen(screen);
|
||||
})();
|
||||
}).catch((err) => {
|
||||
this.errMessage.set("Cannot get screen: " + err.message);
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import * as mobx from "mobx";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {boundMethod} from "autobind-decorator";
|
||||
import {WatchScreenPacketType} from "./types";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
class WebShareWSControl {
|
||||
wsConn : any;
|
||||
open : mobx.IObservableValue<boolean>;
|
||||
opening : boolean = false;
|
||||
reconnectTimes : number = 0;
|
||||
msgQueue : any[] = [];
|
||||
messageCallback : (any) => void = null;
|
||||
screenId : string = null;
|
||||
viewKey : string = null;
|
||||
wsUrl : string;
|
||||
closed : boolean;
|
||||
|
||||
constructor(wsUrl : string, screenId : string, viewKey : string, messageCallback : (any) => void) {
|
||||
this.wsUrl = wsUrl;
|
||||
this.messageCallback = messageCallback;
|
||||
this.screenId = screenId;
|
||||
this.viewKey = viewKey;
|
||||
this.open = mobx.observable.box(false, {name: "WSOpen"});
|
||||
this.closed = true;
|
||||
setInterval(this.sendPing, 15000);
|
||||
}
|
||||
|
||||
close() : void {
|
||||
this.closed = true;
|
||||
if (this.wsConn != null) {
|
||||
this.wsConn.close();
|
||||
}
|
||||
}
|
||||
|
||||
log(str : string) {
|
||||
console.log("[wscontrol]", str);
|
||||
}
|
||||
|
||||
@mobx.action
|
||||
setOpen(val : boolean) {
|
||||
mobx.action(() => {
|
||||
this.open.set(val);
|
||||
})();
|
||||
}
|
||||
|
||||
connectNow(desc : string) {
|
||||
this.closed = false;
|
||||
if (this.open.get()) {
|
||||
return;
|
||||
}
|
||||
this.log(sprintf("try reconnect (%s)", desc));
|
||||
this.opening = true;
|
||||
this.wsConn = new WebSocket(this.wsUrl);
|
||||
this.wsConn.onopen = this.onopen;
|
||||
this.wsConn.onmessage = this.onmessage;
|
||||
this.wsConn.onclose = this.onclose;
|
||||
// turns out onerror is not necessary (onclose always follows onerror)
|
||||
// this.wsConn.onerror = this.onerror;
|
||||
}
|
||||
|
||||
reconnect(forceClose? : boolean) {
|
||||
this.closed = false;
|
||||
if (this.open.get()) {
|
||||
if (forceClose) {
|
||||
this.wsConn.close(); // this will force a reconnect
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.reconnectTimes++;
|
||||
if (this.reconnectTimes > 20) {
|
||||
this.log("cannot connect, giving up");
|
||||
return;
|
||||
}
|
||||
let timeoutArr = [0, 5, 5, 15, 30, 60, 300, 3600];
|
||||
let timeout = 60;
|
||||
if (this.reconnectTimes < timeoutArr.length) {
|
||||
timeout = timeoutArr[this.reconnectTimes];
|
||||
}
|
||||
if (timeout > 0) {
|
||||
this.log(sprintf("sleeping %ds", timeout));
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.connectNow(String(this.reconnectTimes));
|
||||
}, timeout*1000);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
onclose(event : any) {
|
||||
// console.log("close", event);
|
||||
if (event.wasClean) {
|
||||
this.log("connection closed");
|
||||
}
|
||||
else {
|
||||
this.log("connection error/disconnected");
|
||||
}
|
||||
if (this.open.get() || this.opening) {
|
||||
this.setOpen(false);
|
||||
this.opening = false;
|
||||
if (!this.closed) {
|
||||
this.reconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
onopen() {
|
||||
this.log("connection open");
|
||||
this.setOpen(true);
|
||||
this.opening = false;
|
||||
this.runMsgQueue();
|
||||
this.sendWebShareInit();
|
||||
// reconnectTimes is reset in onmessage:hello
|
||||
}
|
||||
|
||||
runMsgQueue() {
|
||||
if (!this.open.get()) {
|
||||
return;
|
||||
}
|
||||
if (this.msgQueue.length == 0) {
|
||||
return;
|
||||
}
|
||||
let msg = this.msgQueue.shift();
|
||||
this.sendMessage(msg);
|
||||
setTimeout(() => {
|
||||
this.runMsgQueue();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
onmessage(event : any) {
|
||||
let eventData = null;
|
||||
if (event.data != null) {
|
||||
eventData = JSON.parse(event.data);
|
||||
}
|
||||
if (eventData == null) {
|
||||
return;
|
||||
}
|
||||
if (eventData.type == "ping") {
|
||||
this.wsConn.send(JSON.stringify({type: "pong", stime: Date.now()}));
|
||||
return;
|
||||
}
|
||||
if (eventData.type == "pong") {
|
||||
// nothing
|
||||
return;
|
||||
}
|
||||
if (eventData.type == "hello") {
|
||||
this.reconnectTimes = 0;
|
||||
return;
|
||||
}
|
||||
if (this.messageCallback) {
|
||||
try {
|
||||
this.messageCallback(eventData);
|
||||
}
|
||||
catch (e) {
|
||||
this.log("[error] messageCallback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
sendPing() {
|
||||
if (!this.open.get()) {
|
||||
return;
|
||||
}
|
||||
this.wsConn.send(JSON.stringify({type: "ping", stime: Date.now()}));
|
||||
}
|
||||
|
||||
sendMessage(data : any) {
|
||||
if (!this.open.get()) {
|
||||
return;
|
||||
}
|
||||
this.wsConn.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
pushMessage(data : any) {
|
||||
if (!this.open.get()) {
|
||||
this.msgQueue.push(data);
|
||||
return;
|
||||
}
|
||||
this.sendMessage(data);
|
||||
}
|
||||
|
||||
sendWebShareInit() {
|
||||
let pk : WatchScreenPacketType = {"type": "webshare", screenid: this.screenId, viewkey: this.viewKey};
|
||||
this.pushMessage(pk);
|
||||
}
|
||||
}
|
||||
|
||||
export {WebShareWSControl};
|
||||
Reference in New Issue
Block a user