mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
checkpoint, switching to model
This commit is contained in:
parent
5dc0e6b651
commit
77bd3ed5bf
43
src/emain.ts
43
src/emain.ts
@ -4,7 +4,7 @@ import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
|
||||
let app = electron.app;
|
||||
app.setAppLogsPath(__dirname, "../logs");
|
||||
app.setName("ScriptHaus");
|
||||
|
||||
let lock : File;
|
||||
try {
|
||||
@ -14,7 +14,29 @@ catch (e) {
|
||||
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;
|
||||
|
||||
@ -27,12 +49,19 @@ function createWindow() {
|
||||
},
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
MainWindow = createWindow();
|
||||
MainWindow.webContents.openDevTools();
|
||||
|
||||
app.on('activate', () => {
|
||||
if (electron.BrowserWindow.getAllWindows().length === 0) {
|
||||
@ -45,10 +74,8 @@ app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
});
|
||||
|
||||
electron.ipcMain.on("relaunch", (event) => {
|
||||
console.log("RELAUNCH!");
|
||||
app.relaunch();
|
||||
app.exit(0);
|
||||
console.log("test", event);
|
||||
electron.ipcMain.on("get-id", (event) => {
|
||||
return event.processId;
|
||||
});
|
||||
|
||||
|
||||
|
104
src/main.tsx
104
src/main.tsx
@ -7,9 +7,9 @@ import dayjs from 'dayjs'
|
||||
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
|
||||
import cn from "classnames"
|
||||
import {TermWrap} from "./term";
|
||||
import {getCurrentSession, getLineId, Session, newSession, getAllSessions, getCurrentSessionId} from "./session";
|
||||
import type {SessionDataType, LineType, CmdDataType, RemoteType} from "./types";
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
import {GlobalMode, Cmd, Window} from "./model";
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
|
||||
@ -47,7 +47,7 @@ function getLineDateStr(ts : number) : string {
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class LineText extends React.Component<{line : LineType, session : Session}, {}> {
|
||||
class LineText extends React.Component<{line : LineType}, {}> {
|
||||
render() {
|
||||
let line = this.props.line;
|
||||
let formattedTime = getLineDateStr(line.ts);
|
||||
@ -71,13 +71,14 @@ class LineText extends React.Component<{line : LineType, session : Session}, {}>
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class LineCmd extends React.Component<{line : LineType, session : Session, changeSizeCallback? : (term : TermWrap) => void}, {}> {
|
||||
class LineCmd extends React.Component<{line : LineType}, {}> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let {session, line} = this.props;
|
||||
let {line} = this.props;
|
||||
let model = GlobalModel;
|
||||
let termElem = document.getElementById("term-" + getLineId(line));
|
||||
let termWrap = session.getTermWrapByLine(line);
|
||||
termWrap.changeSizeCallback = this.props.changeSizeCallback;
|
||||
@ -100,22 +101,6 @@ class LineCmd extends React.Component<{line : LineType, session : Session, chang
|
||||
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 {
|
||||
if (path == homeDir) {
|
||||
return "~";
|
||||
@ -126,7 +111,7 @@ class LineCmd extends React.Component<{line : LineType, session : Session, chang
|
||||
return path;
|
||||
}
|
||||
|
||||
renderCmdText(cmd : CmdDataType, remote : RemoteType) : any {
|
||||
renderCmdText(cmd : Cmd, remote : RemoteType) : any {
|
||||
if (cmd == null) {
|
||||
return (
|
||||
<div className="metapart-mono cmdtext">
|
||||
@ -230,33 +215,15 @@ class Line extends React.Component<{line : LineType, session : Session, changeSi
|
||||
}
|
||||
|
||||
@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"});
|
||||
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
|
||||
onKeyDown(e : any) {
|
||||
mobx.action(() => {
|
||||
let {session} = this.props;
|
||||
let model = GlobalModel;
|
||||
let win = getActiveWindow();
|
||||
let ctrlMod = e.getModifierState("Control") || e.getModifierState("Meta") || e.getModifierState("Shift");
|
||||
if (e.code == "Enter" && !ctrlMod) {
|
||||
e.preventDefault();
|
||||
@ -267,8 +234,8 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
|
||||
e.preventDefault();
|
||||
let hidx = this.historyIndex.get();
|
||||
hidx += 1;
|
||||
if (hidx > session.getNumHistoryItems()) {
|
||||
hidx = session.getNumHistoryItems();
|
||||
if (hidx > win.getNumHistoryItems()) {
|
||||
hidx = win.getNumHistoryItems();
|
||||
}
|
||||
this.historyIndex.set(hidx);
|
||||
return;
|
||||
@ -298,12 +265,12 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
|
||||
|
||||
@boundMethod
|
||||
getCurLine() : string {
|
||||
let {session} = this.props;
|
||||
let model = GlobalModel;
|
||||
let hidx = this.historyIndex.get();
|
||||
if (hidx < this.modHistory.length && this.modHistory[hidx] != null) {
|
||||
return this.modHistory[hidx];
|
||||
}
|
||||
let hitem = session.getHistoryItem(-hidx);
|
||||
let hitem = win.getHistoryItem(-hidx);
|
||||
if (hitem == null) {
|
||||
return "";
|
||||
}
|
||||
@ -325,12 +292,12 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
|
||||
|
||||
@boundMethod
|
||||
doSubmitCmd() {
|
||||
let {session, windowid} = this.props;
|
||||
let {windowid} = this.props;
|
||||
let model = GlobalModel;
|
||||
let commandStr = this.getCurLine();
|
||||
let hitem = {cmdtext: commandStr};
|
||||
session.addToHistory(hitem);
|
||||
this.clearCurLine();
|
||||
session.submitCommand(windowid, commandStr);
|
||||
model.submitCommand(windowid, commandStr);
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -363,7 +330,7 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class SessionView extends React.Component<{session : Session}, {}> {
|
||||
class SessionView extends React.Component<{}, {}> {
|
||||
shouldFollow : mobx.IObservableValue<boolean> = mobx.observable.box(true);
|
||||
|
||||
@boundMethod
|
||||
@ -389,12 +356,12 @@ class SessionView extends React.Component<{session : Session}, {}> {
|
||||
}
|
||||
|
||||
render() {
|
||||
let session = this.props.session;
|
||||
let window = session.getActiveWindow();
|
||||
if (window == null) {
|
||||
let model = GlobalModel;
|
||||
let win = model.getActiveWindow();
|
||||
if (win == null) {
|
||||
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>;
|
||||
}
|
||||
let idx = 0;
|
||||
@ -402,11 +369,11 @@ class SessionView extends React.Component<{session : Session}, {}> {
|
||||
return (
|
||||
<div className="session-view">
|
||||
<div className="lines" onScroll={this.scrollHandler}>
|
||||
<For each="line" of={window.lines} index="idx">
|
||||
<Line key={line.lineid} line={line} session={session} changeSizeCallback={this.changeSizeCallback}/>
|
||||
<For each="line" of={win.lines} index="idx">
|
||||
<Line key={line.lineid} line={line} changeSizeCallback={this.changeSizeCallback}/>
|
||||
</For>
|
||||
</div>
|
||||
<CmdInput session={session} windowid={window.windowid}/>
|
||||
<CmdInput windowid={win.windowid}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -427,15 +394,9 @@ class MainSideBar extends React.Component<{}, {}> {
|
||||
console.log("click session", sessionId);
|
||||
}
|
||||
|
||||
handleReload() {
|
||||
console.log("reload");
|
||||
window.api.relaunch();
|
||||
}
|
||||
|
||||
render() {
|
||||
let curSessionId = getCurrentSessionId();
|
||||
let sessions = getAllSessions();
|
||||
let session : SessionDataType = null;
|
||||
let model = GlobalModel;
|
||||
let curSessionId = model.curSessionId.get();
|
||||
return (
|
||||
<div className={cn("main-sidebar", {"collapsed": this.collapsed.get()})}>
|
||||
<div className="collapse-container">
|
||||
@ -449,10 +410,15 @@ class MainSideBar extends React.Component<{}, {}> {
|
||||
Private Sessions
|
||||
</p>
|
||||
<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>
|
||||
</For>
|
||||
<li className="new-session"><a className="new-session"><i className="fa fa-plus"/> New Session</a></li>
|
||||
</If>
|
||||
</ul>
|
||||
<p className="menu-label">
|
||||
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 offline fa fa-circle"/>root@app01.ec2</a></li>
|
||||
</ul>
|
||||
<p className="menu-label relaunch" onClick={this.handleReload} style={{cursor: "pointer"}}>
|
||||
Relaunch
|
||||
</p>
|
||||
<div className="bottom-spacer"></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -516,7 +479,6 @@ class Main extends React.Component<{}, {}> {
|
||||
}
|
||||
|
||||
render() {
|
||||
let session = getCurrentSession();
|
||||
return (
|
||||
<div id="main">
|
||||
<h1 className="title scripthaus-logo-small">
|
||||
@ -525,7 +487,7 @@ class Main extends React.Component<{}, {}> {
|
||||
</h1>
|
||||
<div className="main-content">
|
||||
<MainSideBar/>
|
||||
<SessionView session={session}/>
|
||||
<SessionView/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
230
src/model.ts
Normal file
230
src/model.ts
Normal 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";
|
||||
}
|
||||
*/
|
@ -3,5 +3,6 @@ let {contextBridge, ipcRenderer} = require("electron");
|
||||
console.log("RUNNING PRELOAD");
|
||||
|
||||
contextBridge.exposeInMainWorld("api", {
|
||||
relaunch: () => ipcRenderer.send("relaunch"),
|
||||
getId: () => ipcRenderer.sendSync("get-id"),
|
||||
onCmdT: (callback) => ipcRenderer.on("cmd-t"),
|
||||
});
|
||||
|
@ -3,18 +3,14 @@ import {createRoot} from 'react-dom/client';
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {Terminal} from 'xterm';
|
||||
import {Main} from "./main";
|
||||
import {GlobalWS} from "./ws";
|
||||
import {WSControl} from "./ws";
|
||||
import {GlobalModel} from "./model";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import {loadSessionList} from "./session";
|
||||
|
||||
// @ts-ignore
|
||||
let VERSION = __SHVERSION__;
|
||||
|
||||
(window as any).ScriptHausClientId = uuidv4();
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
loadSessionList(true);
|
||||
GlobalWS.reconnect();
|
||||
let reactElem = React.createElement(Main, null, null);
|
||||
let elem = document.getElementById("app");
|
||||
let root = createRoot(elem);
|
||||
|
70
src/term.ts
70
src/term.ts
@ -2,8 +2,8 @@ import * as mobx from "mobx";
|
||||
import {Terminal} from 'xterm';
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {boundMethod} from "autobind-decorator";
|
||||
import {GlobalWS} from "./ws";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import {GlobalModel} from "./model";
|
||||
|
||||
function loadPtyOut(term : Terminal, sessionId : string, cmdId : string, delayMs : number, callback?: (number) => void) {
|
||||
term.clear()
|
||||
@ -49,17 +49,6 @@ class TermWrap {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.stopPtyTail();
|
||||
}
|
||||
|
||||
setCmdStatus(status : string) {
|
||||
if (this.cmdStatus == status) {
|
||||
return;
|
||||
}
|
||||
this.cmdStatus = status;
|
||||
if (!this.isRunning() && this.tailReqId) {
|
||||
this.stopPtyTail();
|
||||
}
|
||||
}
|
||||
|
||||
isRunning() : boolean {
|
||||
@ -68,49 +57,17 @@ class TermWrap {
|
||||
|
||||
@boundMethod
|
||||
onKeyHandler(event : any) {
|
||||
console.log("onkey", event);
|
||||
if (!this.isRunning()) {
|
||||
return;
|
||||
}
|
||||
let inputPacket = {
|
||||
type: "input",
|
||||
ck: this.sessionId + "/" + this.cmdId,
|
||||
inputdata: btoa(event.key),
|
||||
remoteid: this.remoteId,
|
||||
};
|
||||
GlobalWS.pushMessage(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);
|
||||
});
|
||||
GlobalModel.sendInputPacket(inputPacket);
|
||||
}
|
||||
|
||||
// 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))();
|
||||
}
|
||||
|
||||
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) {
|
||||
this.terminal.open(elem);
|
||||
if (this.isRunning()) {
|
||||
@ -212,6 +157,9 @@ class TermWrap {
|
||||
});
|
||||
this.terminal.onKey(this.onKeyHandler);
|
||||
}
|
||||
else {
|
||||
this.terminal.onKey(this.onKeyHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +104,7 @@ type CmdDataType = {
|
||||
startpk : CmdStartPacketType,
|
||||
donepk : CmdDonePacketType,
|
||||
runout : any[],
|
||||
usedrows : number,
|
||||
};
|
||||
|
||||
export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDonePacketType, CmdDataType};
|
||||
|
43
src/ws.ts
43
src/ws.ts
@ -2,17 +2,18 @@ import * as mobx from "mobx";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {boundMethod} from "autobind-decorator";
|
||||
|
||||
declare var window : any;
|
||||
|
||||
class WSControl {
|
||||
wsConn : any;
|
||||
open : mobx.IObservableValue<boolean>;
|
||||
opening : boolean = false;
|
||||
reconnectTimes : number = 0;
|
||||
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"});
|
||||
setInterval(this.sendPing, 5000);
|
||||
}
|
||||
@ -22,20 +23,9 @@ class WSControl {
|
||||
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() {
|
||||
if (this.open.get()) {
|
||||
this.wsConn.close();
|
||||
this.wsConn.close(); // this will force a reconnect
|
||||
return;
|
||||
}
|
||||
this.reconnectTimes++;
|
||||
@ -54,7 +44,7 @@ class WSControl {
|
||||
setTimeout(() => {
|
||||
console.log(sprintf("websocket reconnect(%d)", this.reconnectTimes));
|
||||
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.onmessage = this.onmessage;
|
||||
this.wsConn.onerror = this.onerror;
|
||||
@ -126,16 +116,9 @@ class WSControl {
|
||||
this.reconnectTimes = 0;
|
||||
return;
|
||||
}
|
||||
if (eventData.type == "cmddata") {
|
||||
let cb = this.reqMap[eventData.respid];
|
||||
if (!cb) {
|
||||
console.log(sprintf("websocket cmddata req=%s -- no callback", eventData.respid));
|
||||
return;
|
||||
if (this.messageCallback) {
|
||||
this.messageCallback(eventData);
|
||||
}
|
||||
cb(eventData);
|
||||
return;
|
||||
}
|
||||
console.log("websocket message", eventData);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
@ -162,10 +145,4 @@ class WSControl {
|
||||
}
|
||||
}
|
||||
|
||||
var GlobalWS : WSControl;
|
||||
if (window.GlobalWS == null) {
|
||||
GlobalWS = new WSControl();
|
||||
window.GlobalWS = GlobalWS;
|
||||
}
|
||||
|
||||
export {GlobalWS};
|
||||
export {WSControl};
|
||||
|
Loading…
Reference in New Issue
Block a user