mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 550e93e62a | |||
| 42963f4287 | |||
| a356df3396 | |||
| 0eab1e3973 | |||
| 5abff8075b | |||
| 6bd60e8330 | |||
| e62540bdbe | |||
| 85156bd6c2 | |||
| d4a64fa8c2 | |||
| 618a08fe54 | |||
| b788a5e4af | |||
| 2e76556cac | |||
| d66287fcc6 | |||
| f25892ba40 | |||
| 37ff5f8c3e |
+128
-136
@@ -715,7 +715,7 @@ class Model {
|
||||
return this.ws.open.get();
|
||||
}
|
||||
|
||||
runUpdate(genUpdate: UpdatePacket, interactive: boolean) {
|
||||
runUpdate(genUpdate: UpdateMessage, interactive: boolean) {
|
||||
mobx.action(() => {
|
||||
const oldContext = this.getUIContext();
|
||||
try {
|
||||
@@ -727,9 +727,8 @@ class Model {
|
||||
const newContext = this.getUIContext();
|
||||
if (oldContext.sessionid != newContext.sessionid || oldContext.screenid != newContext.screenid) {
|
||||
this.inputModel.resetInput();
|
||||
if (genUpdate.type == "model") {
|
||||
const modelUpdate = genUpdate as ModelUpdatePacket;
|
||||
const reversedGenUpdate = modelUpdate.data.slice().reverse();
|
||||
if (!("ptydata64" in genUpdate)) {
|
||||
const reversedGenUpdate = genUpdate.slice().reverse();
|
||||
const lastCmdLine = reversedGenUpdate.find((update) => "cmdline" in update);
|
||||
if (lastCmdLine) {
|
||||
// TODO a bit of a hack since this update gets applied in runUpdate_internal.
|
||||
@@ -769,12 +768,20 @@ class Model {
|
||||
}
|
||||
|
||||
updateActiveSession(sessionId: string): void {
|
||||
const [oldActiveSessionId, oldActiveScreenId] = this.getActiveIds();
|
||||
|
||||
if (sessionId != null) {
|
||||
const newSessionId = sessionId;
|
||||
if (this.activeSessionId.get() != newSessionId) {
|
||||
this.activeSessionId.set(newSessionId);
|
||||
}
|
||||
}
|
||||
const [newActiveSessionId, newActiveScreenId] = this.getActiveIds();
|
||||
if (oldActiveSessionId != newActiveSessionId || oldActiveScreenId != newActiveScreenId) {
|
||||
this.activeMainView.set("session");
|
||||
this.deactivateScreenLines();
|
||||
this.ws.watchScreen(newActiveSessionId, newActiveScreenId);
|
||||
}
|
||||
}
|
||||
|
||||
updateScreenNumRunningCommands(numRunningCommandUpdates: ScreenNumRunningCommandsUpdateType[]) {
|
||||
@@ -789,9 +796,9 @@ class Model {
|
||||
}
|
||||
}
|
||||
|
||||
runUpdate_internal(genUpdate: UpdatePacket, uiContext: UIContextType, interactive: boolean) {
|
||||
if (genUpdate.type == "pty") {
|
||||
const ptyMsg = genUpdate.data as PtyDataUpdateType;
|
||||
runUpdate_internal(genUpdate: UpdateMessage, uiContext: UIContextType, interactive: boolean) {
|
||||
if ("ptydata64" in genUpdate) {
|
||||
const ptyMsg: PtyDataUpdateType = genUpdate;
|
||||
if (isBlank(ptyMsg.remoteid)) {
|
||||
// regular update
|
||||
this.updatePtyData(ptyMsg);
|
||||
@@ -800,138 +807,125 @@ class Model {
|
||||
const ptyData = base64ToArray(ptyMsg.ptydata64);
|
||||
this.remotesModel.receiveData(ptyMsg.remoteid, ptyMsg.ptypos, ptyData);
|
||||
}
|
||||
} else if (genUpdate.type == "model") {
|
||||
const modelUpdateItems = genUpdate.data as ModelUpdateItemType[];
|
||||
return;
|
||||
}
|
||||
let showedRemotesModal = false;
|
||||
genUpdate.forEach((update) => {
|
||||
if (update.connect != null) {
|
||||
if (update.connect.screens != null) {
|
||||
this.screenMap.clear();
|
||||
this.updateScreens(update.connect.screens);
|
||||
}
|
||||
if (update.connect.sessions != null) {
|
||||
this.sessionList.clear();
|
||||
this.updateSessions(update.connect.sessions);
|
||||
}
|
||||
if (update.connect.remotes != null) {
|
||||
this.remotes.clear();
|
||||
this.updateRemotes(update.connect.remotes);
|
||||
}
|
||||
if (update.connect.activesessionid != null) {
|
||||
this.updateActiveSession(update.connect.activesessionid);
|
||||
}
|
||||
if (update.connect.screennumrunningcommands != null) {
|
||||
this.updateScreenNumRunningCommands(update.connect.screennumrunningcommands);
|
||||
}
|
||||
if (update.connect.screenstatusindicators != null) {
|
||||
this.updateScreenStatusIndicators(update.connect.screenstatusindicators);
|
||||
}
|
||||
|
||||
let showedRemotesModal = false;
|
||||
const [oldActiveSessionId, oldActiveScreenId] = this.getActiveIds();
|
||||
modelUpdateItems.forEach((update) => {
|
||||
if (update.connect != null) {
|
||||
if (update.connect.screens != null) {
|
||||
this.screenMap.clear();
|
||||
this.updateScreens(update.connect.screens);
|
||||
}
|
||||
if (update.connect.sessions != null) {
|
||||
this.sessionList.clear();
|
||||
this.updateSessions(update.connect.sessions);
|
||||
}
|
||||
if (update.connect.remotes != null) {
|
||||
this.remotes.clear();
|
||||
this.updateRemotes(update.connect.remotes);
|
||||
}
|
||||
if (update.connect.activesessionid != null) {
|
||||
this.updateActiveSession(update.connect.activesessionid);
|
||||
}
|
||||
if (update.connect.screennumrunningcommands != null) {
|
||||
this.updateScreenNumRunningCommands(update.connect.screennumrunningcommands);
|
||||
}
|
||||
if (update.connect.screenstatusindicators != null) {
|
||||
this.updateScreenStatusIndicators(update.connect.screenstatusindicators);
|
||||
}
|
||||
|
||||
this.sessionListLoaded.set(true);
|
||||
this.remotesLoaded.set(true);
|
||||
} else if (update.screen != null) {
|
||||
this.updateScreens([update.screen]);
|
||||
} else if (update.session != null) {
|
||||
this.updateSessions([update.session]);
|
||||
} else if (update.activesessionid != null) {
|
||||
this.updateActiveSession(update.activesessionid);
|
||||
} else if (update.line != null) {
|
||||
this.addLineCmd(update.line.line, update.line.cmd, interactive);
|
||||
} else if (update.cmd != null) {
|
||||
this.updateCmd(update.cmd);
|
||||
} else if (update.screenlines != null) {
|
||||
this.updateScreenLines(update.screenlines, false);
|
||||
} else if (update.remote != null) {
|
||||
this.updateRemotes([update.remote]);
|
||||
// This code's purpose is to show view remote connection modal when a new connection is added
|
||||
if (!showedRemotesModal && this.remotesModel.recentConnAddedState.get()) {
|
||||
showedRemotesModal = true;
|
||||
this.remotesModel.openReadModal(update.remote.remoteid);
|
||||
}
|
||||
} else if (update.mainview != null) {
|
||||
switch (update.mainview.mainview) {
|
||||
case "session":
|
||||
this.activeMainView.set("session");
|
||||
break;
|
||||
case "history":
|
||||
if (update.mainview.historyview != null) {
|
||||
this.historyViewModel.showHistoryView(update.mainview.historyview);
|
||||
} else {
|
||||
console.warn("invalid historyview in update:", update.mainview);
|
||||
}
|
||||
break;
|
||||
case "bookmarks":
|
||||
if (update.mainview.bookmarksview != null) {
|
||||
this.bookmarksModel.showBookmarksView(
|
||||
update.mainview.bookmarksview?.bookmarks ?? [],
|
||||
update.mainview.bookmarksview?.selectedbookmark
|
||||
);
|
||||
} else {
|
||||
console.warn("invalid bookmarksview in update:", update.mainview);
|
||||
}
|
||||
break;
|
||||
case "plugins":
|
||||
this.pluginsModel.showPluginsView();
|
||||
break;
|
||||
default:
|
||||
console.warn("invalid mainview in update:", update.mainview);
|
||||
}
|
||||
} else if (update.bookmarks != null) {
|
||||
if (update.bookmarks.bookmarks != null) {
|
||||
this.bookmarksModel.mergeBookmarks(update.bookmarks.bookmarks);
|
||||
}
|
||||
} else if (update.clientdata != null) {
|
||||
this.setClientData(update.clientdata);
|
||||
} else if (update.cmdline != null) {
|
||||
this.inputModel.updateCmdLine(update.cmdline);
|
||||
} else if (update.openaicmdinfochat != null) {
|
||||
this.inputModel.setOpenAICmdInfoChat(update.openaicmdinfochat);
|
||||
} else if (update.screenstatusindicator != null) {
|
||||
this.updateScreenStatusIndicators([update.screenstatusindicator]);
|
||||
} else if (update.screennumrunningcommands != null) {
|
||||
this.updateScreenNumRunningCommands([update.screennumrunningcommands]);
|
||||
} else if (update.userinputrequest != null) {
|
||||
const userInputRequest: UserInputRequest = update.userinputrequest;
|
||||
this.modalsModel.pushModal(appconst.USER_INPUT, userInputRequest);
|
||||
} else if (interactive) {
|
||||
if (update.info != null) {
|
||||
const info: InfoType = update.info;
|
||||
this.inputModel.flashInfoMsg(info, info.timeoutms);
|
||||
} else if (update.remoteview != null) {
|
||||
const rview: RemoteViewType = update.remoteview;
|
||||
if (rview.remoteedit != null) {
|
||||
this.remotesModel.openEditModal({ ...rview.remoteedit });
|
||||
this.sessionListLoaded.set(true);
|
||||
this.remotesLoaded.set(true);
|
||||
} else if (update.screen != null) {
|
||||
this.updateScreens([update.screen]);
|
||||
} else if (update.session != null) {
|
||||
this.updateSessions([update.session]);
|
||||
} else if (update.activesessionid != null) {
|
||||
this.updateActiveSession(update.activesessionid);
|
||||
} else if (update.line != null) {
|
||||
this.addLineCmd(update.line.line, update.line.cmd, interactive);
|
||||
} else if (update.cmd != null) {
|
||||
this.updateCmd(update.cmd);
|
||||
} else if (update.screenlines != null) {
|
||||
this.updateScreenLines(update.screenlines, false);
|
||||
} else if (update.remote != null) {
|
||||
this.updateRemotes([update.remote]);
|
||||
// This code's purpose is to show view remote connection modal when a new connection is added
|
||||
if (!showedRemotesModal && this.remotesModel.recentConnAddedState.get()) {
|
||||
showedRemotesModal = true;
|
||||
this.remotesModel.openReadModal(update.remote.remoteid);
|
||||
}
|
||||
} else if (update.mainview != null) {
|
||||
switch (update.mainview.mainview) {
|
||||
case "session":
|
||||
this.activeMainView.set("session");
|
||||
break;
|
||||
case "history":
|
||||
if (update.mainview.historyview != null) {
|
||||
this.historyViewModel.showHistoryView(update.mainview.historyview);
|
||||
} else {
|
||||
console.warn("invalid historyview in update:", update.mainview);
|
||||
}
|
||||
} else if (update.alertmessage != null) {
|
||||
const alertMessage: AlertMessageType = update.alertmessage;
|
||||
this.showAlert(alertMessage);
|
||||
} else if (update.history != null) {
|
||||
if (
|
||||
uiContext.sessionid == update.history.sessionid &&
|
||||
uiContext.screenid == update.history.screenid
|
||||
) {
|
||||
this.inputModel.setHistoryInfo(update.history);
|
||||
break;
|
||||
case "bookmarks":
|
||||
if (update.mainview.bookmarksview != null) {
|
||||
this.bookmarksModel.showBookmarksView(
|
||||
update.mainview.bookmarksview?.bookmarks ?? [],
|
||||
update.mainview.bookmarksview?.selectedbookmark
|
||||
);
|
||||
} else {
|
||||
console.warn("invalid bookmarksview in update:", update.mainview);
|
||||
}
|
||||
} else if (this.isDev) {
|
||||
console.log("did not match update", update);
|
||||
break;
|
||||
case "plugins":
|
||||
this.pluginsModel.showPluginsView();
|
||||
break;
|
||||
default:
|
||||
console.warn("invalid mainview in update:", update.mainview);
|
||||
}
|
||||
} else if (update.bookmarks != null) {
|
||||
if (update.bookmarks.bookmarks != null) {
|
||||
this.bookmarksModel.mergeBookmarks(update.bookmarks.bookmarks);
|
||||
}
|
||||
} else if (update.clientdata != null) {
|
||||
this.setClientData(update.clientdata);
|
||||
} else if (update.cmdline != null) {
|
||||
this.inputModel.updateCmdLine(update.cmdline);
|
||||
} else if (update.openaicmdinfochat != null) {
|
||||
this.inputModel.setOpenAICmdInfoChat(update.openaicmdinfochat);
|
||||
} else if (update.screenstatusindicator != null) {
|
||||
this.updateScreenStatusIndicators([update.screenstatusindicator]);
|
||||
} else if (update.screennumrunningcommands != null) {
|
||||
this.updateScreenNumRunningCommands([update.screennumrunningcommands]);
|
||||
} else if (update.userinputrequest != null) {
|
||||
let userInputRequest: UserInputRequest = update.userinputrequest;
|
||||
this.modalsModel.pushModal(appconst.USER_INPUT, userInputRequest);
|
||||
} else if (interactive) {
|
||||
if (update.info != null) {
|
||||
const info: InfoType = update.info;
|
||||
this.inputModel.flashInfoMsg(info, info.timeoutms);
|
||||
} else if (update.remoteview != null) {
|
||||
const rview: RemoteViewType = update.remoteview;
|
||||
if (rview.remoteedit != null) {
|
||||
this.remotesModel.openEditModal({ ...rview.remoteedit });
|
||||
}
|
||||
} else if (update.alertmessage != null) {
|
||||
const alertMessage: AlertMessageType = update.alertmessage;
|
||||
this.showAlert(alertMessage);
|
||||
} else if (update.history != null) {
|
||||
if (
|
||||
uiContext.sessionid == update.history.sessionid &&
|
||||
uiContext.screenid == update.history.screenid
|
||||
) {
|
||||
this.inputModel.setHistoryInfo(update.history);
|
||||
}
|
||||
} else if (this.isDev) {
|
||||
console.log("did not match update", update);
|
||||
}
|
||||
});
|
||||
|
||||
// Check if the active session or screen has changed, and if so, watch the new screen
|
||||
const [newActiveSessionId, newActiveScreenId] = this.getActiveIds();
|
||||
if (oldActiveSessionId != newActiveSessionId || oldActiveScreenId != newActiveScreenId) {
|
||||
this.activeMainView.set("session");
|
||||
this.deactivateScreenLines();
|
||||
this.ws.watchScreen(newActiveSessionId, newActiveScreenId);
|
||||
} else if (this.isDev) {
|
||||
console.log("did not match update", update);
|
||||
}
|
||||
} else {
|
||||
console.warn("unknown update", genUpdate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateRemotes(remotes: RemoteType[]): void {
|
||||
@@ -1070,13 +1064,11 @@ class Model {
|
||||
this.handleCmdRestart(cmd);
|
||||
}
|
||||
|
||||
isInfoUpdate(update: UpdatePacket): boolean {
|
||||
if (update.type == "model") {
|
||||
const modelUpdate = update as ModelUpdatePacket;
|
||||
return modelUpdate.data.some((u) => u.info != null || u.history != null);
|
||||
} else {
|
||||
isInfoUpdate(update: UpdateMessage): boolean {
|
||||
if (update == null || "ptydata64" in update) {
|
||||
return false;
|
||||
}
|
||||
return update.some((u) => u.info != null || u.history != null);
|
||||
}
|
||||
|
||||
getClientDataLoop(loopNum: number): void {
|
||||
|
||||
Vendored
+1
-15
@@ -338,10 +338,6 @@ declare global {
|
||||
};
|
||||
|
||||
type ModelUpdateType = {
|
||||
items?: ModelUpdateItemType[];
|
||||
};
|
||||
|
||||
type ModelUpdateItemType = {
|
||||
interactive: boolean;
|
||||
session?: SessionDataType;
|
||||
activesessionid?: string;
|
||||
@@ -444,17 +440,7 @@ declare global {
|
||||
showCut?: boolean;
|
||||
};
|
||||
|
||||
type ModelUpdatePacket = {
|
||||
type: "model";
|
||||
data: ModelUpdateItemType[];
|
||||
};
|
||||
|
||||
type PtyDataUpdatePacket = {
|
||||
type: "pty";
|
||||
data: PtyDataUpdateType;
|
||||
};
|
||||
|
||||
type UpdatePacket = ModelUpdatePacket | PtyDataUpdatePacket;
|
||||
type UpdateMessage = PtyDataUpdateType | ModelUpdateType[];
|
||||
|
||||
type RendererContext = {
|
||||
screenId: string;
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/server"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shexec"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||
)
|
||||
|
||||
var BuildTime = "0"
|
||||
@@ -40,7 +39,6 @@ func handleSingle() {
|
||||
sender.Close()
|
||||
sender.WaitForDone()
|
||||
}()
|
||||
wlog.LogConsumer = sender.SendLogPacket
|
||||
initPacket := shexec.MakeInitPacket()
|
||||
sender.SendPacket(initPacket)
|
||||
if len(os.Args) >= 3 && os.Args[2] == "--version" {
|
||||
@@ -135,13 +133,11 @@ func main() {
|
||||
return
|
||||
} else if firstArg == "--single" || firstArg == "--single-from-server" {
|
||||
base.ProcessType = base.ProcessType_WaveShellSingle
|
||||
wlog.GlobalSubsystem = base.ProcessType_WaveShellSingle
|
||||
base.InitDebugLog("single")
|
||||
handleSingle()
|
||||
return
|
||||
} else if firstArg == "--server" {
|
||||
base.ProcessType = base.ProcessType_WaveShellServer
|
||||
wlog.GlobalSubsystem = base.ProcessType_WaveShellServer
|
||||
base.InitDebugLog("server")
|
||||
rtnCode, err := server.RunServer()
|
||||
if err != nil {
|
||||
|
||||
@@ -42,8 +42,8 @@ const LogRcFileName = "debug.rcfile"
|
||||
const (
|
||||
ProcessType_Unknown = "unknown"
|
||||
ProcessType_WaveSrv = "wavesrv"
|
||||
ProcessType_WaveShellSingle = "wsh-1"
|
||||
ProcessType_WaveShellServer = "wsh-s"
|
||||
ProcessType_WaveShellSingle = "waveshell-single"
|
||||
ProcessType_WaveShellServer = "waveshell-server"
|
||||
)
|
||||
|
||||
// keys are sessionids (also the key RcFilesDirBaseName)
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||
)
|
||||
|
||||
// single : <init, >run, >cmddata, >cmddone, <cmdstart, <>data, <>dataack, <cmddone
|
||||
@@ -556,8 +556,11 @@ func MakeRawPacket(val string) *RawPacketType {
|
||||
}
|
||||
|
||||
type LogPacketType struct {
|
||||
Type string `json:"type"`
|
||||
Entry wlog.LogEntry `json:"entry"`
|
||||
Type string `json:"type"`
|
||||
Ts int64 `json:"ts"` // log timestamp
|
||||
ReqId string `json:"reqid,omitempty"` // if this log line is related to an rpc request
|
||||
ProcInfo string `json:"procinfo,omitempty"` // server/single
|
||||
LogLine string `json:"logline"` // the logline data
|
||||
}
|
||||
|
||||
func (*LogPacketType) GetType() string {
|
||||
@@ -568,8 +571,8 @@ func (p *LogPacketType) String() string {
|
||||
return "log"
|
||||
}
|
||||
|
||||
func MakeLogPacket(entry wlog.LogEntry) *LogPacketType {
|
||||
return &LogPacketType{Type: LogPacketStr, Entry: entry}
|
||||
func MakeLogPacket() *LogPacketType {
|
||||
return &LogPacketType{Type: LogPacketStr, Ts: time.Now().UnixMilli()}
|
||||
}
|
||||
|
||||
type ShellStatePacketType struct {
|
||||
@@ -972,11 +975,6 @@ type CommandPacketType interface {
|
||||
GetCK() base.CommandKey
|
||||
}
|
||||
|
||||
type ModelUpdatePacketType struct {
|
||||
Type string `json:"type"`
|
||||
Updates []any `json:"updates"`
|
||||
}
|
||||
|
||||
func AsExtType(pk PacketType) string {
|
||||
if rpcPacket, ok := pk.(RpcPacketType); ok {
|
||||
return fmt.Sprintf("%s[%s]", rpcPacket.GetType(), rpcPacket.GetReqId())
|
||||
@@ -1105,10 +1103,6 @@ func MakePacketSender(output io.Writer, errHandler func(*PacketSender, PacketTyp
|
||||
return sender
|
||||
}
|
||||
|
||||
func (sender *PacketSender) SendLogPacket(entry wlog.LogEntry) {
|
||||
sender.SendPacket(MakeLogPacket(entry))
|
||||
}
|
||||
|
||||
func (sender *PacketSender) goHandleError(pk PacketType, err error) {
|
||||
sender.Lock.Lock()
|
||||
defer sender.Lock.Unlock()
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||
)
|
||||
|
||||
type PacketParser struct {
|
||||
@@ -245,11 +243,6 @@ func MakePacketParser(input io.Reader, opts *PacketParserOpts) *PacketParser {
|
||||
if pk.GetType() == PingPacketStr {
|
||||
continue
|
||||
}
|
||||
if pk.GetType() == LogPacketStr {
|
||||
logPk := pk.(*LogPacketType)
|
||||
wlog.LogLogEntry(logPk.Entry)
|
||||
continue
|
||||
}
|
||||
if parser.RpcHandler {
|
||||
sent := parser.trySendRpcResponse(pk)
|
||||
if sent {
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shellapi"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shexec"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||
)
|
||||
|
||||
const MaxFileDataPacketSize = 16 * 1024
|
||||
@@ -742,13 +741,6 @@ func RunServer() (int, error) {
|
||||
WriteErrorChOnce: &sync.Once{},
|
||||
WriteFileContextMap: make(map[string]*WriteFileContext),
|
||||
}
|
||||
if debug {
|
||||
packet.GlobalDebug = true
|
||||
}
|
||||
server.MainInput = packet.MakePacketParser(os.Stdin, nil)
|
||||
server.Sender = packet.MakePacketSender(os.Stdout, server.packetSenderErrorHandler)
|
||||
defer server.Close()
|
||||
wlog.LogConsumer = server.Sender.SendLogPacket
|
||||
go func() {
|
||||
for {
|
||||
if server.checkDone() {
|
||||
@@ -758,6 +750,12 @@ func RunServer() (int, error) {
|
||||
server.cleanWriteFileContexts()
|
||||
}
|
||||
}()
|
||||
if debug {
|
||||
packet.GlobalDebug = true
|
||||
}
|
||||
server.MainInput = packet.MakePacketParser(os.Stdin, nil)
|
||||
server.Sender = packet.MakePacketSender(os.Stdout, server.packetSenderErrorHandler)
|
||||
defer server.Close()
|
||||
var err error
|
||||
initPacket, err := shexec.MakeServerInitPacket()
|
||||
if err != nil {
|
||||
|
||||
@@ -1091,6 +1091,7 @@ func (cmd *ShExecType) DetachedWait(startPacket *packet.CmdStartPacketType) {
|
||||
cmd.DetachedOutput.SendPacket(donePacket)
|
||||
<-ptyCopyDone
|
||||
cmd.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func RunCommandDetached(pk *packet.RunPacketType, sender *packet.PacketSender) (*ShExecType, *packet.CmdStartPacketType, error) {
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// implements distributed logging for waveshell processes
|
||||
package wlog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// wlog will send logs back to the controlling wavesrv process
|
||||
// note that these logs end up on your local machine where the main Wave Terminal process is running
|
||||
// wlog has no ability to send logs to a cloud service or Command Line Inc servers
|
||||
|
||||
// this code is written a bit strange (with globals getting set from other packages)
|
||||
// because we want no dependencies so any package (including base) can use wlog
|
||||
|
||||
// this should match base.ProcessType (set by main)
|
||||
var GlobalSubsystem string
|
||||
|
||||
// if not set, Logf is a no-op. will be set by main to hook up to
|
||||
// the main packet.PacketSender
|
||||
var LogConsumer func(LogEntry)
|
||||
|
||||
type LogEntry struct {
|
||||
LogLine string `json:"logline"`
|
||||
ReqId string `json:"reqid"`
|
||||
SubSystem string `json:"subsystem"`
|
||||
}
|
||||
|
||||
func LogLogEntry(entry LogEntry) {
|
||||
if LogConsumer == nil {
|
||||
return
|
||||
}
|
||||
LogConsumer(entry)
|
||||
}
|
||||
|
||||
// log with a request id (if related to an rpc request)
|
||||
func LogfRpc(reqId string, format string, args ...interface{}) {
|
||||
if LogConsumer == nil {
|
||||
return
|
||||
}
|
||||
logEntry := LogEntry{
|
||||
LogLine: fmt.Sprintf(format, args...),
|
||||
ReqId: reqId,
|
||||
SubSystem: GlobalSubsystem,
|
||||
}
|
||||
LogConsumer(logEntry)
|
||||
}
|
||||
|
||||
func LogfSS(subsystem string, format string, args ...interface{}) {
|
||||
if LogConsumer == nil {
|
||||
return
|
||||
}
|
||||
logEntry := LogEntry{
|
||||
LogLine: fmt.Sprintf(format, args...),
|
||||
ReqId: "",
|
||||
SubSystem: subsystem,
|
||||
}
|
||||
LogConsumer(logEntry)
|
||||
}
|
||||
|
||||
func Logf(format string, args ...interface{}) {
|
||||
LogfSS(GlobalSubsystem, format, args...)
|
||||
}
|
||||
|
||||
func LogWithLogger(entry LogEntry) {
|
||||
if entry.SubSystem == "" {
|
||||
entry.SubSystem = "unknown"
|
||||
}
|
||||
if entry.ReqId != "" {
|
||||
log.Printf("[%s] reqid=%s %s", entry.SubSystem, entry.ReqId, entry.LogLine)
|
||||
} else {
|
||||
log.Printf("[%s] %s", entry.SubSystem, entry.LogLine)
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/server"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/cmdrunner"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/pcloud"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/releasechecker"
|
||||
@@ -805,8 +804,6 @@ func doShutdown(reason string) {
|
||||
func main() {
|
||||
scbase.BuildTime = BuildTime
|
||||
base.ProcessType = base.ProcessType_WaveSrv
|
||||
wlog.GlobalSubsystem = base.ProcessType_WaveSrv
|
||||
wlog.LogConsumer = wlog.LogWithLogger
|
||||
|
||||
if len(os.Args) >= 2 && os.Args[1] == "--test" {
|
||||
log.Printf("running test fn\n")
|
||||
|
||||
+248
-241
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,3 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package releasechecker
|
||||
|
||||
import (
|
||||
@@ -11,7 +8,6 @@ import (
|
||||
"golang.org/x/mod/semver"
|
||||
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
|
||||
)
|
||||
|
||||
@@ -70,9 +66,9 @@ func CheckNewRelease(ctx context.Context, force bool) (ReleaseCheckResult, error
|
||||
return Failure, fmt.Errorf("error getting updated client data: %w", err)
|
||||
}
|
||||
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(clientData)
|
||||
scbus.MainUpdateBus.DoUpdate(update)
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *clientData)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
|
||||
return Success, nil
|
||||
}
|
||||
|
||||
@@ -34,10 +34,8 @@ import (
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/statediff"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scpacket"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
@@ -556,9 +554,6 @@ func (msh *MShellProc) GetShellPref() string {
|
||||
if msh.Remote.ShellPref == sstore.ShellTypePref_Detect {
|
||||
return msh.InitPkShellType
|
||||
}
|
||||
if msh.Remote.ShellPref == "" {
|
||||
return packet.ShellType_bash
|
||||
}
|
||||
return msh.Remote.ShellPref
|
||||
}
|
||||
|
||||
@@ -686,9 +681,9 @@ func (msh *MShellProc) GetRemoteRuntimeState() RemoteRuntimeState {
|
||||
|
||||
func (msh *MShellProc) NotifyRemoteUpdate() {
|
||||
rstate := msh.GetRemoteRuntimeState()
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(rstate)
|
||||
scbus.MainUpdateBus.DoUpdate(update)
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, rstate)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
}
|
||||
|
||||
func GetAllRemoteRuntimeState() []*RemoteRuntimeState {
|
||||
@@ -948,13 +943,13 @@ func (msh *MShellProc) writeToPtyBuffer_nolock(strFmt string, args ...interface{
|
||||
|
||||
func sendRemotePtyUpdate(remoteId string, dataOffset int64, data []byte) {
|
||||
data64 := base64.StdEncoding.EncodeToString(data)
|
||||
update := scbus.MakePtyDataUpdate(&scbus.PtyDataUpdate{
|
||||
update := &sstore.PtyDataUpdate{
|
||||
RemoteId: remoteId,
|
||||
PtyPos: dataOffset,
|
||||
PtyData64: data64,
|
||||
PtyDataLen: int64(len(data)),
|
||||
})
|
||||
scbus.MainUpdateBus.DoUpdate(update)
|
||||
}
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
}
|
||||
|
||||
func (msh *MShellProc) isWaitingForPassword_nolock() bool {
|
||||
@@ -2021,9 +2016,9 @@ func (msh *MShellProc) notifyHangups_nolock() {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(*cmd)
|
||||
scbus.MainUpdateBus.DoScreenUpdate(ck.GetGroupId(), update)
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *cmd)
|
||||
sstore.MainBus.SendScreenUpdate(ck.GetGroupId(), update)
|
||||
go pushNumRunningCmdsUpdate(&ck, -1)
|
||||
}
|
||||
msh.RunningCmds = make(map[base.CommandKey]RunCmdType)
|
||||
@@ -2052,7 +2047,7 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
if screen != nil {
|
||||
update.AddUpdate(*screen)
|
||||
sstore.AddUpdate(update, *screen)
|
||||
}
|
||||
rct := msh.GetRunningCmd(donePk.CK)
|
||||
var statePtr *sstore.ShellStatePtr
|
||||
@@ -2064,7 +2059,7 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
if remoteInst != nil {
|
||||
update.AddUpdate(sstore.MakeSessionUpdateForRemote(rct.SessionId, remoteInst))
|
||||
sstore.AddUpdate(update, sstore.MakeSessionUpdateForRemote(rct.SessionId, remoteInst))
|
||||
}
|
||||
statePtr = &sstore.ShellStatePtr{BaseHash: donePk.FinalState.GetHashVal(false)}
|
||||
} else if donePk.FinalStateDiff != nil && rct != nil {
|
||||
@@ -2084,7 +2079,7 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
if remoteInst != nil {
|
||||
update.AddUpdate(sstore.MakeSessionUpdateForRemote(rct.SessionId, remoteInst))
|
||||
sstore.AddUpdate(update, sstore.MakeSessionUpdateForRemote(rct.SessionId, remoteInst))
|
||||
}
|
||||
diffHashArr := append(([]string)(nil), donePk.FinalStateDiff.DiffHashArr...)
|
||||
diffHashArr = append(diffHashArr, donePk.FinalStateDiff.GetHashVal(false))
|
||||
@@ -2098,7 +2093,7 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
}
|
||||
scbus.MainUpdateBus.DoUpdate(update)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2127,13 +2122,13 @@ func (msh *MShellProc) handleCmdFinalPacket(finalPk *packet.CmdFinalPacketType)
|
||||
log.Printf("error getting cmd(2) in handleCmdFinalPacket (not found)\n")
|
||||
return
|
||||
}
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(*rtnCmd)
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *rtnCmd)
|
||||
if screen != nil {
|
||||
update.AddUpdate(*screen)
|
||||
sstore.AddUpdate(update, *screen)
|
||||
}
|
||||
go pushNumRunningCmdsUpdate(&finalPk.CK, -1)
|
||||
scbus.MainUpdateBus.DoUpdate(update)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
}
|
||||
|
||||
// TODO notify FE about cmd errors
|
||||
@@ -2169,7 +2164,7 @@ func (msh *MShellProc) handleDataPacket(dataPk *packet.DataPacketType, dataPosMa
|
||||
}
|
||||
utilfn.IncSyncMap(dataPosMap, dataPk.CK, int64(len(realData)))
|
||||
if update != nil {
|
||||
scbus.MainUpdateBus.DoScreenUpdate(dataPk.CK.GetGroupId(), update)
|
||||
sstore.MainBus.SendScreenUpdate(dataPk.CK.GetGroupId(), update)
|
||||
}
|
||||
}
|
||||
if ack != nil {
|
||||
@@ -2198,9 +2193,9 @@ func (msh *MShellProc) makeHandleCmdFinalPacketClosure(finalPk *packet.CmdFinalP
|
||||
|
||||
func sendScreenUpdates(screens []*sstore.ScreenType) {
|
||||
for _, screen := range screens {
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(*screen)
|
||||
scbus.MainUpdateBus.DoUpdate(update)
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *screen)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@ import (
|
||||
|
||||
"github.com/kevinburke/ssh_config"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scpacket"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/userinput"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/knownhosts"
|
||||
)
|
||||
@@ -105,13 +104,14 @@ func createPublicKeyCallback(sshKeywords *SshKeywords, passphrase string) func()
|
||||
return createDummySigner()
|
||||
}
|
||||
|
||||
request := &userinput.UserInputRequestType{
|
||||
request := &sstore.UserInputRequestType{
|
||||
ResponseType: "text",
|
||||
QueryText: fmt.Sprintf("Enter passphrase for the SSH key: %s", identityFile),
|
||||
Title: "Publickey Auth + Passphrase",
|
||||
}
|
||||
ctx, _ := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
response, err := userinput.GetUserInput(ctx, scbus.MainRpcBus, request)
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancelFn()
|
||||
response, err := sstore.MainBus.GetUserInput(ctx, request)
|
||||
if err != nil {
|
||||
// this is an error where we actually do want to stop
|
||||
// trying keys
|
||||
@@ -141,12 +141,12 @@ func createInteractivePasswordCallbackPrompt() func() (secret string, err error)
|
||||
// in the future
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancelFn()
|
||||
request := &userinput.UserInputRequestType{
|
||||
request := &sstore.UserInputRequestType{
|
||||
ResponseType: "text",
|
||||
QueryText: "Password:",
|
||||
Title: "Password Authentication",
|
||||
}
|
||||
response, err := userinput.GetUserInput(ctx, scbus.MainRpcBus, request)
|
||||
response, err := sstore.MainBus.GetUserInput(ctx, request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -201,12 +201,12 @@ func promptChallengeQuestion(question string, echo bool) (answer string, err err
|
||||
// in the future
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancelFn()
|
||||
request := &userinput.UserInputRequestType{
|
||||
request := &sstore.UserInputRequestType{
|
||||
ResponseType: "text",
|
||||
QueryText: question,
|
||||
Title: "Keyboard Interactive Authentication",
|
||||
}
|
||||
response, err := userinput.GetUserInput(ctx, scbus.MainRpcBus, request)
|
||||
response, err := sstore.MainBus.GetUserInput(ctx, request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -234,10 +234,10 @@ func openKnownHostsForEdit(knownHostsFilename string) (*os.File, error) {
|
||||
return os.OpenFile(knownHostsFilename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
|
||||
}
|
||||
|
||||
func writeToKnownHosts(knownHostsFile string, newLine string, getUserVerification func() (*userinput.UserInputResponsePacketType, error)) error {
|
||||
func writeToKnownHosts(knownHostsFile string, newLine string, getUserVerification func() (*scpacket.UserInputResponsePacketType, error)) error {
|
||||
if getUserVerification == nil {
|
||||
getUserVerification = func() (*userinput.UserInputResponsePacketType, error) {
|
||||
return &userinput.UserInputResponsePacketType{
|
||||
getUserVerification = func() (*scpacket.UserInputResponsePacketType, error) {
|
||||
return &scpacket.UserInputResponsePacketType{
|
||||
Type: "confirm",
|
||||
Confirm: true,
|
||||
}, nil
|
||||
@@ -270,7 +270,7 @@ func writeToKnownHosts(knownHostsFile string, newLine string, getUserVerificatio
|
||||
return f.Close()
|
||||
}
|
||||
|
||||
func createUnknownKeyVerifier(knownHostsFile string, hostname string, remote string, key ssh.PublicKey) func() (*userinput.UserInputResponsePacketType, error) {
|
||||
func createUnknownKeyVerifier(knownHostsFile string, hostname string, remote string, key ssh.PublicKey) func() (*scpacket.UserInputResponsePacketType, error) {
|
||||
base64Key := base64.StdEncoding.EncodeToString(key.Marshal())
|
||||
queryText := fmt.Sprintf(
|
||||
"The authenticity of host '%s (%s)' can't be established "+
|
||||
@@ -280,20 +280,20 @@ func createUnknownKeyVerifier(knownHostsFile string, hostname string, remote str
|
||||
"**Would you like to continue connecting?** If so, the key will be permanently "+
|
||||
"added to the file %s "+
|
||||
"to protect from future man-in-the-middle attacks.", hostname, remote, key.Type(), base64Key, knownHostsFile)
|
||||
request := &userinput.UserInputRequestType{
|
||||
request := &sstore.UserInputRequestType{
|
||||
ResponseType: "confirm",
|
||||
QueryText: queryText,
|
||||
Markdown: true,
|
||||
Title: "Known Hosts Key Missing",
|
||||
}
|
||||
return func() (*userinput.UserInputResponsePacketType, error) {
|
||||
return func() (*scpacket.UserInputResponsePacketType, error) {
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancelFn()
|
||||
return userinput.GetUserInput(ctx, scbus.MainRpcBus, request)
|
||||
return sstore.MainBus.GetUserInput(ctx, request)
|
||||
}
|
||||
}
|
||||
|
||||
func createMissingKnownHostsVerifier(knownHostsFile string, hostname string, remote string, key ssh.PublicKey) func() (*userinput.UserInputResponsePacketType, error) {
|
||||
func createMissingKnownHostsVerifier(knownHostsFile string, hostname string, remote string, key ssh.PublicKey) func() (*scpacket.UserInputResponsePacketType, error) {
|
||||
base64Key := base64.StdEncoding.EncodeToString(key.Marshal())
|
||||
queryText := fmt.Sprintf(
|
||||
"The authenticity of host '%s (%s)' can't be established "+
|
||||
@@ -304,16 +304,16 @@ func createMissingKnownHostsVerifier(knownHostsFile string, hostname string, rem
|
||||
"- %s will be created \n"+
|
||||
"- the key will be added to %s\n\n"+
|
||||
"This will protect from future man-in-the-middle attacks.", hostname, remote, key.Type(), base64Key, knownHostsFile, knownHostsFile)
|
||||
request := &userinput.UserInputRequestType{
|
||||
request := &sstore.UserInputRequestType{
|
||||
ResponseType: "confirm",
|
||||
QueryText: queryText,
|
||||
Markdown: true,
|
||||
Title: "Known Hosts File Missing",
|
||||
}
|
||||
return func() (*userinput.UserInputResponsePacketType, error) {
|
||||
return func() (*scpacket.UserInputResponsePacketType, error) {
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancelFn()
|
||||
return userinput.GetUserInput(ctx, scbus.MainRpcBus, request)
|
||||
return sstore.MainBus.GetUserInput(ctx, request)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,13 +444,13 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
|
||||
"%s\n\n"+
|
||||
"**Offending Keys** \n"+
|
||||
"%s", key.Type(), correctKeyFingerprint, strings.Join(bulletListKnownHosts, " \n"), strings.Join(offendingKeysFmt, " \n"))
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(sstore.AlertMessageType{
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, sstore.AlertMessageType{
|
||||
Markdown: true,
|
||||
Title: "Known Hosts Key Changed",
|
||||
Message: alertText,
|
||||
})
|
||||
scbus.MainUpdateBus.DoUpdate(update)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
return fmt.Errorf("remote host identification has changed")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package scbus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
||||
)
|
||||
|
||||
const ModelUpdateStr = "model"
|
||||
|
||||
// A channel for sending model updates to the client
|
||||
type ModelUpdateChannel[J any] struct {
|
||||
ScreenId string
|
||||
ClientId string
|
||||
ch chan J
|
||||
}
|
||||
|
||||
func (uch *ModelUpdateChannel[J]) GetChannel() chan J {
|
||||
return uch.ch
|
||||
}
|
||||
|
||||
func (uch *ModelUpdateChannel[J]) SetChannel(ch chan J) {
|
||||
uch.ch = ch
|
||||
}
|
||||
|
||||
// Match the screenId to the channel
|
||||
func (sch *ModelUpdateChannel[J]) Match(screenId string) bool {
|
||||
if screenId == "" {
|
||||
return true
|
||||
}
|
||||
return screenId == sch.ScreenId
|
||||
}
|
||||
|
||||
// An interface for all model updates
|
||||
type ModelUpdateItem interface {
|
||||
// The key to use when marshalling to JSON and interpreting in the client
|
||||
GetType() string
|
||||
}
|
||||
|
||||
// An inner data type for the ModelUpdatePacketType. Stores a collection of model updates to be sent to the client.
|
||||
type ModelUpdate []ModelUpdateItem
|
||||
|
||||
func (mu *ModelUpdate) IsEmpty() bool {
|
||||
if mu == nil {
|
||||
return true
|
||||
}
|
||||
muArr := []ModelUpdateItem(*mu)
|
||||
return len(muArr) == 0
|
||||
}
|
||||
|
||||
func (mu *ModelUpdate) MarshalJSON() ([]byte, error) {
|
||||
rtn := make([]map[string]any, 0)
|
||||
for _, u := range *mu {
|
||||
m := make(map[string]any)
|
||||
m[(u).GetType()] = u
|
||||
rtn = append(rtn, m)
|
||||
}
|
||||
return json.Marshal(rtn)
|
||||
}
|
||||
|
||||
// An UpdatePacket for sending model updates to the client
|
||||
type ModelUpdatePacketType struct {
|
||||
Type string `json:"type"`
|
||||
Data *ModelUpdate `json:"data"`
|
||||
}
|
||||
|
||||
func (*ModelUpdatePacketType) GetType() string {
|
||||
return ModelUpdateStr
|
||||
}
|
||||
|
||||
func (upk *ModelUpdatePacketType) IsEmpty() bool {
|
||||
if upk == nil {
|
||||
return true
|
||||
}
|
||||
return upk.Data.IsEmpty()
|
||||
}
|
||||
|
||||
// Clean the ClientData in an update, if present
|
||||
func (upk *ModelUpdatePacketType) Clean() {
|
||||
if upk.IsEmpty() {
|
||||
return
|
||||
}
|
||||
for _, item := range *(upk.Data) {
|
||||
if i, ok := (item).(CleanableUpdateItem); ok {
|
||||
i.Clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a collection of model updates to the update
|
||||
func (upk *ModelUpdatePacketType) AddUpdate(items ...ModelUpdateItem) {
|
||||
*(upk.Data) = append(*(upk.Data), items...)
|
||||
}
|
||||
|
||||
// Create a new model update packet
|
||||
func MakeUpdatePacket() *ModelUpdatePacketType {
|
||||
return &ModelUpdatePacketType{
|
||||
Type: ModelUpdateStr,
|
||||
Data: &ModelUpdate{},
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the items in the update that are of type I
|
||||
func GetUpdateItems[I ModelUpdateItem](upk *ModelUpdatePacketType) []*I {
|
||||
if upk.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
ret := make([]*I, 0)
|
||||
for _, item := range *(upk.Data) {
|
||||
if i, ok := (item).(I); ok {
|
||||
ret = append(ret, &i)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// An interface for model updates that can be cleaned
|
||||
type CleanableUpdateItem interface {
|
||||
Clean()
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Register the model update packet type
|
||||
packet.RegisterPacketType(ModelUpdateStr, reflect.TypeOf(ModelUpdatePacketType{}))
|
||||
|
||||
// Enforce the UpdatePacket interface
|
||||
var _ UpdatePacket = (*ModelUpdatePacketType)(nil)
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package scbus
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
||||
)
|
||||
|
||||
const PtyDataUpdateStr = "pty"
|
||||
|
||||
// The inner data type for the PtyDataUpdatePacketType. Stores the pty data to be sent to the client.
|
||||
type PtyDataUpdate struct {
|
||||
ScreenId string `json:"screenid,omitempty"`
|
||||
LineId string `json:"lineid,omitempty"`
|
||||
RemoteId string `json:"remoteid,omitempty"`
|
||||
PtyPos int64 `json:"ptypos"`
|
||||
PtyData64 string `json:"ptydata64"`
|
||||
PtyDataLen int64 `json:"ptydatalen"`
|
||||
}
|
||||
|
||||
// An UpdatePacket for sending pty data to the client
|
||||
type PtyDataUpdatePacketType struct {
|
||||
Type string `json:"type"`
|
||||
Data *PtyDataUpdate `json:"data"`
|
||||
}
|
||||
|
||||
func (*PtyDataUpdatePacketType) GetType() string {
|
||||
return PtyDataUpdateStr
|
||||
}
|
||||
|
||||
func (pdu *PtyDataUpdatePacketType) Clean() {
|
||||
// This is a no-op for PtyDataUpdatePacketType, but it is required to satisfy the UpdatePacket interface
|
||||
}
|
||||
|
||||
func (pdu *PtyDataUpdatePacketType) IsEmpty() bool {
|
||||
return pdu == nil || pdu.Data == nil || pdu.Data.PtyDataLen == 0
|
||||
}
|
||||
|
||||
// Create a new PtyDataUpdatePacketType
|
||||
func MakePtyDataUpdate(update *PtyDataUpdate) *PtyDataUpdatePacketType {
|
||||
return &PtyDataUpdatePacketType{Type: PtyDataUpdateStr, Data: update}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Register the PtyDataUpdatePacketType with the packet package
|
||||
packet.RegisterPacketType(PtyDataUpdateStr, reflect.TypeOf(PtyDataUpdatePacketType{}))
|
||||
|
||||
// Enforce the UpdatePacket interface
|
||||
var _ UpdatePacket = (*PtyDataUpdatePacketType)(nil)
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Defines interfaces for creating communciation channels between server and clients
|
||||
package scbus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
||||
)
|
||||
|
||||
var MainUpdateBus *UpdateBus = MakeUpdateBus()
|
||||
var MainRpcBus *RpcBus = MakeRpcBus()
|
||||
|
||||
// The default channel size
|
||||
const ChSize = 100
|
||||
|
||||
type Channel[I packet.PacketType] interface {
|
||||
GetChannel() chan I
|
||||
SetChannel(chan I)
|
||||
Match(string) bool
|
||||
}
|
||||
|
||||
// A concurrent bus for registering and managing channels
|
||||
type Bus[I packet.PacketType] struct {
|
||||
Lock *sync.Mutex
|
||||
Channels map[string]Channel[I]
|
||||
}
|
||||
|
||||
// Opens new channel and registers it with the bus. If a channel exists, it is closed and replaced.
|
||||
func (bus *Bus[I]) RegisterChannel(key string, channelEntry Channel[I]) chan I {
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
uch, found := bus.Channels[key]
|
||||
ch := make(chan I, ChSize)
|
||||
channelEntry.SetChannel(ch)
|
||||
if found {
|
||||
close(uch.GetChannel())
|
||||
}
|
||||
bus.Channels[key] = channelEntry
|
||||
return channelEntry.GetChannel()
|
||||
}
|
||||
|
||||
// Closes the channel matching the provided key and removes it from the bus
|
||||
func (bus *Bus[I]) UnregisterChannel(key string) {
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
uch, found := bus.Channels[key]
|
||||
if found {
|
||||
close(uch.GetChannel())
|
||||
delete(bus.Channels, key)
|
||||
}
|
||||
}
|
||||
|
||||
// An interface for updates to be sent over an UpdateChannel
|
||||
type UpdatePacket interface {
|
||||
// The key to use when marshalling to JSON and interpreting in the client
|
||||
GetType() string
|
||||
Clean()
|
||||
IsEmpty() bool
|
||||
}
|
||||
|
||||
// Enforce that UpdatePacket is a packet.PacketType
|
||||
var _ packet.PacketType = (UpdatePacket)(nil)
|
||||
|
||||
// A channel for sending model updates to the client
|
||||
type UpdateChannel struct {
|
||||
ScreenId string
|
||||
ch chan UpdatePacket
|
||||
}
|
||||
|
||||
func (uch *UpdateChannel) GetChannel() chan UpdatePacket {
|
||||
return uch.ch
|
||||
}
|
||||
|
||||
func (uch *UpdateChannel) SetChannel(ch chan UpdatePacket) {
|
||||
uch.ch = ch
|
||||
}
|
||||
|
||||
// Match the screenId to the channel
|
||||
func (sch *UpdateChannel) Match(screenId string) bool {
|
||||
if screenId == "" {
|
||||
return true
|
||||
}
|
||||
return screenId == sch.ScreenId
|
||||
}
|
||||
|
||||
// Enforce that UpdateChannel is a Channel
|
||||
var _ Channel[UpdatePacket] = (*UpdateChannel)(nil)
|
||||
|
||||
// A collection of channels that can transmit updates
|
||||
type UpdateBus struct {
|
||||
Bus[UpdatePacket]
|
||||
}
|
||||
|
||||
func (bus *UpdateBus) GetLock() *sync.Mutex {
|
||||
return bus.Lock
|
||||
}
|
||||
|
||||
// Create a new UpdateBus
|
||||
func MakeUpdateBus() *UpdateBus {
|
||||
return &UpdateBus{
|
||||
Bus[UpdatePacket]{
|
||||
Lock: &sync.Mutex{},
|
||||
Channels: make(map[string]Channel[UpdatePacket]),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Send an update to all channels in the collection
|
||||
func (bus *UpdateBus) DoUpdate(update UpdatePacket) {
|
||||
if update.IsEmpty() {
|
||||
return
|
||||
}
|
||||
update.Clean()
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
for key, uch := range bus.Channels {
|
||||
select {
|
||||
case uch.GetChannel() <- update:
|
||||
|
||||
default:
|
||||
log.Printf("[error] dropped update on %s updatebus uch key=%s\n", reflect.TypeOf(uch), key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send a model update to only clients that are subscribed to the given screenId
|
||||
func (bus *UpdateBus) DoScreenUpdate(screenId string, update UpdatePacket) {
|
||||
if update.IsEmpty() {
|
||||
return
|
||||
}
|
||||
update.Clean()
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
for id, uch := range bus.Channels {
|
||||
if uch.Match(screenId) {
|
||||
select {
|
||||
case uch.GetChannel() <- update:
|
||||
|
||||
default:
|
||||
log.Printf("[error] dropped update on updatebus uch id=%s\n", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An interface for rpc requests
|
||||
// This is separate from the RpcPacketType defined in the waveshell/pkg/packet package, as that one is intended for use communicating between wavesrv and waveshell. It is has a different set of required methods.
|
||||
type RpcPacket interface {
|
||||
SetReqId(string)
|
||||
SetTimeoutMs(int)
|
||||
GetType() string
|
||||
}
|
||||
|
||||
// An interface for rpc responses
|
||||
// This is separate from the RpcResponsePacketType defined in the waveshell/pkg/packet package, as that one is intended for use communicating between wavesrv and waveshell. It is has a different set of required methods.
|
||||
type RpcResponse interface {
|
||||
SetError(string)
|
||||
GetError() string
|
||||
GetType() string
|
||||
}
|
||||
|
||||
// A collection of channels that can receive rpc responses
|
||||
type RpcBus struct {
|
||||
Bus[RpcResponse]
|
||||
}
|
||||
|
||||
// Create a new RpcBus
|
||||
func MakeRpcBus() *RpcBus {
|
||||
return &RpcBus{
|
||||
Bus[RpcResponse]{
|
||||
Lock: &sync.Mutex{},
|
||||
Channels: make(map[string]Channel[RpcResponse]),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Get the user input channel for the given request id
|
||||
func (bus *RpcBus) GetRpcChannel(id string) (chan RpcResponse, bool) {
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
|
||||
if ch, ok := bus.Channels[id]; ok {
|
||||
return ch.GetChannel(), ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Implements the Channel interface to allow receiving rpc responses
|
||||
type RpcChannel struct {
|
||||
ch chan RpcResponse
|
||||
}
|
||||
|
||||
func (ch *RpcChannel) GetChannel() chan RpcResponse {
|
||||
return ch.ch
|
||||
}
|
||||
|
||||
func (ch *RpcChannel) SetChannel(newCh chan RpcResponse) {
|
||||
ch.ch = newCh
|
||||
}
|
||||
|
||||
// This is a no-op, only used to satisfy the Channel interface
|
||||
func (ch *RpcChannel) Match(string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Enforce that RpcChannel is a Channel
|
||||
var _ Channel[RpcResponse] = (*RpcChannel)(nil)
|
||||
|
||||
// Send a user input request to the frontend and wait for a response
|
||||
func (bus *RpcBus) DoRpc(ctx context.Context, pk RpcPacket) (RpcResponse, error) {
|
||||
id := uuid.New().String()
|
||||
ch := bus.RegisterChannel(id, &RpcChannel{})
|
||||
pk.SetReqId(id)
|
||||
defer bus.UnregisterChannel(id)
|
||||
|
||||
deadline, _ := ctx.Deadline()
|
||||
pk.SetTimeoutMs(int(time.Until(deadline).Milliseconds()) - 500)
|
||||
|
||||
// Send the request to the frontend
|
||||
mu := MakeUpdatePacket()
|
||||
mu.AddUpdate(pk)
|
||||
MainUpdateBus.DoUpdate(mu)
|
||||
|
||||
var response RpcResponse
|
||||
var err error
|
||||
// prepare to receive response
|
||||
select {
|
||||
case resp := <-ch:
|
||||
response = resp
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("timed out waiting for rpc response")
|
||||
}
|
||||
|
||||
if response.GetError() != "" {
|
||||
err = fmt.Errorf(response.GetError())
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
@@ -83,6 +83,7 @@ const WatchScreenPacketStr = "watchscreen"
|
||||
const FeInputPacketStr = "feinput"
|
||||
const RemoteInputPacketStr = "remoteinput"
|
||||
const CmdInputTextPacketStr = "cmdinputtext"
|
||||
const UserInputResponsePacketStr = "userinputresp"
|
||||
|
||||
type FeCommandPacketType struct {
|
||||
Type string `json:"type"`
|
||||
@@ -155,16 +156,21 @@ type CmdInputTextPacketType struct {
|
||||
Text utilfn.StrWithPos `json:"text"`
|
||||
}
|
||||
|
||||
type UserInputResponsePacketType struct {
|
||||
Type string `json:"type"`
|
||||
RequestId string `json:"requestid"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Confirm bool `json:"confirm,omitempty"`
|
||||
ErrorMsg string `json:"errormsg,omitempty"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
packet.RegisterPacketType(FeCommandPacketStr, reflect.TypeOf(FeCommandPacketType{}))
|
||||
packet.RegisterPacketType(WatchScreenPacketStr, reflect.TypeOf(WatchScreenPacketType{}))
|
||||
packet.RegisterPacketType(FeInputPacketStr, reflect.TypeOf(FeInputPacketType{}))
|
||||
packet.RegisterPacketType(RemoteInputPacketStr, reflect.TypeOf(RemoteInputPacketType{}))
|
||||
packet.RegisterPacketType(CmdInputTextPacketStr, reflect.TypeOf(CmdInputTextPacketType{}))
|
||||
}
|
||||
|
||||
type PacketType interface {
|
||||
GetType() string
|
||||
packet.RegisterPacketType(UserInputResponsePacketStr, reflect.TypeOf(UserInputResponsePacketType{}))
|
||||
}
|
||||
|
||||
func (*CmdInputTextPacketType) GetType() string {
|
||||
@@ -206,3 +212,7 @@ func MakeRemoteInputPacket() *RemoteInputPacketType {
|
||||
func (*RemoteInputPacketType) GetType() string {
|
||||
return RemoteInputPacketStr
|
||||
}
|
||||
|
||||
func (*UserInputResponsePacketType) GetType() string {
|
||||
return UserInputResponsePacketStr
|
||||
}
|
||||
|
||||
+21
-16
@@ -15,10 +15,8 @@ import (
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/mapqueue"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scpacket"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/userinput"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/wsshell"
|
||||
)
|
||||
|
||||
@@ -37,8 +35,8 @@ type WSState struct {
|
||||
ClientId string
|
||||
ConnectTime time.Time
|
||||
Shell *wsshell.WSShell
|
||||
UpdateCh chan scbus.UpdatePacket
|
||||
UpdateQueue []any
|
||||
UpdateCh chan interface{}
|
||||
UpdateQueue []interface{}
|
||||
Authenticated bool
|
||||
AuthKey string
|
||||
|
||||
@@ -73,7 +71,7 @@ func (ws *WSState) GetShell() *wsshell.WSShell {
|
||||
return ws.Shell
|
||||
}
|
||||
|
||||
func (ws *WSState) WriteUpdate(update any) error {
|
||||
func (ws *WSState) WriteUpdate(update interface{}) error {
|
||||
shell := ws.GetShell()
|
||||
if shell == nil {
|
||||
return fmt.Errorf("cannot write update, empty shell")
|
||||
@@ -105,21 +103,26 @@ func (ws *WSState) WatchScreen(sessionId string, screenId string) {
|
||||
}
|
||||
ws.SessionId = sessionId
|
||||
ws.ScreenId = screenId
|
||||
ws.UpdateCh = scbus.MainUpdateBus.RegisterChannel(ws.ClientId, &scbus.UpdateChannel{ScreenId: ws.ScreenId})
|
||||
log.Printf("[ws] watch screen clientid=%s sessionid=%s screenid=%s, updateCh=%v\n", ws.ClientId, sessionId, screenId, ws.UpdateCh)
|
||||
ws.UpdateCh = sstore.MainBus.RegisterChannel(ws.ClientId, ws.ScreenId)
|
||||
go ws.RunUpdates(ws.UpdateCh)
|
||||
}
|
||||
|
||||
func (ws *WSState) UnWatchScreen() {
|
||||
ws.Lock.Lock()
|
||||
defer ws.Lock.Unlock()
|
||||
scbus.MainUpdateBus.UnregisterChannel(ws.ClientId)
|
||||
sstore.MainBus.UnregisterChannel(ws.ClientId)
|
||||
ws.SessionId = ""
|
||||
ws.ScreenId = ""
|
||||
log.Printf("[ws] unwatch screen clientid=%s\n", ws.ClientId)
|
||||
}
|
||||
|
||||
func (ws *WSState) RunUpdates(updateCh chan scbus.UpdatePacket) {
|
||||
func (ws *WSState) getUpdateCh() chan interface{} {
|
||||
ws.Lock.Lock()
|
||||
defer ws.Lock.Unlock()
|
||||
return ws.UpdateCh
|
||||
}
|
||||
|
||||
func (ws *WSState) RunUpdates(updateCh chan interface{}) {
|
||||
if updateCh == nil {
|
||||
panic("invalid nil updateCh passed to RunUpdates")
|
||||
}
|
||||
@@ -138,6 +141,7 @@ func writeJsonProtected(shell *wsshell.WSShell, update any) {
|
||||
return
|
||||
}
|
||||
log.Printf("[error] in scws RunUpdates WriteJson: %v\n", r)
|
||||
return
|
||||
}()
|
||||
shell.WriteJson(update)
|
||||
}
|
||||
@@ -151,6 +155,7 @@ func (ws *WSState) ReplaceShell(shell *wsshell.WSShell) {
|
||||
}
|
||||
ws.Shell.Conn.Close()
|
||||
ws.Shell = shell
|
||||
return
|
||||
}
|
||||
|
||||
// returns all state required to display current UI
|
||||
@@ -165,8 +170,8 @@ func (ws *WSState) handleConnection() error {
|
||||
connectUpdate.Remotes = remotes
|
||||
// restore status indicators
|
||||
connectUpdate.ScreenStatusIndicators, connectUpdate.ScreenNumRunningCommands = sstore.GetCurrentIndicatorState()
|
||||
mu := scbus.MakeUpdatePacket()
|
||||
mu.AddUpdate(*connectUpdate)
|
||||
mu := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(mu, *connectUpdate)
|
||||
err = ws.Shell.WriteJson(mu)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -277,11 +282,11 @@ func (ws *WSState) processMessage(msgBytes []byte) error {
|
||||
sstore.ScreenMemSetCmdInputText(cmdInputPk.ScreenId, cmdInputPk.Text, cmdInputPk.SeqNum)
|
||||
return nil
|
||||
}
|
||||
if pk.GetType() == userinput.UserInputResponsePacketStr {
|
||||
userInputRespPk := pk.(*userinput.UserInputResponsePacketType)
|
||||
uich, ok := scbus.MainRpcBus.GetRpcChannel(userInputRespPk.RequestId)
|
||||
if pk.GetType() == scpacket.UserInputResponsePacketStr {
|
||||
userInputRespPk := pk.(*scpacket.UserInputResponsePacketType)
|
||||
uich, ok := sstore.MainBus.GetUserInputChannel(userInputRespPk.RequestId)
|
||||
if !ok {
|
||||
return fmt.Errorf("received User Input Response with invalid Id (%s): %v", userInputRespPk.RequestId, err)
|
||||
return fmt.Errorf("received User Input Response with invalid Id (%s): %v\n", userInputRespPk.RequestId, err)
|
||||
}
|
||||
select {
|
||||
case uich <- userInputRespPk:
|
||||
@@ -297,7 +302,7 @@ func (ws *WSState) RunWSRead() {
|
||||
if shell == nil {
|
||||
return
|
||||
}
|
||||
shell.WriteJson(map[string]any{"type": "hello"}) // let client know we accepted this connection, ignore error
|
||||
shell.WriteJson(map[string]interface{}{"type": "hello"}) // let client know we accepted this connection, ignore error
|
||||
for msgBytes := range shell.ReadChan {
|
||||
err := ws.processMessage(msgBytes)
|
||||
if err != nil {
|
||||
|
||||
+55
-61
@@ -22,7 +22,6 @@ import (
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/dbutil"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
|
||||
)
|
||||
|
||||
const HistoryCols = "h.historyid, h.ts, h.userid, h.sessionid, h.screenid, h.lineid, h.haderror, h.cmdstr, h.remoteownerid, h.remoteid, h.remotename, h.ismetacmd, h.linenum, h.exitcode, h.durationms, h.festate, h.tags, h.status"
|
||||
@@ -564,7 +563,7 @@ func GetSessionByName(ctx context.Context, name string) (*SessionType, error) {
|
||||
|
||||
// returns sessionId
|
||||
// if sessionName == "", it will be generated
|
||||
func InsertSessionWithName(ctx context.Context, sessionName string, activate bool) (*scbus.ModelUpdatePacketType, error) {
|
||||
func InsertSessionWithName(ctx context.Context, sessionName string, activate bool) (*ModelUpdate, error) {
|
||||
var newScreen *ScreenType
|
||||
newSessionId := scbase.GenWaveUUID()
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
@@ -578,7 +577,7 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
screenUpdateItems := scbus.GetUpdateItems[ScreenType](screenUpdate)
|
||||
screenUpdateItems := GetUpdateItems[ScreenType](screenUpdate)
|
||||
if len(screenUpdateItems) < 1 {
|
||||
return fmt.Errorf("no screen update items")
|
||||
}
|
||||
@@ -596,11 +595,11 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(*session)
|
||||
update.AddUpdate(*newScreen)
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *session)
|
||||
AddUpdate(update, *newScreen)
|
||||
if activate {
|
||||
update.AddUpdate(ActiveSessionIdUpdate(newSessionId))
|
||||
AddUpdate(update, ActiveSessionIdUpdate(newSessionId))
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -688,7 +687,7 @@ func fmtUniqueName(name string, defaultFmtStr string, startIdx int, strs []strin
|
||||
}
|
||||
}
|
||||
|
||||
func InsertScreen(ctx context.Context, sessionId string, origScreenName string, opts ScreenCreateOpts, activate bool) (*scbus.ModelUpdatePacketType, error) {
|
||||
func InsertScreen(ctx context.Context, sessionId string, origScreenName string, opts ScreenCreateOpts, activate bool) (*ModelUpdate, error) {
|
||||
var newScreenId string
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT archived`
|
||||
@@ -754,14 +753,14 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(*newScreen)
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *newScreen)
|
||||
if activate {
|
||||
bareSession, err := GetBareSessionById(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
update.AddUpdate(*bareSession)
|
||||
AddUpdate(update, *bareSession)
|
||||
UpdateWithCurrentOpenAICmdInfoChat(newScreenId, update)
|
||||
}
|
||||
return update, nil
|
||||
@@ -876,30 +875,28 @@ func GetCmdByScreenId(ctx context.Context, screenId string, lineId string) (*Cmd
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateWithClearOpenAICmdInfo(screenId string) *scbus.ModelUpdatePacketType {
|
||||
func UpdateWithClearOpenAICmdInfo(screenId string) (*ModelUpdate, error) {
|
||||
ScreenMemClearCmdInfoChat(screenId)
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId, nil)
|
||||
}
|
||||
|
||||
func UpdateWithAddNewOpenAICmdInfoPacket(ctx context.Context, screenId string, pk *packet.OpenAICmdInfoChatMessage) *scbus.ModelUpdatePacketType {
|
||||
func UpdateWithAddNewOpenAICmdInfoPacket(ctx context.Context, screenId string, pk *packet.OpenAICmdInfoChatMessage) (*ModelUpdate, error) {
|
||||
ScreenMemAddCmdInfoChatMessage(screenId, pk)
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId, nil)
|
||||
}
|
||||
|
||||
func UpdateWithCurrentOpenAICmdInfoChat(screenId string, update *scbus.ModelUpdatePacketType) *scbus.ModelUpdatePacketType {
|
||||
if update == nil {
|
||||
update = scbus.MakeUpdatePacket()
|
||||
}
|
||||
update.AddUpdate(OpenAICmdInfoChatUpdate(ScreenMemGetCmdInfoChat(screenId).Messages))
|
||||
return update
|
||||
func UpdateWithCurrentOpenAICmdInfoChat(screenId string, update *ModelUpdate) (*ModelUpdate, error) {
|
||||
ret := &ModelUpdate{}
|
||||
AddOpenAICmdInfoChatUpdate(ret, ScreenMemGetCmdInfoChat(screenId).Messages)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func UpdateWithUpdateOpenAICmdInfoPacket(ctx context.Context, screenId string, messageID int, pk *packet.OpenAICmdInfoChatMessage) (*scbus.ModelUpdatePacketType, error) {
|
||||
func UpdateWithUpdateOpenAICmdInfoPacket(ctx context.Context, screenId string, messageID int, pk *packet.OpenAICmdInfoChatMessage) (*ModelUpdate, error) {
|
||||
err := ScreenMemUpdateCmdInfoChatMessage(screenId, messageID, pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId, nil), nil
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId, nil)
|
||||
}
|
||||
|
||||
func UpdateCmdForRestart(ctx context.Context, ck base.CommandKey, ts int64, cmdPid int, remotePid int, termOpts *TermOpts) error {
|
||||
@@ -916,7 +913,7 @@ func UpdateCmdForRestart(ctx context.Context, ck base.CommandKey, ts int64, cmdP
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateCmdDoneInfo(ctx context.Context, ck base.CommandKey, donePk *packet.CmdDonePacketType, status string) (*scbus.ModelUpdatePacketType, error) {
|
||||
func UpdateCmdDoneInfo(ctx context.Context, ck base.CommandKey, donePk *packet.CmdDonePacketType, status string) (*ModelUpdate, error) {
|
||||
if donePk == nil {
|
||||
return nil, fmt.Errorf("invalid cmddone packet")
|
||||
}
|
||||
@@ -950,8 +947,8 @@ func UpdateCmdDoneInfo(ctx context.Context, ck base.CommandKey, donePk *packet.C
|
||||
return nil, fmt.Errorf("cmd data not found for ck[%s]", ck)
|
||||
}
|
||||
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(*rtnCmd)
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *rtnCmd)
|
||||
|
||||
// Update in-memory screen indicator status
|
||||
var indicator StatusIndicatorLevel
|
||||
@@ -1099,7 +1096,7 @@ func getNextId(ids []string, delId string) string {
|
||||
return ids[0]
|
||||
}
|
||||
|
||||
func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (*scbus.ModelUpdatePacketType, error) {
|
||||
func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (*ModelUpdate, error) {
|
||||
SetActiveSessionId(ctx, sessionId)
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ?`
|
||||
@@ -1117,12 +1114,12 @@ func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(ActiveSessionIdUpdate(sessionId))
|
||||
update.AddUpdate(*bareSession)
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(sessionId))
|
||||
AddUpdate(update, *bareSession)
|
||||
memState := GetScreenMemState(screenId)
|
||||
if memState != nil {
|
||||
update.AddUpdate(CmdLineUpdate(memState.CmdInputText))
|
||||
AddCmdLineUpdate(update, memState.CmdInputText)
|
||||
UpdateWithCurrentOpenAICmdInfoChat(screenId, update)
|
||||
|
||||
// Clear any previous status indicator for this screen
|
||||
@@ -1154,7 +1151,7 @@ func cleanScreenCmds(ctx context.Context, screenId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ArchiveScreen(ctx context.Context, sessionId string, screenId string) (scbus.UpdatePacket, error) {
|
||||
func ArchiveScreen(ctx context.Context, sessionId string, screenId string) (UpdatePacket, error) {
|
||||
var isActive bool
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ?`
|
||||
@@ -1191,14 +1188,14 @@ func ArchiveScreen(ctx context.Context, sessionId string, screenId string) (scbu
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot retrive archived screen: %w", err)
|
||||
}
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(*newScreen)
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *newScreen)
|
||||
if isActive {
|
||||
bareSession, err := GetBareSessionById(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update.AddUpdate(*bareSession)
|
||||
AddUpdate(update, *bareSession)
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -1218,7 +1215,7 @@ func UnArchiveScreen(ctx context.Context, sessionId string, screenId string) err
|
||||
}
|
||||
|
||||
// if sessionDel is passed, we do *not* delete the screen directory (session delete will handle that)
|
||||
func DeleteScreen(ctx context.Context, screenId string, sessionDel bool, update *scbus.ModelUpdatePacketType) (*scbus.ModelUpdatePacketType, error) {
|
||||
func DeleteScreen(ctx context.Context, screenId string, sessionDel bool, update *ModelUpdate) (*ModelUpdate, error) {
|
||||
var sessionId string
|
||||
var isActive bool
|
||||
var screenTombstone *ScreenTombstoneType
|
||||
@@ -1279,16 +1276,16 @@ func DeleteScreen(ctx context.Context, screenId string, sessionDel bool, update
|
||||
GoDeleteScreenDirs(screenId)
|
||||
}
|
||||
if update == nil {
|
||||
update = scbus.MakeUpdatePacket()
|
||||
update = &ModelUpdate{}
|
||||
}
|
||||
update.AddUpdate(*screenTombstone)
|
||||
update.AddUpdate(ScreenType{SessionId: sessionId, ScreenId: screenId, Remove: true})
|
||||
AddUpdate(update, *screenTombstone)
|
||||
AddUpdate(update, ScreenType{SessionId: sessionId, ScreenId: screenId, Remove: true})
|
||||
if isActive {
|
||||
bareSession, err := GetBareSessionById(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update.AddUpdate(*bareSession)
|
||||
AddUpdate(update, *bareSession)
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -1519,7 +1516,7 @@ func SetScreenName(ctx context.Context, sessionId string, screenId string, name
|
||||
return txErr
|
||||
}
|
||||
|
||||
func ArchiveScreenLines(ctx context.Context, screenId string) (*scbus.ModelUpdatePacketType, error) {
|
||||
func ArchiveScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error) {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid FROM screen WHERE screenid = ?`
|
||||
if !tx.Exists(query, screenId) {
|
||||
@@ -1538,12 +1535,12 @@ func ArchiveScreenLines(ctx context.Context, screenId string) (*scbus.ModelUpdat
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := scbus.MakeUpdatePacket()
|
||||
ret.AddUpdate(*screenLines)
|
||||
ret := &ModelUpdate{}
|
||||
AddUpdate(ret, *screenLines)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func DeleteScreenLines(ctx context.Context, screenId string) (*scbus.ModelUpdatePacketType, error) {
|
||||
func DeleteScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error) {
|
||||
var lineIds []string
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT lineid FROM line
|
||||
@@ -1582,9 +1579,9 @@ func DeleteScreenLines(ctx context.Context, screenId string) (*scbus.ModelUpdate
|
||||
}
|
||||
screenLines.Lines = append(screenLines.Lines, line)
|
||||
}
|
||||
ret := scbus.MakeUpdatePacket()
|
||||
ret.AddUpdate(*screen)
|
||||
ret.AddUpdate(*screenLines)
|
||||
ret := &ModelUpdate{}
|
||||
AddUpdate(ret, *screen)
|
||||
AddUpdate(ret, *screenLines)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -1632,11 +1629,11 @@ func ScreenReset(ctx context.Context, screenId string) ([]*RemoteInstance, error
|
||||
})
|
||||
}
|
||||
|
||||
func DeleteSession(ctx context.Context, sessionId string) (scbus.UpdatePacket, error) {
|
||||
func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error) {
|
||||
var newActiveSessionId string
|
||||
var screenIds []string
|
||||
var sessionTombstone *SessionTombstoneType
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update := &ModelUpdate{}
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
bareSession, err := GetBareSessionById(tx.Context(), sessionId)
|
||||
if err != nil {
|
||||
@@ -1671,11 +1668,11 @@ func DeleteSession(ctx context.Context, sessionId string) (scbus.UpdatePacket, e
|
||||
}
|
||||
GoDeleteScreenDirs(screenIds...)
|
||||
if newActiveSessionId != "" {
|
||||
update.AddUpdate(ActiveSessionIdUpdate(newActiveSessionId))
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(newActiveSessionId))
|
||||
}
|
||||
update.AddUpdate(SessionType{SessionId: sessionId, Remove: true})
|
||||
AddUpdate(update, SessionType{SessionId: sessionId, Remove: true})
|
||||
if sessionTombstone != nil {
|
||||
update.AddUpdate(*sessionTombstone)
|
||||
AddUpdate(update, *sessionTombstone)
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -1702,7 +1699,7 @@ func fixActiveSessionId(ctx context.Context) (string, error) {
|
||||
return newActiveSessionId, nil
|
||||
}
|
||||
|
||||
func ArchiveSession(ctx context.Context, sessionId string) (*scbus.ModelUpdatePacketType, error) {
|
||||
func ArchiveSession(ctx context.Context, sessionId string) (*ModelUpdate, error) {
|
||||
if sessionId == "" {
|
||||
return nil, fmt.Errorf("invalid blank sessionid")
|
||||
}
|
||||
@@ -1726,17 +1723,17 @@ func ArchiveSession(ctx context.Context, sessionId string) (*scbus.ModelUpdatePa
|
||||
return nil, txErr
|
||||
}
|
||||
bareSession, _ := GetBareSessionById(ctx, sessionId)
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update := &ModelUpdate{}
|
||||
if bareSession != nil {
|
||||
update.AddUpdate(*bareSession)
|
||||
AddUpdate(update, *bareSession)
|
||||
}
|
||||
if newActiveSessionId != "" {
|
||||
update.AddUpdate(ActiveSessionIdUpdate(newActiveSessionId))
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(newActiveSessionId))
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func UnArchiveSession(ctx context.Context, sessionId string, activate bool) (*scbus.ModelUpdatePacketType, error) {
|
||||
func UnArchiveSession(ctx context.Context, sessionId string, activate bool) (*ModelUpdate, error) {
|
||||
if sessionId == "" {
|
||||
return nil, fmt.Errorf("invalid blank sessionid")
|
||||
}
|
||||
@@ -1762,13 +1759,13 @@ func UnArchiveSession(ctx context.Context, sessionId string, activate bool) (*sc
|
||||
return nil, txErr
|
||||
}
|
||||
bareSession, _ := GetBareSessionById(ctx, sessionId)
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update := &ModelUpdate{}
|
||||
|
||||
if bareSession != nil {
|
||||
update.AddUpdate(*bareSession)
|
||||
AddUpdate(update, *bareSession)
|
||||
}
|
||||
if activate {
|
||||
update.AddUpdate(ActiveSessionIdUpdate(sessionId))
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(sessionId))
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -2868,9 +2865,6 @@ func GetRemoteActiveShells(ctx context.Context, remoteId string) ([]string, erro
|
||||
riArr := dbutil.SelectMapsGen[*RemoteInstance](tx, query, remoteId)
|
||||
shellTypeMap := make(map[string]bool)
|
||||
for _, ri := range riArr {
|
||||
if ri.ShellType == "" {
|
||||
continue
|
||||
}
|
||||
shellTypeMap[ri.ShellType] = true
|
||||
}
|
||||
return utilfn.GetMapKeys(shellTypeMap), nil
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user