diff --git a/src/main.tsx b/src/main.tsx
index d9e160e2..c0d2e41f 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -10,7 +10,7 @@ import cn from "classnames"
import {TermWrap} from "./term";
import type {SessionDataType, LineType, CmdDataType, RemoteType} from "./types";
import localizedFormat from 'dayjs/plugin/localizedFormat';
-import {GlobalModel, Session, Cmd, Window, Screen, ScreenWindow} from "./model";
+import {GlobalModel, GlobalInput, Session, Cmd, Window, Screen, ScreenWindow} from "./model";
dayjs.extend(localizedFormat)
@@ -305,7 +305,7 @@ class CmdInput extends React.Component<{}, {}> {
let commandStr = this.getCurLine();
let hitem = {cmdtext: commandStr};
this.clearCurLine();
- model.submitCommand(commandStr);
+ model.submitRawCommand(commandStr);
}
render() {
@@ -543,7 +543,7 @@ class ScreenTabs extends React.Component<{session : Session}, {}> {
@boundMethod
handleNewScreen() {
let {session} = this.props;
- GlobalModel.createNewScreen(session, null, true);
+ GlobalInput.createNewScreen();
}
@boundMethod
@@ -559,7 +559,7 @@ class ScreenTabs extends React.Component<{session : Session}, {}> {
if (screen == null) {
return;
}
- GlobalModel.submitCommand(sprintf("/s %s", screenId));
+ GlobalInput.switchScreen(screenId);
}
render() {
@@ -572,7 +572,7 @@ class ScreenTabs extends React.Component<{session : Session}, {}> {
return (
- this.handleSwitchScreen(screen.screenId, index+1)}>
+
this.handleSwitchScreen(screen.screenId)}>
{screen.name.get()}
⌘{index+1}
diff --git a/src/model.ts b/src/model.ts
index c4c25ffd..41cfd1e9 100644
--- a/src/model.ts
+++ b/src/model.ts
@@ -4,7 +4,7 @@ import {boundMethod} from "autobind-decorator";
import {handleJsonFetchResponse, base64ToArray, genMergeData} from "./util";
import {TermWrap} from "./term";
import {v4 as uuidv4} from "uuid";
-import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, SessionUpdateType, WindowUpdateType} from "./types";
+import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, SessionUpdateType, WindowUpdateType, UpdateMessage} from "./types";
import {WSControl} from "./ws";
var GlobalUser = "sawka";
@@ -505,7 +505,7 @@ class Model {
this.clientId = getApi().getId();
this.loadRemotes();
this.loadSessionList();
- this.ws = new WSControl(this.clientId, this.onWSMessage.bind(this))
+ this.ws = new WSControl(this.clientId, this.runUpdate.bind(this))
this.ws.reconnect();
getApi().onTCmd(this.onTCmd.bind(this));
getApi().onICmd(this.onICmd.bind(this));
@@ -515,6 +515,7 @@ class Model {
onTCmd(mods : KeyModsType) {
console.log("got cmd-t", mods);
+ GlobalInput.createNewScreen();
}
onICmd(mods : KeyModsType) {
@@ -534,21 +535,21 @@ class Model {
if (newScreenId == null) {
return;
}
- this.submitCommand(sprintf("/s %s", newScreenId));
+ GlobalInput.switchScreen(newScreenId);
}
onDigitCmd(e : any, arg : {digit: number}, mods : KeyModsType) {
console.log("switch screen (digit)", arg, mods);
- this.submitCommand(sprintf("/s %d", arg.digit));
+ GlobalInput.switchScreen(String(arg.digit));
}
isConnected() : boolean {
return this.ws.open.get();
}
- onWSMessage(message : any) {
- if ("ptydata64" in message) {
- let ptyMsg : PtyDataUpdateType = message;
+ runUpdate(update : UpdateMessage) {
+ if ("ptydata64" in update) {
+ let ptyMsg : PtyDataUpdateType = update;
let activeScreen = this.getActiveScreen();
if (!activeScreen || activeScreen.sessionId != ptyMsg.sessionid) {
return;
@@ -556,8 +557,8 @@ class Model {
activeScreen.updatePtyData(ptyMsg);
return;
}
- if ("sessions" in message) {
- let sessionUpdateMsg : SessionUpdateType = message;
+ if ("sessions" in update) {
+ let sessionUpdateMsg : SessionUpdateType = update;
mobx.action(() => {
let oldActiveScreen = this.getActiveScreen();
genMergeData(this.sessionList, sessionUpdateMsg.sessions, (s : Session) => s.sessionId, (sdata : SessionDataType) => sdata.sessionid, (sdata : SessionDataType) => new Session(sdata), (s : Session) => s.sessionIdx.get());
@@ -573,7 +574,7 @@ class Model {
})();
}
- console.log("ws-message", message);
+ console.log("run-update>", update);
}
removeSession(sessionId : string) {
@@ -664,35 +665,27 @@ class Model {
win.addLineCmd(line, cmd, interactive);
}
- submitCommand(cmdStr : string) {
- console.log("submit-command>", cmdStr);
+ getClientKwargs() : Record {
+ let session = this.getActiveSession();
let win = this.getActiveWindow();
- if (win == null) {
- this.errorHandler("cannot submit command, no active window", null)
- return;
- }
let screen = this.getActiveScreen();
- if (screen == null) {
- this.errorHandler("cannot submit command, no active screen", null)
- return;
+ let rtn : Record = {};
+ if (session != null) {
+ rtn.session = session.sessionId;
}
- let data : FeCmdPacketType = {
- type: "fecmd",
- sessionid: win.sessionId,
- screenid: screen.screenId,
- windowid: win.windowId,
- cmdstr: cmdStr,
- userid: GlobalUser,
- remotestate: null
- };
- let rstate = win.getCurRemoteInstance();
- if (rstate == null) {
- this.errorHandler("cannot submit command, no remote state found", null);
- return;
+ if (screen != null) {
+ rtn.screen = screen.screenId;
}
- data.remotestate = {remoteid: rstate.remoteid, remotename: rstate.name, ...rstate.state};
+ if (win != null) {
+ rtn.window = win.windowId;
+ rtn.remote = win.curRemote.get();
+ }
+ return rtn;
+ }
+
+ submitCommandPacket(cmdPk : FeCmdPacketType) {
let url = sprintf("http://localhost:8080/api/run-command");
- fetch(url, {method: "post", body: JSON.stringify(data)}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
+ fetch(url, {method: "post", body: JSON.stringify(cmdPk)}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
mobx.action(() => {
if (data.data != null && data.data.line != null) {
this.addLineCmd(data.data.line, data.data.cmd, true);
@@ -703,6 +696,27 @@ class Model {
});
}
+ submitCommand(metaCmd : string, metaSubCmd : string, args : string[], kwargs : Record) {
+ let pk : FeCmdPacketType = {
+ type: "fecmd",
+ metacmd: metaCmd,
+ metasubcmd: metaSubCmd,
+ args: args,
+ kwargs: Object.assign({}, this.getClientKwargs(), kwargs),
+ };
+ this.submitCommandPacket(pk);
+ }
+
+ submitRawCommand(cmdStr : string) {
+ let pk : FeCmdPacketType = {
+ type: "fecmd",
+ metacmd: "eval",
+ args: [cmdStr],
+ kwargs: this.getClientKwargs(),
+ };
+ this.submitCommandPacket(pk)
+ }
+
loadSessionList() {
let url = new URL("http://localhost:8080/api/get-all-sessions");
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
@@ -751,23 +765,6 @@ class Model {
this.ws.pushMessage({type: "watchscreen", sessionid: curScreen.sessionId, screenid: curScreen.screenId});
}
- createNewScreen(session : Session, name : string, activate : boolean) {
- let params : Record = {sessionid: session.sessionId};
- if (name != null) {
- params.name = name;
- }
- if (activate) {
- params.activate = "1";
- }
- let usp = new URLSearchParams(params);
- let url = new URL("http://localhost:8080/api/create-screen?" + usp.toString());
- fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
- console.log("created screen", data.data);
- }).catch((err) => {
- this.errorHandler(sprintf("creating screen session=%s", session.sessionId), err);
- });
- }
-
loadWindow(sessionId : string, windowId : string) : Window {
let newWin = new Window(sessionId, windowId);
this.windows.set(sessionId + "/" + windowId, newWin);
@@ -837,12 +834,32 @@ class Model {
}
}
+class InputClass {
+ constructor() {
+ }
+
+ switchScreen(screen : string) {
+ GlobalModel.submitCommand("screen", null, [screen], null);
+ }
+
+ createNewScreen() {
+ GlobalModel.submitCommand("screen", "open", null, null);
+ }
+
+ closeScreen(screen : string) {
+ GlobalModel.submitCommand("screen", "close", [screen], null);
+ }
+};
+
let GlobalModel : Model = null;
+let GlobalInput : InputClass = null;
if ((window as any).GlobalModal == null) {
(window as any).GlobalModel = new Model();
+ (window as any).GlobalInput = new InputClass();
}
GlobalModel = (window as any).GlobalModel;
+GlobalInput = (window as any).GlobalInput;
-export {Model, Session, Window, GlobalModel, Cmd, Screen, ScreenWindow};
+export {Model, Session, Window, GlobalModel, GlobalInput, Cmd, Screen, ScreenWindow};
diff --git a/src/types.ts b/src/types.ts
index 381885ef..a838981f 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -114,12 +114,10 @@ type CmdRemoteStateType = {
type FeCmdPacketType = {
type : string,
- sessionid : string,
- screenid : string,
- windowid : string,
- userid : string,
- cmdstr : string,
- remotestate : CmdRemoteStateType,
+ metacmd : string,
+ metasubcmd? : string,
+ args : string[],
+ kwargs : Record;
};
type WatchScreenPacketType = {
@@ -177,9 +175,11 @@ type SessionUpdateType = {
sessions: SessionDataType[],
};
+type UpdateMessage = PtyDataUpdateType | SessionUpdateType;
+
type WindowUpdateType = {
window: WindowDataType,
remove: boolean,
}
-export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDonePacketType, CmdDataType, ScreenDataType, ScreenOptsType, ScreenWindowType, LayoutType, PtyDataUpdateType, SessionUpdateType, WindowUpdateType};
+export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDonePacketType, CmdDataType, ScreenDataType, ScreenOptsType, ScreenWindowType, LayoutType, PtyDataUpdateType, SessionUpdateType, WindowUpdateType, UpdateMessage};
diff --git a/src/util.ts b/src/util.ts
index bfb7306b..d9f89cf3 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -5,14 +5,19 @@ function fetchJsonData(resp : any, ctErr : boolean) : Promise {
let contentType = resp.headers.get("Content-Type");
if (contentType != null && contentType.startsWith("application/json")) {
return resp.text().then((textData) => {
+ let rtnData : any = null;
try {
- return JSON.parse(textData);
+ rtnData = JSON.parse(textData);
}
catch (err) {
let errMsg = sprintf("Unparseable JSON: " + err.message);
let rtnErr = new Error(errMsg);
throw rtnErr;
}
+ if (rtnData != null && rtnData.error) {
+ throw new Error(rtnData.error);
+ }
+ return rtnData;
});
}
if (ctErr) {