checkpoint, switching to model

This commit is contained in:
sawka 2022-07-11 14:43:18 -07:00
parent 5dc0e6b651
commit 77bd3ed5bf
8 changed files with 325 additions and 183 deletions

View File

@ -4,7 +4,7 @@ import * as path from "path";
import * as fs from "fs"; import * as fs from "fs";
let app = electron.app; let app = electron.app;
app.setAppLogsPath(__dirname, "../logs"); app.setName("ScriptHaus");
let lock : File; let lock : File;
try { try {
@ -14,7 +14,29 @@ catch (e) {
app.exit(0); app.exit(0);
} }
console.log("ACQUIRED LOCK"); let menuTemplate = [
{
role: "appMenu",
},
{
role: "fileMenu",
},
{
role: "editMenu",
},
{
role: "viewMenu",
},
{
role: "windowMenu",
},
{
role: "help",
},
];
let menu = electron.Menu.buildFromTemplate(menuTemplate);
electron.Menu.setApplicationMenu(menu);
let MainWindow = null; let MainWindow = null;
@ -27,12 +49,19 @@ function createWindow() {
}, },
}); });
win.loadFile("../static/index.html"); win.loadFile("../static/index.html");
win.webContents.on("before-input-event", (e, input) => {
if (input.type != "keyDown") {
return;
}
if (input.code == "KeyT" && input.meta) {
win.webContents.send("cmt-t");
}
});
return win; return win;
} }
app.whenReady().then(() => { app.whenReady().then(() => {
MainWindow = createWindow(); MainWindow = createWindow();
MainWindow.webContents.openDevTools();
app.on('activate', () => { app.on('activate', () => {
if (electron.BrowserWindow.getAllWindows().length === 0) { if (electron.BrowserWindow.getAllWindows().length === 0) {
@ -45,10 +74,8 @@ app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit() if (process.platform !== 'darwin') app.quit()
}); });
electron.ipcMain.on("relaunch", (event) => { electron.ipcMain.on("get-id", (event) => {
console.log("RELAUNCH!"); return event.processId;
app.relaunch();
app.exit(0);
console.log("test", event);
}); });

View File

@ -7,9 +7,9 @@ import dayjs from 'dayjs'
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
import cn from "classnames" import cn from "classnames"
import {TermWrap} from "./term"; import {TermWrap} from "./term";
import {getCurrentSession, getLineId, Session, newSession, getAllSessions, getCurrentSessionId} from "./session";
import type {SessionDataType, LineType, CmdDataType, RemoteType} from "./types"; import type {SessionDataType, LineType, CmdDataType, RemoteType} from "./types";
import localizedFormat from 'dayjs/plugin/localizedFormat'; import localizedFormat from 'dayjs/plugin/localizedFormat';
import {GlobalMode, Cmd, Window} from "./model";
dayjs.extend(localizedFormat) dayjs.extend(localizedFormat)
@ -47,7 +47,7 @@ function getLineDateStr(ts : number) : string {
} }
@mobxReact.observer @mobxReact.observer
class LineText extends React.Component<{line : LineType, session : Session}, {}> { class LineText extends React.Component<{line : LineType}, {}> {
render() { render() {
let line = this.props.line; let line = this.props.line;
let formattedTime = getLineDateStr(line.ts); let formattedTime = getLineDateStr(line.ts);
@ -71,13 +71,14 @@ class LineText extends React.Component<{line : LineType, session : Session}, {}>
} }
@mobxReact.observer @mobxReact.observer
class LineCmd extends React.Component<{line : LineType, session : Session, changeSizeCallback? : (term : TermWrap) => void}, {}> { class LineCmd extends React.Component<{line : LineType}, {}> {
constructor(props) { constructor(props) {
super(props); super(props);
} }
componentDidMount() { componentDidMount() {
let {session, line} = this.props; let {line} = this.props;
let model = GlobalModel;
let termElem = document.getElementById("term-" + getLineId(line)); let termElem = document.getElementById("term-" + getLineId(line));
let termWrap = session.getTermWrapByLine(line); let termWrap = session.getTermWrapByLine(line);
termWrap.changeSizeCallback = this.props.changeSizeCallback; termWrap.changeSizeCallback = this.props.changeSizeCallback;
@ -100,22 +101,6 @@ class LineCmd extends React.Component<{line : LineType, session : Session, chang
termWrap.reloadTerminal(true, 500); termWrap.reloadTerminal(true, 500);
} }
@boundMethod
singleLineCmdText(cmdText : string) {
if (cmdText == null) {
return "(none)";
}
cmdText = cmdText.trim();
let nlIdx = cmdText.indexOf("\n");
if (nlIdx != -1) {
cmdText = cmdText.substr(0, nlIdx) + "...";
}
if (cmdText.length > 80) {
cmdText = cmdText.substr(0, 77) + "...";
}
return cmdText;
}
replaceHomePath(path : string, homeDir : string) : string { replaceHomePath(path : string, homeDir : string) : string {
if (path == homeDir) { if (path == homeDir) {
return "~"; return "~";
@ -126,7 +111,7 @@ class LineCmd extends React.Component<{line : LineType, session : Session, chang
return path; return path;
} }
renderCmdText(cmd : CmdDataType, remote : RemoteType) : any { renderCmdText(cmd : Cmd, remote : RemoteType) : any {
if (cmd == null) { if (cmd == null) {
return ( return (
<div className="metapart-mono cmdtext"> <div className="metapart-mono cmdtext">
@ -230,33 +215,15 @@ class Line extends React.Component<{line : LineType, session : Session, changeSi
} }
@mobxReact.observer @mobxReact.observer
class CmdInput extends React.Component<{session : Session, windowid : string}, {}> { class CmdInput extends React.Component<{windowid : string}, {}> {
historyIndex : mobx.IObservableValue<number> = mobx.observable.box(0, {name: "history-index"}); historyIndex : mobx.IObservableValue<number> = mobx.observable.box(0, {name: "history-index"});
modHistory : mobx.IObservableArray<string> = mobx.observable.array([""], {name: "mod-history"}); modHistory : mobx.IObservableArray<string> = mobx.observable.array([""], {name: "mod-history"});
elistener : any;
componentDidMount() {
this.elistener = this.handleKeyPress.bind(this);
document.addEventListener("keypress", this.elistener);
}
componentWillUnmount() {
document.removeEventListener("keypress", this.elistener);
}
handleKeyPress(event : any) {
if (event.code == "KeyI" && event.metaKey) {
let elem = document.getElementById("main-cmd-input");
if (elem != null) {
elem.focus();
}
}
}
@mobx.action @boundMethod @mobx.action @boundMethod
onKeyDown(e : any) { onKeyDown(e : any) {
mobx.action(() => { mobx.action(() => {
let {session} = this.props; let model = GlobalModel;
let win = getActiveWindow();
let ctrlMod = e.getModifierState("Control") || e.getModifierState("Meta") || e.getModifierState("Shift"); let ctrlMod = e.getModifierState("Control") || e.getModifierState("Meta") || e.getModifierState("Shift");
if (e.code == "Enter" && !ctrlMod) { if (e.code == "Enter" && !ctrlMod) {
e.preventDefault(); e.preventDefault();
@ -267,8 +234,8 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
e.preventDefault(); e.preventDefault();
let hidx = this.historyIndex.get(); let hidx = this.historyIndex.get();
hidx += 1; hidx += 1;
if (hidx > session.getNumHistoryItems()) { if (hidx > win.getNumHistoryItems()) {
hidx = session.getNumHistoryItems(); hidx = win.getNumHistoryItems();
} }
this.historyIndex.set(hidx); this.historyIndex.set(hidx);
return; return;
@ -298,12 +265,12 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
@boundMethod @boundMethod
getCurLine() : string { getCurLine() : string {
let {session} = this.props; let model = GlobalModel;
let hidx = this.historyIndex.get(); let hidx = this.historyIndex.get();
if (hidx < this.modHistory.length && this.modHistory[hidx] != null) { if (hidx < this.modHistory.length && this.modHistory[hidx] != null) {
return this.modHistory[hidx]; return this.modHistory[hidx];
} }
let hitem = session.getHistoryItem(-hidx); let hitem = win.getHistoryItem(-hidx);
if (hitem == null) { if (hitem == null) {
return ""; return "";
} }
@ -325,12 +292,12 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
@boundMethod @boundMethod
doSubmitCmd() { doSubmitCmd() {
let {session, windowid} = this.props; let {windowid} = this.props;
let model = GlobalModel;
let commandStr = this.getCurLine(); let commandStr = this.getCurLine();
let hitem = {cmdtext: commandStr}; let hitem = {cmdtext: commandStr};
session.addToHistory(hitem);
this.clearCurLine(); this.clearCurLine();
session.submitCommand(windowid, commandStr); model.submitCommand(windowid, commandStr);
} }
render() { render() {
@ -363,7 +330,7 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
} }
@mobxReact.observer @mobxReact.observer
class SessionView extends React.Component<{session : Session}, {}> { class SessionView extends React.Component<{}, {}> {
shouldFollow : mobx.IObservableValue<boolean> = mobx.observable.box(true); shouldFollow : mobx.IObservableValue<boolean> = mobx.observable.box(true);
@boundMethod @boundMethod
@ -389,12 +356,12 @@ class SessionView extends React.Component<{session : Session}, {}> {
} }
render() { render() {
let session = this.props.session; let model = GlobalModel;
let window = session.getActiveWindow(); let win = model.getActiveWindow();
if (window == null) { if (win == null) {
return <div className="session-view">(no active window {session.activeWindowId.get()})</div>; return <div className="session-view">(no active window {session.activeWindowId.get()})</div>;
} }
if (session.loading.get() || window.linesLoading.get()) { if (!win.linesLoaded.get()) {
return <div className="session-view">(loading)</div>; return <div className="session-view">(loading)</div>;
} }
let idx = 0; let idx = 0;
@ -402,11 +369,11 @@ class SessionView extends React.Component<{session : Session}, {}> {
return ( return (
<div className="session-view"> <div className="session-view">
<div className="lines" onScroll={this.scrollHandler}> <div className="lines" onScroll={this.scrollHandler}>
<For each="line" of={window.lines} index="idx"> <For each="line" of={win.lines} index="idx">
<Line key={line.lineid} line={line} session={session} changeSizeCallback={this.changeSizeCallback}/> <Line key={line.lineid} line={line} changeSizeCallback={this.changeSizeCallback}/>
</For> </For>
</div> </div>
<CmdInput session={session} windowid={window.windowid}/> <CmdInput windowid={win.windowid}/>
</div> </div>
); );
} }
@ -427,15 +394,9 @@ class MainSideBar extends React.Component<{}, {}> {
console.log("click session", sessionId); console.log("click session", sessionId);
} }
handleReload() {
console.log("reload");
window.api.relaunch();
}
render() { render() {
let curSessionId = getCurrentSessionId(); let model = GlobalModel;
let sessions = getAllSessions(); let curSessionId = model.curSessionId.get();
let session : SessionDataType = null;
return ( return (
<div className={cn("main-sidebar", {"collapsed": this.collapsed.get()})}> <div className={cn("main-sidebar", {"collapsed": this.collapsed.get()})}>
<div className="collapse-container"> <div className="collapse-container">
@ -449,10 +410,15 @@ class MainSideBar extends React.Component<{}, {}> {
Private Sessions Private Sessions
</p> </p>
<ul className="menu-list"> <ul className="menu-list">
<For each="session" of={sessions}> <If condition={!model.sessionListLoaded()}>
<li><a>(loading)</a></li>
</If>
<If condition={model.sessionListLoaded()}>
<For each="session" of={model.sessionList}>
<li key={session.sessionid}><a className={cn({"is-active": curSessionId == session.sessionid})} onClick={() => this.handleSessionClick(session.sessionid)}>#{session.name}</a></li> <li key={session.sessionid}><a className={cn({"is-active": curSessionId == session.sessionid})} onClick={() => this.handleSessionClick(session.sessionid)}>#{session.name}</a></li>
</For> </For>
<li className="new-session"><a className="new-session"><i className="fa fa-plus"/> New Session</a></li> <li className="new-session"><a className="new-session"><i className="fa fa-plus"/> New Session</a></li>
</If>
</ul> </ul>
<p className="menu-label"> <p className="menu-label">
Shared Sessions Shared Sessions
@ -499,9 +465,6 @@ class MainSideBar extends React.Component<{}, {}> {
<li><a><i className="status fa fa-circle"/>mike@test01.ec2</a></li> <li><a><i className="status fa fa-circle"/>mike@test01.ec2</a></li>
<li><a><i className="status offline fa fa-circle"/>root@app01.ec2</a></li> <li><a><i className="status offline fa fa-circle"/>root@app01.ec2</a></li>
</ul> </ul>
<p className="menu-label relaunch" onClick={this.handleReload} style={{cursor: "pointer"}}>
Relaunch
</p>
<div className="bottom-spacer"></div> <div className="bottom-spacer"></div>
</div> </div>
</div> </div>
@ -516,7 +479,6 @@ class Main extends React.Component<{}, {}> {
} }
render() { render() {
let session = getCurrentSession();
return ( return (
<div id="main"> <div id="main">
<h1 className="title scripthaus-logo-small"> <h1 className="title scripthaus-logo-small">
@ -525,7 +487,7 @@ class Main extends React.Component<{}, {}> {
</h1> </h1>
<div className="main-content"> <div className="main-content">
<MainSideBar/> <MainSideBar/>
<SessionView session={session}/> <SessionView/>
</div> </div>
</div> </div>
); );

230
src/model.ts Normal file
View File

@ -0,0 +1,230 @@
import * as mobx from "mobx";
import {sprintf} from "sprintf-js";
import {boundMethod} from "autobind-decorator";
import {handleJsonFetchResponse} from "./util";
import {TermWrap} from "./term";
import {v4 as uuidv4} from "uuid";
import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, CmdDataType, FeCmdPacketType} from "./types";
import {WSControl} from "./ws";
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
class Cmd {
cmdId : string;
data : OV<CmdDataType>;
terminal : any;
ptyPos : number = 0;
atRowMax : boolean = false;
usedRowsUpdated : () => void = null;
watching : boolean = false;
constructor(cmd : CmdDataType) {
this.cmdId = cmd.cmdid;
this.data = mobx.observable.box(cmd, {deep: false});
}
setCmd(cmd : CmdDataType) {
mobx.action(() => {
this.data.set(cmd);
});
}
getSingleLineCmdText() {
let cmdText = this.data.get().cmdstr;
if (cmdText == null) {
return "(none)";
}
cmdText = cmdText.trim();
let nlIdx = cmdText.indexOf("\n");
if (nlIdx != -1) {
cmdText = cmdText.substr(0, nlIdx) + "...";
}
if (cmdText.length > 80) {
cmdText = cmdText.substr(0, 77) + "...";
}
return cmdText;
}
};
class Window {
windowId : string;
name : OV<string>;
curRemote : OV<string>;
loaded : OV<boolean> = mobx.observable.box(false);
lines : OArr<LineType> = mobx.observable.array([]);
linesLoaded : OV<boolean> = mobx.observable.box(false);
history : any[] = [];
constructor(wdata : WindowDataType) {
this.windowId = wdata.windowid;
this.name = mobx.observable.box(wdata.name);
this.curRemote = mobx.observable.box(wdata.curremote);
}
getNumHistoryItems() : number {
return 0;
}
getHistoryItem() : any {
return null
}
};
class Session {
sessionId : string;
name : OV<string>;
curWindowId : OV<string>;
windows : OArr<Window>;
notifyNum : OV<number> = mobx.observable.box(0);
constructor(sdata : SessionDataType) {
this.sessionId = sdata.sessionid;
this.name = mobx.observable.box(sdata.name);
let winData = sdata.windows || [];
let wins : Window[] = [];
for (let i=0; i<winData.length; i++) {
let win = new Window(winData[i]);
wins.push(win);
}
this.windows = mobx.observable.array(wins);
this.curWindowId = mobx.observable.box((wins.length == 0 ? null : wins[0].windowId));
}
getActiveWindow() : Window {
let cwin = this.curWindowId.get();
if (cwin == null) {
return null;
}
for (let i=0; i<this.windows.length; i++) {
if (this.windows[i].windowId == cwin) {
return this.windows[i];
}
}
return null;
}
}
class Model {
clientId : string;
curSessionId : OV<string> = mobx.observable.box(null);
sessionListLoaded : OV<boolean> = mobx.observable.box(false);
sessionList : OArr<Session> = mobx.observable.array([], {name: "SessionList"});
cmds : Record<string, Cmd> = {};
ws : WSControl;
constructor() {
this.clientId = uuidv4();
this.loadSessionList();
this.ws = new WSControl(this.clientId, this.onMessage.bind(this))
this.ws.reconnect();
}
isConnected() : boolean {
return this.ws.open.get();
}
onMessage(message : any) {
}
getActiveSession() : Session {
let sid = this.curSessionId.get();
if (sid == null) {
return null;
}
for (let i=0; i<this.sessionList.length; i++) {
if (this.sessionList[i].sessionId == sid) {
return this.sessionList[i];
}
}
return null;
}
getActiveWindow() : Window {
let session = this.getActiveSession();
if (session == null) {
return null;
}
return session.getActiveWindow();
}
getCmd(cmdId : string) : Cmd {
return this.cmds[cmdId];
}
submitCommand(windowId : string, cmdStr : string) {
}
loadSessionList() {
let url = new URL("http://localhost:8080/api/get-all-sessions");
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
mobx.action(() => {
let sdatalist : SessionDataType[] = data.data || [];
let slist : Session[] = [];
let defaultSessionId = null;
for (let i=0; i<sdatalist.length; i++) {
let sdata = sdatalist[i];
if (sdata.name == "default") {
defaultSessionId = sdata.sessionid;
}
let s = new Session(sdata);
slist.push(s);
}
this.sessionList.replace(slist);
this.sessionListLoaded.set(true)
this.curSessionId.set(defaultSessionId);
})();
}).catch((err) => {
console.log("error getting session list");
});
}
sendInputPacket(inputPacket : any) {
this.ws.pushMessage(inputPacket);
}
}
let GlobalModel : Model = null;
if ((window as any).GlobalModal == null) {
(window as any).GlobalModel = new Model();
}
GlobalModel = (window as any).GlobalModel;
export {Model, Window, GlobalModel, Cmd};
// GlobalWS.registerAndSendGetCmd(getCmdPacket, (dataPacket) => {
// let realData = atob(dataPacket.ptydata64);
// this.updatePtyData(this.ptyPos, realData, dataPacket.ptydatalen);
// });
/*
reloadTerminal(startTail : boolean, delayMs : number) {
loadPtyOut(this.terminal, this.sessionId, this.cmdId, delayMs, (ptyoutLen) => {
mobx.action(() => {
this.incRenderVersion();
this.ptyPos = ptyoutLen;
})();
if (startTail) {
this.startPtyTail();
}
});
}
setCmdStatus(status : string) {
if (this.cmdStatus == status) {
return;
}
this.cmdStatus = status;
if (!this.isRunning() && this.tailReqId) {
this.stopPtyTail();
}
}
}
isRunning() : boolean {
return this.cmdStatus == "running" || this.cmdStatus == "detached";
}
*/

View File

@ -3,5 +3,6 @@ let {contextBridge, ipcRenderer} = require("electron");
console.log("RUNNING PRELOAD"); console.log("RUNNING PRELOAD");
contextBridge.exposeInMainWorld("api", { contextBridge.exposeInMainWorld("api", {
relaunch: () => ipcRenderer.send("relaunch"), getId: () => ipcRenderer.sendSync("get-id"),
onCmdT: (callback) => ipcRenderer.on("cmd-t"),
}); });

View File

@ -3,18 +3,14 @@ import {createRoot} from 'react-dom/client';
import {sprintf} from "sprintf-js"; import {sprintf} from "sprintf-js";
import {Terminal} from 'xterm'; import {Terminal} from 'xterm';
import {Main} from "./main"; import {Main} from "./main";
import {GlobalWS} from "./ws"; import {WSControl} from "./ws";
import {GlobalModel} from "./model";
import {v4 as uuidv4} from "uuid"; import {v4 as uuidv4} from "uuid";
import {loadSessionList} from "./session";
// @ts-ignore // @ts-ignore
let VERSION = __SHVERSION__; let VERSION = __SHVERSION__;
(window as any).ScriptHausClientId = uuidv4();
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
loadSessionList(true);
GlobalWS.reconnect();
let reactElem = React.createElement(Main, null, null); let reactElem = React.createElement(Main, null, null);
let elem = document.getElementById("app"); let elem = document.getElementById("app");
let root = createRoot(elem); let root = createRoot(elem);

View File

@ -2,8 +2,8 @@ import * as mobx from "mobx";
import {Terminal} from 'xterm'; import {Terminal} from 'xterm';
import {sprintf} from "sprintf-js"; import {sprintf} from "sprintf-js";
import {boundMethod} from "autobind-decorator"; import {boundMethod} from "autobind-decorator";
import {GlobalWS} from "./ws";
import {v4 as uuidv4} from "uuid"; import {v4 as uuidv4} from "uuid";
import {GlobalModel} from "./model";
function loadPtyOut(term : Terminal, sessionId : string, cmdId : string, delayMs : number, callback?: (number) => void) { function loadPtyOut(term : Terminal, sessionId : string, cmdId : string, delayMs : number, callback?: (number) => void) {
term.clear() term.clear()
@ -49,17 +49,6 @@ class TermWrap {
} }
destroy() { destroy() {
this.stopPtyTail();
}
setCmdStatus(status : string) {
if (this.cmdStatus == status) {
return;
}
this.cmdStatus = status;
if (!this.isRunning() && this.tailReqId) {
this.stopPtyTail();
}
} }
isRunning() : boolean { isRunning() : boolean {
@ -68,49 +57,17 @@ class TermWrap {
@boundMethod @boundMethod
onKeyHandler(event : any) { onKeyHandler(event : any) {
console.log("onkey", event);
if (!this.isRunning()) {
return;
}
let inputPacket = { let inputPacket = {
type: "input", type: "input",
ck: this.sessionId + "/" + this.cmdId, ck: this.sessionId + "/" + this.cmdId,
inputdata: btoa(event.key), inputdata: btoa(event.key),
remoteid: this.remoteId, remoteid: this.remoteId,
}; };
GlobalWS.pushMessage(inputPacket); GlobalModel.sendInputPacket(inputPacket);
}
stopPtyTail() {
if (this.tailReqId == null) {
return;
}
let untailCmdPacket = {
type: "untailcmd",
reqid: uuidv4(),
ck: this.sessionId + "/" + this.cmdId,
};
GlobalWS.sendMessage(untailCmdPacket);
GlobalWS.unregisterReq(this.tailReqId);
this.tailReqId = null;
}
startPtyTail() {
if (this.tailReqId != null) {
return;
}
if (!this.isRunning()) {
return;
}
this.tailReqId = uuidv4();
let getCmdPacket = {
type: "getcmd",
reqid: this.tailReqId,
ck: this.sessionId + "/" + this.cmdId,
ptypos: this.ptyPos,
tail: true,
ptyonly: true,
};
GlobalWS.registerAndSendGetCmd(getCmdPacket, (dataPacket) => {
let realData = atob(dataPacket.ptydata64);
this.updatePtyData(this.ptyPos, realData, dataPacket.ptydatalen);
});
} }
// datalen is passed because data could be utf-8 and data.length is not the actual *byte* length // datalen is passed because data could be utf-8 and data.length is not the actual *byte* length
@ -189,18 +146,6 @@ class TermWrap {
mobx.action(() => this.renderVersion.set(this.renderVersion.get() + 1))(); mobx.action(() => this.renderVersion.set(this.renderVersion.get() + 1))();
} }
reloadTerminal(startTail : boolean, delayMs : number) {
loadPtyOut(this.terminal, this.sessionId, this.cmdId, delayMs, (ptyoutLen) => {
mobx.action(() => {
this.incRenderVersion();
this.ptyPos = ptyoutLen;
})();
if (startTail) {
this.startPtyTail();
}
});
}
connectToElem(elem : Element) { connectToElem(elem : Element) {
this.terminal.open(elem); this.terminal.open(elem);
if (this.isRunning()) { if (this.isRunning()) {
@ -212,6 +157,9 @@ class TermWrap {
}); });
this.terminal.onKey(this.onKeyHandler); this.terminal.onKey(this.onKeyHandler);
} }
else {
this.terminal.onKey(this.onKeyHandler);
}
} }
} }

View File

@ -104,6 +104,7 @@ type CmdDataType = {
startpk : CmdStartPacketType, startpk : CmdStartPacketType,
donepk : CmdDonePacketType, donepk : CmdDonePacketType,
runout : any[], runout : any[],
usedrows : number,
}; };
export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDonePacketType, CmdDataType}; export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDonePacketType, CmdDataType};

View File

@ -2,17 +2,18 @@ import * as mobx from "mobx";
import {sprintf} from "sprintf-js"; import {sprintf} from "sprintf-js";
import {boundMethod} from "autobind-decorator"; import {boundMethod} from "autobind-decorator";
declare var window : any;
class WSControl { class WSControl {
wsConn : any; wsConn : any;
open : mobx.IObservableValue<boolean>; open : mobx.IObservableValue<boolean>;
opening : boolean = false; opening : boolean = false;
reconnectTimes : number = 0; reconnectTimes : number = 0;
msgQueue : any[] = []; msgQueue : any[] = [];
reqMap : Record<string, (dataPacket : any) => void> = {}; clientId : string;
messageCallback : (any) => void = null;
constructor() { constructor(clientId : string, messageCallback : (any) => void) {
this.messageCallback = messageCallback;
this.clientId = clientId;
this.open = mobx.observable.box(false, {name: "WSOpen"}); this.open = mobx.observable.box(false, {name: "WSOpen"});
setInterval(this.sendPing, 5000); setInterval(this.sendPing, 5000);
} }
@ -22,20 +23,9 @@ class WSControl {
this.open.set(val); this.open.set(val);
} }
registerAndSendGetCmd(pk : any, callback : (dataPacket : any) => void) {
if (pk.reqid) {
this.reqMap[pk.reqid] = callback;
}
this.pushMessage(pk)
}
unregisterReq(reqid : string) {
delete this.reqMap[reqid];
}
reconnect() { reconnect() {
if (this.open.get()) { if (this.open.get()) {
this.wsConn.close(); this.wsConn.close(); // this will force a reconnect
return; return;
} }
this.reconnectTimes++; this.reconnectTimes++;
@ -54,7 +44,7 @@ class WSControl {
setTimeout(() => { setTimeout(() => {
console.log(sprintf("websocket reconnect(%d)", this.reconnectTimes)); console.log(sprintf("websocket reconnect(%d)", this.reconnectTimes));
this.opening = true; this.opening = true;
this.wsConn = new WebSocket("ws://localhost:8081/ws?clientid=" + window.ScriptHausClientId); this.wsConn = new WebSocket("ws://localhost:8081/ws?clientid=" + this.clientId);
this.wsConn.onopen = this.onopen; this.wsConn.onopen = this.onopen;
this.wsConn.onmessage = this.onmessage; this.wsConn.onmessage = this.onmessage;
this.wsConn.onerror = this.onerror; this.wsConn.onerror = this.onerror;
@ -126,16 +116,9 @@ class WSControl {
this.reconnectTimes = 0; this.reconnectTimes = 0;
return; return;
} }
if (eventData.type == "cmddata") { if (this.messageCallback) {
let cb = this.reqMap[eventData.respid]; this.messageCallback(eventData);
if (!cb) {
console.log(sprintf("websocket cmddata req=%s -- no callback", eventData.respid));
return;
} }
cb(eventData);
return;
}
console.log("websocket message", eventData);
} }
@boundMethod @boundMethod
@ -162,10 +145,4 @@ class WSControl {
} }
} }
var GlobalWS : WSControl; export {WSControl};
if (window.GlobalWS == null) {
GlobalWS = new WSControl();
window.GlobalWS = GlobalWS;
}
export {GlobalWS};