mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-22 21:42:49 +01:00
checkpoint on big cmd screen migration
This commit is contained in:
parent
cec75c0d5b
commit
02ae7ea972
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*~
|
||||
bin/
|
||||
*.out
|
@ -143,6 +143,12 @@ func HandleGetClientData(w http.ResponseWriter, r *http.Request) {
|
||||
WriteJsonError(w, err)
|
||||
return
|
||||
}
|
||||
mdata, err := sstore.GetCmdMigrationInfo(r.Context())
|
||||
if err != nil {
|
||||
WriteJsonError(w, err)
|
||||
return
|
||||
}
|
||||
cdata.Migration = mdata
|
||||
WriteJsonSuccess(w, cdata)
|
||||
return
|
||||
}
|
||||
@ -223,16 +229,16 @@ func HandleRtnState(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}()
|
||||
qvals := r.URL.Query()
|
||||
sessionId := qvals.Get("sessionid")
|
||||
screenId := qvals.Get("screenid")
|
||||
cmdId := qvals.Get("cmdid")
|
||||
if sessionId == "" || cmdId == "" {
|
||||
if screenId == "" || cmdId == "" {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(fmt.Sprintf("must specify sessionid and cmdid")))
|
||||
w.Write([]byte(fmt.Sprintf("must specify screenid and cmdid")))
|
||||
return
|
||||
}
|
||||
if _, err := uuid.Parse(sessionId); err != nil {
|
||||
if _, err := uuid.Parse(screenId); err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(fmt.Sprintf("invalid sessionid: %v", err)))
|
||||
w.Write([]byte(fmt.Sprintf("invalid screenid: %v", err)))
|
||||
return
|
||||
}
|
||||
if _, err := uuid.Parse(cmdId); err != nil {
|
||||
@ -240,7 +246,7 @@ func HandleRtnState(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(fmt.Sprintf("invalid cmdid: %v", err)))
|
||||
return
|
||||
}
|
||||
data, err := cmdrunner.GetRtnStateDiff(r.Context(), sessionId, cmdId)
|
||||
data, err := cmdrunner.GetRtnStateDiff(r.Context(), screenId, cmdId)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(fmt.Sprintf("cannot get rtnstate diff: %v", err)))
|
||||
@ -278,16 +284,16 @@ func HandleRemotePty(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func HandleGetPtyOut(w http.ResponseWriter, r *http.Request) {
|
||||
qvals := r.URL.Query()
|
||||
sessionId := qvals.Get("sessionid")
|
||||
screenId := qvals.Get("screenid")
|
||||
cmdId := qvals.Get("cmdid")
|
||||
if sessionId == "" || cmdId == "" {
|
||||
if screenId == "" || cmdId == "" {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(fmt.Sprintf("must specify sessionid and cmdid")))
|
||||
w.Write([]byte(fmt.Sprintf("must specify screenid and cmdid")))
|
||||
return
|
||||
}
|
||||
if _, err := uuid.Parse(sessionId); err != nil {
|
||||
if _, err := uuid.Parse(screenId); err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(fmt.Sprintf("invalid sessionid: %v", err)))
|
||||
w.Write([]byte(fmt.Sprintf("invalid screenid: %v", err)))
|
||||
return
|
||||
}
|
||||
if _, err := uuid.Parse(cmdId); err != nil {
|
||||
@ -295,7 +301,7 @@ func HandleGetPtyOut(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(fmt.Sprintf("invalid cmdid: %v", err)))
|
||||
return
|
||||
}
|
||||
realOffset, data, err := sstore.ReadFullPtyOutFile(r.Context(), sessionId, cmdId)
|
||||
realOffset, data, err := sstore.ReadFullPtyOutFile(r.Context(), screenId, cmdId)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
@ -558,6 +564,7 @@ func main() {
|
||||
go telemetryLoop()
|
||||
go stdinReadWatch()
|
||||
go runWebSocketServer()
|
||||
go sstore.RunCmdScreenMigration()
|
||||
gr := mux.NewRouter()
|
||||
gr.HandleFunc("/api/ptyout", AuthKeyWrap(HandleGetPtyOut))
|
||||
gr.HandleFunc("/api/remote-pty", AuthKeyWrap(HandleRemotePty))
|
||||
|
2
db/migrations/000013_cmdmigration.down.sql
Normal file
2
db/migrations/000013_cmdmigration.down.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- invalid, will throw an error, cannot migrate down
|
||||
SELECT x;
|
123
db/migrations/000013_cmdmigration.up.sql
Normal file
123
db/migrations/000013_cmdmigration.up.sql
Normal file
@ -0,0 +1,123 @@
|
||||
DELETE FROM cmd
|
||||
WHERE screenid = '';
|
||||
|
||||
DELETE FROM line
|
||||
WHERE screenid = '';
|
||||
|
||||
DELETE FROM cmd
|
||||
WHERE cmdid NOT IN (SELECT cmdid FROM line);
|
||||
|
||||
DELETE FROM line
|
||||
WHERE cmdid <> '' AND cmdid NOT IN (SELECT cmdid FROM cmd);
|
||||
|
||||
CREATE TABLE new_bookmark_cmd (
|
||||
bookmarkid varchar(36) NOT NULL,
|
||||
screenid varchar(36) NOT NULL,
|
||||
cmdid varchar(36) NOT NULL,
|
||||
PRIMARY KEY (bookmarkid, screenid, cmdid)
|
||||
);
|
||||
INSERT INTO new_bookmark_cmd
|
||||
SELECT
|
||||
b.bookmarkid,
|
||||
c.screenid,
|
||||
c.cmdid
|
||||
FROM bookmark_cmd b, cmd c
|
||||
WHERE b.cmdid = c.cmdid;
|
||||
DROP TABLE bookmark_cmd;
|
||||
ALTER TABLE new_bookmark_cmd RENAME TO bookmark_cmd;
|
||||
|
||||
ALTER TABLE client ADD COLUMN cmdstoretype varchar(20) DEFAULT 'session';
|
||||
|
||||
CREATE TABLE cmd_migrate (
|
||||
sessionid varchar(36) NOT NULL,
|
||||
screenid varchar(36) NOT NULL,
|
||||
cmdid varchar(36) NOT NULL
|
||||
);
|
||||
INSERT INTO cmd_migrate
|
||||
SELECT sessionid, screenid, cmdid
|
||||
FROM cmd;
|
||||
|
||||
-- update primary key for screen
|
||||
CREATE TABLE new_screen (
|
||||
screenid varchar(36) NOT NULL,
|
||||
sessionid varchar(36) NOT NULL,
|
||||
name varchar(50) NOT NULL,
|
||||
screenidx int NOT NULL,
|
||||
screenopts json NOT NULL,
|
||||
ownerid varchar(36) NOT NULL,
|
||||
sharemode varchar(12) NOT NULL,
|
||||
curremoteownerid varchar(36) NOT NULL,
|
||||
curremoteid varchar(36) NOT NULL,
|
||||
curremotename varchar(50) NOT NULL,
|
||||
nextlinenum int NOT NULL,
|
||||
selectedline int NOT NULL,
|
||||
anchor json NOT NULL,
|
||||
focustype varchar(12) NOT NULL,
|
||||
archived boolean NOT NULL,
|
||||
archivedts bigint NOT NULL,
|
||||
PRIMARY KEY (screenid)
|
||||
);
|
||||
INSERT INTO new_screen
|
||||
SELECT screenid, sessionid, name, screenidx, screenopts, ownerid, sharemode,
|
||||
curremoteownerid, curremoteid, curremotename, nextlinenum, selectedline,
|
||||
anchor, focustype, archived, archivedts
|
||||
FROM screen;
|
||||
DROP TABLE screen;
|
||||
ALTER TABLE new_screen RENAME TO screen;
|
||||
|
||||
-- drop sessionid from line
|
||||
CREATE TABLE new_line (
|
||||
screenid varchar(36) NOT NULL,
|
||||
userid varchar(36) NOT NULL,
|
||||
lineid varchar(36) NOT NULL,
|
||||
ts bigint NOT NULL,
|
||||
linenum int NOT NULL,
|
||||
linenumtemp boolean NOT NULL,
|
||||
linetype varchar(10) NOT NULL,
|
||||
linelocal boolean NOT NULL,
|
||||
text text NOT NULL,
|
||||
cmdid varchar(36) NOT NULL,
|
||||
ephemeral boolean NOT NULL,
|
||||
contentheight int NOT NULL,
|
||||
star int NOT NULL,
|
||||
archived boolean NOT NULL,
|
||||
renderer varchar(50) NOT NULL,
|
||||
bookmarked boolean NOT NULL,
|
||||
PRIMARY KEY (screenid, lineid)
|
||||
);
|
||||
INSERT INTO new_line
|
||||
SELECT screenid, userid, lineid, ts, linenum, linenumtemp, linetype, linelocal,
|
||||
text, cmdid, ephemeral, contentheight, star, archived, renderer, bookmarked
|
||||
FROM line;
|
||||
DROP TABLE line;
|
||||
ALTER TABLE new_line RENAME TO line;
|
||||
|
||||
-- drop sessionid from cmd
|
||||
CREATE TABLE new_cmd (
|
||||
screenid varchar(36) NOT NULL,
|
||||
cmdid varchar(36) NOT NULL,
|
||||
remoteownerid varchar(36) NOT NULL,
|
||||
remoteid varchar(36) NOT NULL,
|
||||
remotename varchar(50) NOT NULL,
|
||||
cmdstr text NOT NULL,
|
||||
rawcmdstr text NOT NULL,
|
||||
festate json NOT NULL,
|
||||
statebasehash varchar(36) NOT NULL,
|
||||
statediffhasharr json NOT NULL,
|
||||
termopts json NOT NULL,
|
||||
origtermopts json NOT NULL,
|
||||
status varchar(10) NOT NULL,
|
||||
startpk json NOT NULL,
|
||||
doneinfo json NOT NULL,
|
||||
runout json NOT NULL,
|
||||
rtnstate boolean NOT NULL,
|
||||
rtnbasehash varchar(36) NOT NULL,
|
||||
rtndiffhasharr json NOT NULL,
|
||||
PRIMARY KEY (screenid, cmdid)
|
||||
);
|
||||
INSERT INTO new_cmd
|
||||
SELECT screenid, cmdid, remoteownerid, remoteid, remotename, cmdstr, cmdstr,
|
||||
festate, statebasehash, statediffhasharr, termopts, origtermopts, status, startpk, doneinfo, runout, rtnstate, rtnbasehash, rtndiffhasharr
|
||||
FROM cmd;
|
||||
DROP TABLE cmd;
|
||||
ALTER TABLE new_cmd RENAME TO cmd;
|
@ -417,7 +417,7 @@ func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.U
|
||||
// runPacket.State is set in remote.RunCommand()
|
||||
runPacket := packet.MakeRunPacket()
|
||||
runPacket.ReqId = uuid.New().String()
|
||||
runPacket.CK = base.MakeCommandKey(ids.SessionId, scbase.GenPromptUUID())
|
||||
runPacket.CK = base.MakeCommandKey(ids.ScreenId, scbase.GenPromptUUID())
|
||||
runPacket.UsePty = true
|
||||
ptermVal := defaultStr(pk.Kwargs["pterm"], DefaultPTERM)
|
||||
runPacket.TermOpts, err = GetUITermOpts(pk.UIContext.WinSize, ptermVal)
|
||||
@ -433,12 +433,13 @@ func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.U
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd.RawCmdStr = pk.GetRawStr()
|
||||
update, err := addLineForCmd(ctx, "/run", true, ids, cmd, renderer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update.Interactive = pk.Interactive
|
||||
sstore.MainBus.SendUpdate(ids.SessionId, update)
|
||||
sstore.MainBus.SendScreenUpdate(ids.ScreenId, update)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -559,7 +560,7 @@ func ScreenPurgeCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/screen:purge cannot purge screen: %w", err)
|
||||
}
|
||||
update, err := sstore.DeleteScreen(ctx, ids.ScreenId)
|
||||
update, err := sstore.PurgeScreen(ctx, ids.ScreenId, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1255,10 +1256,10 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
|
||||
|
||||
func makeStaticCmd(ctx context.Context, metaCmd string, ids resolvedIds, cmdStr string, cmdOutput []byte) (*sstore.CmdType, error) {
|
||||
cmd := &sstore.CmdType{
|
||||
SessionId: ids.SessionId,
|
||||
ScreenId: ids.ScreenId,
|
||||
CmdId: scbase.GenPromptUUID(),
|
||||
CmdStr: cmdStr,
|
||||
RawCmdStr: cmdStr,
|
||||
Remote: ids.Remote.RemotePtr,
|
||||
TermOpts: sstore.TermOpts{Rows: shexec.DefaultTermRows, Cols: shexec.DefaultTermCols, FlexRows: true, MaxPtySize: remote.DefaultMaxPtySize},
|
||||
Status: sstore.CmdStatusDone,
|
||||
@ -1272,13 +1273,13 @@ func makeStaticCmd(ctx context.Context, metaCmd string, ids resolvedIds, cmdStr
|
||||
if ids.Remote.FeState != nil {
|
||||
cmd.FeState = *ids.Remote.FeState
|
||||
}
|
||||
err := sstore.CreateCmdPtyFile(ctx, cmd.SessionId, cmd.CmdId, cmd.TermOpts.MaxPtySize)
|
||||
err := sstore.CreateCmdPtyFile(ctx, cmd.ScreenId, cmd.CmdId, cmd.TermOpts.MaxPtySize)
|
||||
if err != nil {
|
||||
// TODO tricky error since the command was a success, but we can't show the output
|
||||
return nil, fmt.Errorf("cannot create local ptyout file for %s command: %w", metaCmd, err)
|
||||
}
|
||||
// can ignore ptyupdate
|
||||
_, err = sstore.AppendToCmdPtyBlob(ctx, cmd.SessionId, ids.ScreenId, cmd.CmdId, cmdOutput, 0)
|
||||
_, err = sstore.AppendToCmdPtyBlob(ctx, ids.ScreenId, cmd.CmdId, cmdOutput, 0)
|
||||
if err != nil {
|
||||
// TODO tricky error since the command was a success, but we can't show the output
|
||||
return nil, fmt.Errorf("cannot append to local ptyout file for %s command: %v", metaCmd, err)
|
||||
@ -1287,7 +1288,7 @@ func makeStaticCmd(ctx context.Context, metaCmd string, ids resolvedIds, cmdStr
|
||||
}
|
||||
|
||||
func addLineForCmd(ctx context.Context, metaCmd string, shouldFocus bool, ids resolvedIds, cmd *sstore.CmdType, renderer string) (*sstore.ModelUpdate, error) {
|
||||
rtnLine, err := sstore.AddCmdLine(ctx, ids.SessionId, ids.ScreenId, DefaultUserId, cmd, renderer)
|
||||
rtnLine, err := sstore.AddCmdLine(ctx, ids.ScreenId, DefaultUserId, cmd, renderer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1495,7 +1496,7 @@ func CommentCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
|
||||
if strings.TrimSpace(text) == "" {
|
||||
return nil, fmt.Errorf("cannot post empty comment")
|
||||
}
|
||||
rtnLine, err := sstore.AddCommentLine(ctx, ids.SessionId, ids.ScreenId, DefaultUserId, text)
|
||||
rtnLine, err := sstore.AddCommentLine(ctx, ids.ScreenId, DefaultUserId, text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1637,7 +1638,7 @@ func SessionDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update, err := sstore.DeleteSession(ctx, ids.SessionId)
|
||||
update, err := sstore.PurgeSession(ctx, ids.SessionId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete session: %v", err)
|
||||
}
|
||||
@ -1907,10 +1908,9 @@ func HistoryPurgeCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
continue
|
||||
}
|
||||
lineObj := &sstore.LineType{
|
||||
SessionId: historyItem.SessionId,
|
||||
ScreenId: historyItem.ScreenId,
|
||||
LineId: historyItem.LineId,
|
||||
Remove: true,
|
||||
ScreenId: historyItem.ScreenId,
|
||||
LineId: historyItem.LineId,
|
||||
Remove: true,
|
||||
}
|
||||
update.Lines = append(update.Lines, lineObj)
|
||||
}
|
||||
@ -2076,7 +2076,7 @@ func splitLinesForInfo(str string) []string {
|
||||
|
||||
func resizeRunningCommand(ctx context.Context, cmd *sstore.CmdType, newCols int) error {
|
||||
siPk := packet.MakeSpecialInputPacket()
|
||||
siPk.CK = base.MakeCommandKey(cmd.SessionId, cmd.CmdId)
|
||||
siPk.CK = base.MakeCommandKey(cmd.ScreenId, cmd.CmdId)
|
||||
siPk.WinSize = &packet.WinSize{Rows: int(cmd.TermOpts.Rows), Cols: newCols}
|
||||
msh := remote.GetRemoteById(cmd.Remote.RemoteId)
|
||||
if msh == nil {
|
||||
@ -2088,7 +2088,7 @@ func resizeRunningCommand(ctx context.Context, cmd *sstore.CmdType, newCols int)
|
||||
}
|
||||
newTermOpts := cmd.TermOpts
|
||||
newTermOpts.Cols = int64(newCols)
|
||||
err = sstore.UpdateCmdTermOpts(ctx, cmd.SessionId, cmd.CmdId, newTermOpts)
|
||||
err = sstore.UpdateCmdTermOpts(ctx, cmd.ScreenId, cmd.CmdId, newTermOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -2112,7 +2112,7 @@ func ScreenResizeCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
return nil, fmt.Errorf("/screen:resize invalid zero/negative 'cols' argument")
|
||||
}
|
||||
cols = base.BoundInt(cols, shexec.MinTermCols, shexec.MaxTermCols)
|
||||
runningCmds, err := sstore.GetRunningScreenCmds(ctx, ids.SessionId, ids.ScreenId)
|
||||
runningCmds, err := sstore.GetRunningScreenCmds(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/screen:resize cannot get running commands: %v", err)
|
||||
}
|
||||
@ -2140,7 +2140,7 @@ func LineSetHeightCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
return nil, fmt.Errorf("/line:setheight requires 2 arguments (linearg and height)")
|
||||
}
|
||||
lineArg := pk.Args[0]
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
@ -2168,7 +2168,7 @@ func LineSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
|
||||
return nil, fmt.Errorf("/line:set requires 1 argument (linearg)")
|
||||
}
|
||||
lineArg := pk.Args[0]
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
@ -2186,7 +2186,7 @@ func LineSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
|
||||
if len(varsUpdated) == 0 {
|
||||
return nil, fmt.Errorf("/line:set requires a value to set: %s", formatStrs([]string{"renderer"}, "or", false))
|
||||
}
|
||||
updatedLine, err := sstore.GetLineById(ctx, ids.SessionId, ids.ScreenId, lineId)
|
||||
updatedLine, err := sstore.GetLineById(ctx, ids.ScreenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:set cannot retrieve updated line: %v", err)
|
||||
}
|
||||
@ -2332,21 +2332,21 @@ func LineBookmarkCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
return nil, fmt.Errorf("/line:bookmark requires an argument (line number or id)")
|
||||
}
|
||||
lineArg := pk.Args[0]
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
if lineId == "" {
|
||||
return nil, fmt.Errorf("line %q not found", lineArg)
|
||||
}
|
||||
lineObj, cmdObj, err := sstore.GetLineCmdByLineId(ctx, ids.SessionId, ids.ScreenId, lineId)
|
||||
lineObj, cmdObj, err := sstore.GetLineCmdByLineId(ctx, ids.ScreenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:bookmark error getting line: %v", err)
|
||||
}
|
||||
if cmdObj == nil {
|
||||
return nil, fmt.Errorf("cannot bookmark non-cmd line")
|
||||
}
|
||||
ck := base.MakeCommandKey(lineObj.SessionId, cmdObj.CmdId)
|
||||
ck := base.MakeCommandKey(lineObj.ScreenId, cmdObj.CmdId)
|
||||
bm := &sstore.BookmarkType{
|
||||
BookmarkId: uuid.New().String(),
|
||||
CreatedTs: time.Now().UnixMilli(),
|
||||
@ -2360,7 +2360,7 @@ func LineBookmarkCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot insert bookmark: %v", err)
|
||||
}
|
||||
newLineObj, err := sstore.GetLineById(ctx, ids.SessionId, ids.ScreenId, lineId)
|
||||
newLineObj, err := sstore.GetLineById(ctx, ids.ScreenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:bookmark error getting line: %v", err)
|
||||
}
|
||||
@ -2387,7 +2387,7 @@ func LineStarCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sst
|
||||
return nil, fmt.Errorf("/line:star only takes up to 2 arguments (line-number and star-value)")
|
||||
}
|
||||
lineArg := pk.Args[0]
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
@ -2405,7 +2405,7 @@ func LineStarCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sst
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:star error updating star value: %v", err)
|
||||
}
|
||||
lineObj, err := sstore.GetLineById(ctx, ids.SessionId, ids.ScreenId, lineId)
|
||||
lineObj, err := sstore.GetLineById(ctx, ids.ScreenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:star error getting line: %v", err)
|
||||
}
|
||||
@ -2425,7 +2425,7 @@ func LineArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
|
||||
return nil, fmt.Errorf("/line:archive requires an argument (line number or id)")
|
||||
}
|
||||
lineArg := pk.Args[0]
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
@ -2440,7 +2440,7 @@ func LineArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:archive error updating hidden status: %v", err)
|
||||
}
|
||||
lineObj, err := sstore.GetLineById(ctx, ids.SessionId, ids.ScreenId, lineId)
|
||||
lineObj, err := sstore.GetLineById(ctx, ids.ScreenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:archive error getting line: %v", err)
|
||||
}
|
||||
@ -2461,7 +2461,7 @@ func LinePurgeCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
|
||||
}
|
||||
var lineIds []string
|
||||
for _, lineArg := range pk.Args {
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
@ -2470,17 +2470,16 @@ func LinePurgeCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
|
||||
}
|
||||
lineIds = append(lineIds, lineId)
|
||||
}
|
||||
err = sstore.PurgeLinesByIds(ctx, ids.SessionId, lineIds)
|
||||
err = sstore.PurgeLinesByIds(ctx, ids.ScreenId, lineIds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:purge error purging lines: %v", err)
|
||||
}
|
||||
update := sstore.ModelUpdate{}
|
||||
for _, lineId := range lineIds {
|
||||
lineObj := &sstore.LineType{
|
||||
SessionId: ids.SessionId,
|
||||
ScreenId: ids.ScreenId,
|
||||
LineId: lineId,
|
||||
Remove: true,
|
||||
ScreenId: ids.ScreenId,
|
||||
LineId: lineId,
|
||||
Remove: true,
|
||||
}
|
||||
update.Lines = append(update.Lines, lineObj)
|
||||
}
|
||||
@ -2496,14 +2495,14 @@ func LineShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sst
|
||||
return nil, fmt.Errorf("/line:show requires an argument (line number or id)")
|
||||
}
|
||||
lineArg := pk.Args[0]
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
if lineId == "" {
|
||||
return nil, fmt.Errorf("line %q not found", lineArg)
|
||||
}
|
||||
line, cmd, err := sstore.GetLineCmdByLineId(ctx, ids.SessionId, ids.ScreenId, lineId)
|
||||
line, cmd, err := sstore.GetLineCmdByLineId(ctx, ids.ScreenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting line: %v", err)
|
||||
}
|
||||
@ -2542,7 +2541,7 @@ func LineShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sst
|
||||
if cmd.RtnState {
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "rtnstate", "true"))
|
||||
}
|
||||
stat, _ := sstore.StatCmdPtyFile(ctx, cmd.SessionId, cmd.CmdId)
|
||||
stat, _ := sstore.StatCmdPtyFile(ctx, cmd.ScreenId, cmd.CmdId)
|
||||
if stat == nil {
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "file", "-"))
|
||||
} else {
|
||||
@ -2599,11 +2598,11 @@ func SignalCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
return nil, fmt.Errorf("/signal requires a second argument (signal name)")
|
||||
}
|
||||
lineArg := pk.Args[0]
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.ScreenId, lineArg)
|
||||
lineId, err := sstore.FindLineIdByArg(ctx, ids.ScreenId, lineArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up lineid: %v", err)
|
||||
}
|
||||
line, cmd, err := sstore.GetLineCmdByLineId(ctx, ids.SessionId, ids.ScreenId, lineId)
|
||||
line, cmd, err := sstore.GetLineCmdByLineId(ctx, ids.ScreenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting line: %v", err)
|
||||
}
|
||||
@ -2640,7 +2639,7 @@ func SignalCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
return nil, fmt.Errorf("cannot send signal, remote is not connected")
|
||||
}
|
||||
siPk := packet.MakeSpecialInputPacket()
|
||||
siPk.CK = base.MakeCommandKey(cmd.SessionId, cmd.CmdId)
|
||||
siPk.CK = base.MakeCommandKey(cmd.ScreenId, cmd.CmdId)
|
||||
siPk.SigName = sigArg
|
||||
err = msh.SendSpecialInput(siPk)
|
||||
if err != nil {
|
||||
@ -2950,8 +2949,8 @@ func displayStateUpdateDiff(buf *bytes.Buffer, oldState packet.ShellState, newSt
|
||||
}
|
||||
}
|
||||
|
||||
func GetRtnStateDiff(ctx context.Context, sessionId string, cmdId string) ([]byte, error) {
|
||||
cmd, err := sstore.GetCmdById(ctx, sessionId, cmdId)
|
||||
func GetRtnStateDiff(ctx context.Context, screenId string, cmdId string) ([]byte, error) {
|
||||
cmd, err := sstore.GetCmdByScreenId(ctx, screenId, cmdId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ func resolveSession(ctx context.Context, sessionArg string, curSessionArg string
|
||||
}
|
||||
|
||||
func resolveLine(ctx context.Context, sessionId string, screenId string, lineArg string, curLineArg string) (*ResolveItem, error) {
|
||||
lines, err := sstore.GetLineResolveItems(ctx, sessionId, screenId)
|
||||
lines, err := sstore.GetLineResolveItems(ctx, screenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get lines: %v", err)
|
||||
}
|
||||
|
@ -578,7 +578,7 @@ func (msh *MShellProc) GetRemoteRuntimeState() RemoteRuntimeState {
|
||||
func (msh *MShellProc) NotifyRemoteUpdate() {
|
||||
rstate := msh.GetRemoteRuntimeState()
|
||||
update := &sstore.ModelUpdate{Remotes: []interface{}{rstate}}
|
||||
sstore.MainBus.SendUpdate("", update)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
}
|
||||
|
||||
func GetAllRemoteRuntimeState() []RemoteRuntimeState {
|
||||
@ -811,7 +811,7 @@ func sendRemotePtyUpdate(remoteId string, dataOffset int64, data []byte) {
|
||||
PtyData64: data64,
|
||||
PtyDataLen: int64(len(data)),
|
||||
}
|
||||
sstore.MainBus.SendUpdate("", update)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
}
|
||||
|
||||
func (msh *MShellProc) isWaitingForPassword_nolock() bool {
|
||||
@ -1265,8 +1265,8 @@ func RunCommand(ctx context.Context, sessionId string, screenId string, remotePt
|
||||
if remotePtr.OwnerId != "" {
|
||||
return nil, nil, fmt.Errorf("cannot run command against another user's remote '%s'", remotePtr.MakeFullRemoteRef())
|
||||
}
|
||||
if sessionId != runPacket.CK.GetSessionId() {
|
||||
return nil, nil, fmt.Errorf("run commands sessionids do not match")
|
||||
if screenId != runPacket.CK.GetGroupId() {
|
||||
return nil, nil, fmt.Errorf("run commands screenids do not match")
|
||||
}
|
||||
msh := GetRemoteById(remotePtr.RemoteId)
|
||||
if msh == nil {
|
||||
@ -1284,7 +1284,7 @@ func RunCommand(ctx context.Context, sessionId string, screenId string, remotePt
|
||||
}
|
||||
ok, existingPSC := msh.testAndSetPendingStateCmd(remotePtr.Name, newPSC)
|
||||
if !ok {
|
||||
line, _, err := sstore.GetLineCmdByCmdId(ctx, sessionId, screenId, existingPSC.GetCmdId())
|
||||
line, _, err := sstore.GetLineCmdByCmdId(ctx, screenId, existingPSC.GetCmdId())
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("cannot run command while a stateful command is still running: %v", err)
|
||||
}
|
||||
@ -1344,10 +1344,10 @@ func RunCommand(ctx context.Context, sessionId string, screenId string, remotePt
|
||||
status = sstore.CmdStatusDetached
|
||||
}
|
||||
cmd := &sstore.CmdType{
|
||||
SessionId: runPacket.CK.GetSessionId(),
|
||||
ScreenId: screenId,
|
||||
ScreenId: runPacket.CK.GetGroupId(),
|
||||
CmdId: runPacket.CK.GetCmdId(),
|
||||
CmdStr: runPacket.Command,
|
||||
RawCmdStr: runPacket.Command,
|
||||
Remote: remotePtr,
|
||||
FeState: *sstore.FeStateFromShellState(currentState),
|
||||
StatePtr: *statePtr,
|
||||
@ -1358,7 +1358,7 @@ func RunCommand(ctx context.Context, sessionId string, screenId string, remotePt
|
||||
RunOut: nil,
|
||||
RtnState: runPacket.ReturnState,
|
||||
}
|
||||
err = sstore.CreateCmdPtyFile(ctx, cmd.SessionId, cmd.CmdId, cmd.TermOpts.MaxPtySize)
|
||||
err = sstore.CreateCmdPtyFile(ctx, cmd.ScreenId, cmd.CmdId, cmd.TermOpts.MaxPtySize)
|
||||
if err != nil {
|
||||
// TODO the cmd is running, so this is a tricky error to handle
|
||||
return nil, nil, fmt.Errorf("cannot create local ptyout file for running command: %v", err)
|
||||
@ -1476,12 +1476,12 @@ func makeDataAckPacket(ck base.CommandKey, fdNum int, ackLen int, err error) *pa
|
||||
|
||||
func (msh *MShellProc) notifyHangups_nolock() {
|
||||
for ck, _ := range msh.RunningCmds {
|
||||
cmd, err := sstore.GetCmdById(context.Background(), ck.GetSessionId(), ck.GetCmdId())
|
||||
cmd, err := sstore.GetCmdByScreenId(context.Background(), ck.GetGroupId(), ck.GetCmdId())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
update := sstore.ModelUpdate{Cmd: cmd}
|
||||
sstore.MainBus.SendUpdate(ck.GetSessionId(), update)
|
||||
sstore.MainBus.SendScreenUpdate(ck.GetGroupId(), update)
|
||||
}
|
||||
msh.RunningCmds = make(map[base.CommandKey]RunCmdType)
|
||||
}
|
||||
@ -1505,12 +1505,12 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
msh.WriteToPtyBuffer("*error updating cmddone: %v\n", err)
|
||||
return
|
||||
}
|
||||
screens, err := sstore.UpdateScreensWithCmdFg(context.Background(), donePk.CK.GetSessionId(), donePk.CK.GetCmdId())
|
||||
screen, err := sstore.UpdateScreenWithCmdFg(context.Background(), donePk.CK.GetGroupId(), donePk.CK.GetCmdId())
|
||||
if err != nil {
|
||||
msh.WriteToPtyBuffer("*error trying to update cmd-fg screens: %v\n", err)
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
update.Screens = screens
|
||||
update.Screens = []*sstore.ScreenType{screen}
|
||||
rct := msh.GetRunningCmd(donePk.CK)
|
||||
var statePtr *sstore.ShellStatePtr
|
||||
if donePk.FinalState != nil && rct != nil {
|
||||
@ -1550,13 +1550,13 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
}
|
||||
sstore.MainBus.SendUpdate(donePk.CK.GetSessionId(), update)
|
||||
sstore.MainBus.SendScreenUpdate(donePk.CK.GetGroupId(), update)
|
||||
return
|
||||
}
|
||||
|
||||
func (msh *MShellProc) handleCmdFinalPacket(finalPk *packet.CmdFinalPacketType) {
|
||||
defer msh.RemoveRunningCmd(finalPk.CK)
|
||||
rtnCmd, err := sstore.GetCmdById(context.Background(), finalPk.CK.GetSessionId(), finalPk.CK.GetCmdId())
|
||||
rtnCmd, err := sstore.GetCmdByScreenId(context.Background(), finalPk.CK.GetGroupId(), finalPk.CK.GetCmdId())
|
||||
if err != nil {
|
||||
log.Printf("error calling GetCmdById in handleCmdFinalPacket: %v\n", err)
|
||||
return
|
||||
@ -1566,7 +1566,7 @@ func (msh *MShellProc) handleCmdFinalPacket(finalPk *packet.CmdFinalPacketType)
|
||||
}
|
||||
log.Printf("finalpk %s (hangup): %s\n", finalPk.CK, finalPk.Error)
|
||||
sstore.HangupCmd(context.Background(), finalPk.CK)
|
||||
rtnCmd, err = sstore.GetCmdById(context.Background(), finalPk.CK.GetSessionId(), finalPk.CK.GetCmdId())
|
||||
rtnCmd, err = sstore.GetCmdByScreenId(context.Background(), finalPk.CK.GetGroupId(), finalPk.CK.GetCmdId())
|
||||
if err != nil {
|
||||
log.Printf("error getting cmd(2) in handleCmdFinalPacket: %v\n", err)
|
||||
return
|
||||
@ -1576,7 +1576,7 @@ func (msh *MShellProc) handleCmdFinalPacket(finalPk *packet.CmdFinalPacketType)
|
||||
return
|
||||
}
|
||||
update := &sstore.ModelUpdate{Cmd: rtnCmd}
|
||||
sstore.MainBus.SendUpdate(finalPk.CK.GetSessionId(), update)
|
||||
sstore.MainBus.SendScreenUpdate(finalPk.CK.GetGroupId(), update)
|
||||
}
|
||||
|
||||
// TODO notify FE about cmd errors
|
||||
@ -1600,7 +1600,7 @@ func (msh *MShellProc) handleDataPacket(dataPk *packet.DataPacketType, dataPosMa
|
||||
if len(realData) > 0 {
|
||||
dataPos := dataPosMap[dataPk.CK]
|
||||
rcmd := msh.GetRunningCmd(dataPk.CK)
|
||||
update, err := sstore.AppendToCmdPtyBlob(context.Background(), dataPk.CK.GetSessionId(), rcmd.ScreenId, dataPk.CK.GetCmdId(), realData, dataPos)
|
||||
update, err := sstore.AppendToCmdPtyBlob(context.Background(), rcmd.ScreenId, dataPk.CK.GetCmdId(), realData, dataPos)
|
||||
if err != nil {
|
||||
ack = makeDataAckPacket(dataPk.CK, dataPk.FdNum, 0, err)
|
||||
} else {
|
||||
@ -1608,7 +1608,7 @@ func (msh *MShellProc) handleDataPacket(dataPk *packet.DataPacketType, dataPosMa
|
||||
}
|
||||
dataPosMap[dataPk.CK] += int64(len(realData))
|
||||
if update != nil {
|
||||
sstore.MainBus.SendUpdate(dataPk.CK.GetSessionId(), update)
|
||||
sstore.MainBus.SendScreenUpdate(dataPk.CK.GetGroupId(), update)
|
||||
}
|
||||
}
|
||||
if ack != nil {
|
||||
|
@ -27,6 +27,7 @@ const HomeVarName = "HOME"
|
||||
const PromptHomeVarName = "PROMPT_HOME"
|
||||
const PromptDevVarName = "PROMPT_DEV"
|
||||
const SessionsDirBaseName = "sessions"
|
||||
const ScreensDirBaseName = "screens"
|
||||
const PromptLockFile = "prompt.lock"
|
||||
const PromptDirName = "prompt"
|
||||
const PromptDevDirName = "prompt-dev"
|
||||
@ -36,6 +37,7 @@ const PromptAuthKeyFileName = "prompt.authkey"
|
||||
const MShellVersion = "v0.2.0"
|
||||
|
||||
var SessionDirCache = make(map[string]string)
|
||||
var ScreenDirCache = make(map[string]string)
|
||||
var BaseLock = &sync.Mutex{}
|
||||
var BuildTime = "-"
|
||||
|
||||
@ -164,6 +166,7 @@ func AcquirePromptLock() (*os.File, error) {
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// deprecated (v0.1.8)
|
||||
func EnsureSessionDir(sessionId string) (string, error) {
|
||||
if sessionId == "" {
|
||||
return "", fmt.Errorf("cannot get session dir for blank sessionid")
|
||||
@ -186,12 +189,41 @@ func EnsureSessionDir(sessionId string) (string, error) {
|
||||
return sdir, nil
|
||||
}
|
||||
|
||||
// deprecated (v0.1.8)
|
||||
func GetSessionsDir() string {
|
||||
promptHome := GetPromptHomeDir()
|
||||
sdir := path.Join(promptHome, SessionsDirBaseName)
|
||||
return sdir
|
||||
}
|
||||
|
||||
func EnsureScreenDir(screenId string) (string, error) {
|
||||
if screenId == "" {
|
||||
return "", fmt.Errorf("cannot get screen dir for blank sessionid")
|
||||
}
|
||||
BaseLock.Lock()
|
||||
sdir, ok := ScreenDirCache[screenId]
|
||||
BaseLock.Unlock()
|
||||
if ok {
|
||||
return sdir, nil
|
||||
}
|
||||
scHome := GetPromptHomeDir()
|
||||
sdir = path.Join(scHome, ScreensDirBaseName, screenId)
|
||||
err := ensureDir(sdir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
BaseLock.Lock()
|
||||
ScreenDirCache[screenId] = sdir
|
||||
BaseLock.Unlock()
|
||||
return sdir, nil
|
||||
}
|
||||
|
||||
func GetScreensDir() string {
|
||||
promptHome := GetPromptHomeDir()
|
||||
sdir := path.Join(promptHome, ScreensDirBaseName)
|
||||
return sdir
|
||||
}
|
||||
|
||||
func ensureDir(dirName string) error {
|
||||
info, err := os.Stat(dirName)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
@ -211,7 +243,8 @@ func ensureDir(dirName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func PtyOutFile(sessionId string, cmdId string) (string, error) {
|
||||
// deprecated (v0.1.8)
|
||||
func PtyOutFile_Sessions(sessionId string, cmdId string) (string, error) {
|
||||
sdir, err := EnsureSessionDir(sessionId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -225,30 +258,18 @@ func PtyOutFile(sessionId string, cmdId string) (string, error) {
|
||||
return fmt.Sprintf("%s/%s.ptyout.cf", sdir, cmdId), nil
|
||||
}
|
||||
|
||||
func RunOutFile(sessionId string, cmdId string) (string, error) {
|
||||
sdir, err := EnsureSessionDir(sessionId)
|
||||
func PtyOutFile(screenId string, cmdId string) (string, error) {
|
||||
sdir, err := EnsureScreenDir(screenId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if sessionId == "" {
|
||||
return "", fmt.Errorf("cannot get runout file for blank sessionid")
|
||||
if screenId == "" {
|
||||
return "", fmt.Errorf("cannot get ptyout file for blank screenid")
|
||||
}
|
||||
if cmdId == "" {
|
||||
return "", fmt.Errorf("cannot get runout file for blank cmdid")
|
||||
return "", fmt.Errorf("cannot get ptyout file for blank cmdid")
|
||||
}
|
||||
return fmt.Sprintf("%s/%s.runout", sdir, cmdId), nil
|
||||
}
|
||||
|
||||
type PromptFileNameGenerator struct {
|
||||
PromptHome string
|
||||
}
|
||||
|
||||
func (g PromptFileNameGenerator) PtyOutFile(ck base.CommandKey) string {
|
||||
return path.Join(g.PromptHome, SessionsDirBaseName, ck.GetSessionId(), ck.GetCmdId()+".ptyout")
|
||||
}
|
||||
|
||||
func (g PromptFileNameGenerator) RunOutFile(ck base.CommandKey) string {
|
||||
return path.Join(g.PromptHome, SessionsDirBaseName, ck.GetSessionId(), ck.GetCmdId()+".runout")
|
||||
return fmt.Sprintf("%s/%s.ptyout.cf", sdir, cmdId), nil
|
||||
}
|
||||
|
||||
func GenPromptUUID() string {
|
||||
|
@ -99,7 +99,7 @@ func (ws *WSState) WatchScreen(sessionId string, screenId string) {
|
||||
}
|
||||
ws.SessionId = sessionId
|
||||
ws.ScreenId = screenId
|
||||
ws.UpdateCh = sstore.MainBus.RegisterChannel(ws.ClientId, ws.SessionId)
|
||||
ws.UpdateCh = sstore.MainBus.RegisterChannel(ws.ClientId, ws.ScreenId)
|
||||
go ws.RunUpdates(ws.UpdateCh)
|
||||
}
|
||||
|
||||
|
@ -440,12 +440,10 @@ func GetScreenLinesById(ctx context.Context, screenId string) (*ScreenLinesType,
|
||||
if screen == nil {
|
||||
return nil, nil
|
||||
}
|
||||
query = `SELECT sessionid FROM screen WHERE screenid = ?`
|
||||
sessionId := tx.GetString(query, screenId)
|
||||
query = `SELECT * FROM line WHERE sessionid = ? AND screenid = ? ORDER BY linenum`
|
||||
tx.Select(&screen.Lines, query, sessionId, screen.ScreenId)
|
||||
query = `SELECT * FROM cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE sessionid = ? AND screenid = ?)`
|
||||
screen.Cmds = SelectMapsGen[*CmdType](tx, query, sessionId, screen.ScreenId)
|
||||
query = `SELECT * FROM line WHERE screenid = ? ORDER BY linenum`
|
||||
tx.Select(&screen.Lines, query, screen.ScreenId)
|
||||
query = `SELECT * FROM cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE screenid = ?)`
|
||||
screen.Cmds = SelectMapsGen[*CmdType](tx, query, screen.ScreenId)
|
||||
return screen, nil
|
||||
})
|
||||
}
|
||||
@ -700,22 +698,22 @@ func GetScreenById(ctx context.Context, screenId string) (*ScreenType, error) {
|
||||
})
|
||||
}
|
||||
|
||||
func FindLineIdByArg(ctx context.Context, sessionId string, screenId string, lineArg string) (string, error) {
|
||||
func FindLineIdByArg(ctx context.Context, screenId string, lineArg string) (string, error) {
|
||||
var lineId string
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
lineNum, err := strconv.Atoi(lineArg)
|
||||
if err == nil {
|
||||
// valid linenum
|
||||
query := `SELECT lineid FROM line WHERE sessionid = ? AND screenid = ? AND linenum = ?`
|
||||
lineId = tx.GetString(query, sessionId, screenId, lineNum)
|
||||
query := `SELECT lineid FROM line WHERE screenid = ? AND linenum = ?`
|
||||
lineId = tx.GetString(query, screenId, lineNum)
|
||||
} else if len(lineArg) == 8 {
|
||||
// prefix id string match
|
||||
query := `SELECT lineid FROM line WHERE sessionid = ? AND screenid = ? AND substr(lineid, 1, 8) = ?`
|
||||
lineId = tx.GetString(query, sessionId, screenId, lineArg)
|
||||
query := `SELECT lineid FROM line WHERE screenid = ? AND substr(lineid, 1, 8) = ?`
|
||||
lineId = tx.GetString(query, screenId, lineArg)
|
||||
} else {
|
||||
// id match
|
||||
query := `SELECT lineid FROM line WHERE sessionid = ? AND screenid = ? AND lineid = ?`
|
||||
lineId = tx.GetString(query, sessionId, screenId, lineArg)
|
||||
query := `SELECT lineid FROM line WHERE screenid = ? AND lineid = ?`
|
||||
lineId = tx.GetString(query, screenId, lineArg)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -725,33 +723,33 @@ func FindLineIdByArg(ctx context.Context, sessionId string, screenId string, lin
|
||||
return lineId, nil
|
||||
}
|
||||
|
||||
func GetLineCmdByLineId(ctx context.Context, sessionId string, screenId string, lineId string) (*LineType, *CmdType, error) {
|
||||
func GetLineCmdByLineId(ctx context.Context, screenId string, lineId string) (*LineType, *CmdType, error) {
|
||||
return WithTxRtn3(ctx, func(tx *TxWrap) (*LineType, *CmdType, error) {
|
||||
var lineVal LineType
|
||||
query := `SELECT * FROM line WHERE sessionid = ? AND screenid = ? AND lineid = ?`
|
||||
found := tx.Get(&lineVal, query, sessionId, screenId, lineId)
|
||||
query := `SELECT * FROM line WHERE screenid = ? AND lineid = ?`
|
||||
found := tx.Get(&lineVal, query, screenId, lineId)
|
||||
if !found {
|
||||
return nil, nil, nil
|
||||
}
|
||||
var cmdRtn *CmdType
|
||||
if lineVal.CmdId != "" {
|
||||
query = `SELECT * FROM cmd WHERE sessionid = ? AND cmdid = ?`
|
||||
cmdRtn = GetMapGen[*CmdType](tx, query, sessionId, lineVal.CmdId)
|
||||
query = `SELECT * FROM cmd WHERE screenid = ? AND cmdid = ?`
|
||||
cmdRtn = GetMapGen[*CmdType](tx, query, screenId, lineVal.CmdId)
|
||||
}
|
||||
return &lineVal, cmdRtn, nil
|
||||
})
|
||||
}
|
||||
|
||||
func GetLineCmdByCmdId(ctx context.Context, sessionId string, screenId string, cmdId string) (*LineType, *CmdType, error) {
|
||||
func GetLineCmdByCmdId(ctx context.Context, screenId string, cmdId string) (*LineType, *CmdType, error) {
|
||||
return WithTxRtn3(ctx, func(tx *TxWrap) (*LineType, *CmdType, error) {
|
||||
var lineVal LineType
|
||||
query := `SELECT * FROM line WHERE sessionid = ? AND screenid = ? AND cmdid = ?`
|
||||
found := tx.Get(&lineVal, query, sessionId, screenId, cmdId)
|
||||
query := `SELECT * FROM line WHERE screenid = ? AND cmdid = ?`
|
||||
found := tx.Get(&lineVal, query, screenId, cmdId)
|
||||
if !found {
|
||||
return nil, nil, nil
|
||||
}
|
||||
query = `SELECT * FROM cmd WHERE sessionid = ? AND cmdid = ?`
|
||||
cmdRtn := GetMapGen[*CmdType](tx, query, sessionId, cmdId)
|
||||
query = `SELECT * FROM cmd WHERE screenid = ? AND cmdid = ?`
|
||||
cmdRtn := GetMapGen[*CmdType](tx, query, screenId, cmdId)
|
||||
return &lineVal, cmdRtn, nil
|
||||
})
|
||||
}
|
||||
@ -770,24 +768,24 @@ func InsertLine(ctx context.Context, line *LineType, cmd *CmdType) error {
|
||||
return fmt.Errorf("cmd should have screenid set")
|
||||
}
|
||||
return WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ?`
|
||||
if !tx.Exists(query, line.SessionId, line.ScreenId) {
|
||||
return fmt.Errorf("screen not found, cannot insert line[%s/%s]", line.SessionId, line.ScreenId)
|
||||
query := `SELECT screenid FROM screen WHERE screenid = ?`
|
||||
if !tx.Exists(query, line.ScreenId) {
|
||||
return fmt.Errorf("screen not found, cannot insert line[%s]", line.ScreenId)
|
||||
}
|
||||
query = `SELECT nextlinenum FROM screen WHERE sessionid = ? AND screenid = ?`
|
||||
nextLineNum := tx.GetInt(query, line.SessionId, line.ScreenId)
|
||||
query = `SELECT nextlinenum FROM screen WHERE screenid = ?`
|
||||
nextLineNum := tx.GetInt(query, line.ScreenId)
|
||||
line.LineNum = int64(nextLineNum)
|
||||
query = `INSERT INTO line ( sessionid, screenid, userid, lineid, ts, linenum, linenumtemp, linelocal, linetype, text, cmdid, renderer, ephemeral, contentheight, star, archived, bookmarked, pinned)
|
||||
VALUES (:sessionid,:screenid,:userid,:lineid,:ts,:linenum,:linenumtemp,:linelocal,:linetype,:text,:cmdid,:renderer,:ephemeral,:contentheight,:star,:archived,:bookmarked,:pinned)`
|
||||
query = `INSERT INTO line ( screenid, userid, lineid, ts, linenum, linenumtemp, linelocal, linetype, text, cmdid, renderer, ephemeral, contentheight, star, archived, bookmarked)
|
||||
VALUES (:screenid,:userid,:lineid,:ts,:linenum,:linenumtemp,:linelocal,:linetype,:text,:cmdid,:renderer,:ephemeral,:contentheight,:star,:archived,:bookmarked)`
|
||||
tx.NamedExec(query, line)
|
||||
query = `UPDATE screen SET nextlinenum = ? WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Exec(query, nextLineNum+1, line.SessionId, line.ScreenId)
|
||||
query = `UPDATE screen SET nextlinenum = ? WHERE screenid = ?`
|
||||
tx.Exec(query, nextLineNum+1, line.ScreenId)
|
||||
if cmd != nil {
|
||||
cmd.OrigTermOpts = cmd.TermOpts
|
||||
cmdMap := cmd.ToMap()
|
||||
query = `
|
||||
INSERT INTO cmd ( sessionid, screenid, cmdid, remoteownerid, remoteid, remotename, cmdstr, festate, statebasehash, statediffhasharr, termopts, origtermopts, status, startpk, doneinfo, rtnstate, runout, rtnbasehash, rtndiffhasharr)
|
||||
VALUES (:sessionid,:screenid,:cmdid,:remoteownerid,:remoteid,:remotename,:cmdstr,:festate,:statebasehash,:statediffhasharr,:termopts,:origtermopts,:status,:startpk,:doneinfo,:rtnstate,:runout,:rtnbasehash,:rtndiffhasharr)
|
||||
INSERT INTO cmd ( screenid, cmdid, remoteownerid, remoteid, remotename, cmdstr, rawcmdstr, festate, statebasehash, statediffhasharr, termopts, origtermopts, status, startpk, doneinfo, rtnstate, runout, rtnbasehash, rtndiffhasharr)
|
||||
VALUES (:screenid,:cmdid,:remoteownerid,:remoteid,:remotename,:cmdstr,:rawcmdstr,:festate,:statebasehash,:statediffhasharr,:termopts,:origtermopts,:status,:startpk,:doneinfo,:rtnstate,:runout,:rtnbasehash,:rtndiffhasharr)
|
||||
`
|
||||
tx.NamedExec(query, cmdMap)
|
||||
}
|
||||
@ -795,11 +793,11 @@ INSERT INTO cmd ( sessionid, screenid, cmdid, remoteownerid, remoteid, remotena
|
||||
})
|
||||
}
|
||||
|
||||
func GetCmdById(ctx context.Context, sessionId string, cmdId string) (*CmdType, error) {
|
||||
func GetCmdByScreenId(ctx context.Context, screenId string, cmdId string) (*CmdType, error) {
|
||||
var cmd *CmdType
|
||||
err := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT * FROM cmd WHERE sessionid = ? AND cmdid = ?`
|
||||
cmd = GetMapGen[*CmdType](tx, query, sessionId, cmdId)
|
||||
query := `SELECT * FROM cmd WHERE screenid = ? AND cmdid = ?`
|
||||
cmd = GetMapGen[*CmdType](tx, query, screenId, cmdId)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@ -808,18 +806,6 @@ func GetCmdById(ctx context.Context, sessionId string, cmdId string) (*CmdType,
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func HasDoneInfo(ctx context.Context, ck base.CommandKey) (bool, error) {
|
||||
var found bool
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
found = tx.Exists(`SELECT sessionid FROM cmd WHERE sessionid = ? AND cmdid = ? AND doneinfo is NOT NULL`, ck.GetSessionId(), ck.GetCmdId())
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return false, txErr
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
func UpdateCmdDoneInfo(ctx context.Context, ck base.CommandKey, doneInfo *CmdDoneInfo) (*ModelUpdate, error) {
|
||||
if doneInfo == nil {
|
||||
return nil, fmt.Errorf("invalid cmddone packet")
|
||||
@ -829,10 +815,10 @@ func UpdateCmdDoneInfo(ctx context.Context, ck base.CommandKey, doneInfo *CmdDon
|
||||
}
|
||||
var rtnCmd *CmdType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `UPDATE cmd SET status = ?, doneinfo = ? WHERE sessionid = ? AND cmdid = ?`
|
||||
tx.Exec(query, CmdStatusDone, quickJson(doneInfo), ck.GetSessionId(), ck.GetCmdId())
|
||||
query := `UPDATE cmd SET status = ?, doneinfo = ? WHERE screenid = ? AND cmdid = ?`
|
||||
tx.Exec(query, CmdStatusDone, quickJson(doneInfo), ck.GetGroupId(), ck.GetCmdId())
|
||||
var err error
|
||||
rtnCmd, err = GetCmdById(tx.Context(), ck.GetSessionId(), ck.GetCmdId())
|
||||
rtnCmd, err = GetCmdByScreenId(tx.Context(), ck.GetGroupId(), ck.GetCmdId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -852,8 +838,8 @@ func UpdateCmdRtnState(ctx context.Context, ck base.CommandKey, statePtr ShellSt
|
||||
return fmt.Errorf("cannot update cmdrtnstate, empty ck")
|
||||
}
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `UPDATE cmd SET rtnbasehash = ?, rtndiffhasharr = ? WHERE sessionid = ? AND cmdid = ?`
|
||||
tx.Exec(query, statePtr.BaseHash, quickJsonArr(statePtr.DiffHashArr), ck.GetSessionId(), ck.GetCmdId())
|
||||
query := `UPDATE cmd SET rtnbasehash = ?, rtndiffhasharr = ? WHERE screenid = ? AND cmdid = ?`
|
||||
tx.Exec(query, statePtr.BaseHash, quickJsonArr(statePtr.DiffHashArr), ck.GetGroupId(), ck.GetCmdId())
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
@ -867,8 +853,8 @@ func AppendCmdErrorPk(ctx context.Context, errPk *packet.CmdErrorPacketType) err
|
||||
return fmt.Errorf("invalid cmderror packet (no ck)")
|
||||
}
|
||||
return WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `UPDATE cmd SET runout = json_insert(runout, '$[#]', ?) WHERE sessionid = ? AND cmdid = ?`
|
||||
tx.Exec(query, quickJson(errPk), errPk.CK.GetSessionId(), errPk.CK.GetCmdId())
|
||||
query := `UPDATE cmd SET runout = json_insert(runout, '$[#]', ?) WHERE screenid = ? AND cmdid = ?`
|
||||
tx.Exec(query, quickJson(errPk), errPk.CK.GetGroupId(), errPk.CK.GetCmdId())
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -899,8 +885,8 @@ func HangupRunningCmdsByRemoteId(ctx context.Context, remoteId string) error {
|
||||
|
||||
func HangupCmd(ctx context.Context, ck base.CommandKey) error {
|
||||
return WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `UPDATE cmd SET status = ? WHERE sessionid = ? AND cmdid = ?`
|
||||
tx.Exec(query, CmdStatusHangup, ck.GetSessionId(), ck.GetCmdId())
|
||||
query := `UPDATE cmd SET status = ? WHERE screenid = ? AND cmdid = ?`
|
||||
tx.Exec(query, CmdStatusHangup, ck.GetGroupId(), ck.GetCmdId())
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -949,40 +935,27 @@ func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (*
|
||||
return &ModelUpdate{ActiveSessionId: sessionId, Sessions: []*SessionType{bareSession}}, nil
|
||||
}
|
||||
|
||||
func cleanSessionCmds(ctx context.Context, sessionId string) error {
|
||||
// screen may not exist at this point (so don't query screen table)
|
||||
func cleanScreenCmds(ctx context.Context, screenId string) error {
|
||||
var removedCmds []string
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT cmdid FROM cmd WHERE sessionid = ? AND cmdid NOT IN (SELECT cmdid FROM line WHERE sessionid = ?)`
|
||||
removedCmds = tx.SelectStrings(query, sessionId, sessionId)
|
||||
query = `DELETE FROM cmd WHERE sessionid = ? AND cmdid NOT IN (SELECT cmdid FROM line WHERE sessionid = ?)`
|
||||
tx.Exec(query, sessionId, sessionId)
|
||||
query = `DELETE FROM bookmark_cmd WHERE sessionid = ? AND cmdid NOT IN (SELECT cmdid FROM cmd WHERE sessionid = ?)`
|
||||
tx.Exec(query, sessionId, sessionId)
|
||||
query := `SELECT cmdid FROM cmd WHERE screenid = ? AND cmdid NOT IN (SELECT cmdid FROM line WHERE screenid = ?)`
|
||||
removedCmds = tx.SelectStrings(query, screenId, screenId)
|
||||
query = `DELETE FROM cmd WHERE screenid = ? AND cmdid NOT IN (SELECT cmdid FROM line WHERE screenid = ?)`
|
||||
tx.Exec(query, screenId, screenId)
|
||||
query = `DELETE FROM bookmark_cmd WHERE screenid = ? AND cmdid NOT IN (SELECT cmdid FROM cmd WHERE screenid = ?)`
|
||||
tx.Exec(query, screenId, screenId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return txErr
|
||||
}
|
||||
for _, cmdId := range removedCmds {
|
||||
DeletePtyOutFile(ctx, sessionId, cmdId)
|
||||
DeletePtyOutFile(ctx, screenId, cmdId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CleanScreen(sessionId string, screenId string) {
|
||||
// NOTE: context.Background() here! (this could take a long time, and is async)
|
||||
txErr := WithTx(context.Background(), func(tx *TxWrap) error {
|
||||
query := `DELETE FROM history WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Exec(query, sessionId, screenId)
|
||||
query = `DELETE FROM line WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Exec(query, sessionId, screenId)
|
||||
return cleanSessionCmds(tx.Context(), sessionId)
|
||||
})
|
||||
if txErr != nil {
|
||||
fmt.Printf("ERROR cleaning session:%s screen:%s : %v\n", sessionId, screenId, txErr)
|
||||
}
|
||||
}
|
||||
|
||||
func ArchiveScreen(ctx context.Context, sessionId string, screenId string) (UpdatePacket, error) {
|
||||
var isActive bool
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
@ -1042,7 +1015,7 @@ func UnArchiveScreen(ctx context.Context, sessionId string, screenId string) err
|
||||
return txErr
|
||||
}
|
||||
|
||||
func DeleteScreen(ctx context.Context, screenId string) (UpdatePacket, error) {
|
||||
func PurgeScreen(ctx context.Context, screenId string, sessionDel bool) (UpdatePacket, error) {
|
||||
var sessionId string
|
||||
var isActive bool
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
@ -1050,30 +1023,39 @@ func DeleteScreen(ctx context.Context, screenId string) (UpdatePacket, error) {
|
||||
if !tx.Exists(query, screenId) {
|
||||
return fmt.Errorf("cannot purge screen (not found)")
|
||||
}
|
||||
query = `SELECT sessionid FROM screen WHERE screenid = ?`
|
||||
sessionId = tx.GetString(query, screenId)
|
||||
if sessionId == "" {
|
||||
return fmt.Errorf("cannot purge screen (no sessionid)")
|
||||
}
|
||||
query = `SELECT count(*) FROM screen WHERE sessionid = ? AND NOT archived`
|
||||
numScreens := tx.GetInt(query, sessionId)
|
||||
if numScreens <= 1 {
|
||||
return fmt.Errorf("cannot purge the last screen in a session")
|
||||
}
|
||||
isActive = tx.Exists(`SELECT sessionid FROM session WHERE sessionid = ? AND activescreenid = ?`, sessionId, screenId)
|
||||
if isActive {
|
||||
screenIds := tx.SelectStrings(`SELECT screenid FROM screen WHERE sessionid = ? AND NOT archived ORDER BY screenidx`, sessionId)
|
||||
nextId := getNextId(screenIds, screenId)
|
||||
tx.Exec(`UPDATE session SET activescreenid = ? WHERE sessionid = ?`, nextId, sessionId)
|
||||
if !sessionDel {
|
||||
query = `SELECT sessionid FROM screen WHERE screenid = ?`
|
||||
sessionId = tx.GetString(query, screenId)
|
||||
if sessionId == "" {
|
||||
return fmt.Errorf("cannot purge screen (no sessionid)")
|
||||
}
|
||||
query = `SELECT count(*) FROM screen WHERE sessionid = ? AND NOT archived`
|
||||
numScreens := tx.GetInt(query, sessionId)
|
||||
if numScreens <= 1 {
|
||||
return fmt.Errorf("cannot purge the last screen in a session")
|
||||
}
|
||||
isActive = tx.Exists(`SELECT sessionid FROM session WHERE sessionid = ? AND activescreenid = ?`, sessionId, screenId)
|
||||
if isActive {
|
||||
screenIds := tx.SelectStrings(`SELECT screenid FROM screen WHERE sessionid = ? AND NOT archived ORDER BY screenidx`, sessionId)
|
||||
nextId := getNextId(screenIds, screenId)
|
||||
tx.Exec(`UPDATE session SET activescreenid = ? WHERE sessionid = ?`, nextId, sessionId)
|
||||
}
|
||||
}
|
||||
query = `DELETE FROM screen WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
query = `DELETE FROM history WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
query = `DELETE FROM line WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
go CleanScreen(sessionId, screenId)
|
||||
go cleanScreenCmds(context.Background(), screenId)
|
||||
if sessionDel {
|
||||
return nil, nil
|
||||
}
|
||||
update := ModelUpdate{}
|
||||
update.Screens = []*ScreenType{&ScreenType{SessionId: sessionId, ScreenId: screenId, Remove: true}}
|
||||
if isActive {
|
||||
@ -1312,13 +1294,12 @@ func SetScreenName(ctx context.Context, sessionId string, screenId string, name
|
||||
|
||||
func ArchiveScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error) {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT sessionid FROM screen WHERE screenid = ?`
|
||||
sessionId := tx.GetString(query, screenId)
|
||||
if sessionId == "" {
|
||||
return fmt.Errorf("screen sessionid does not exist")
|
||||
query := `SELECT screenid FROM screen WHERE screenid = ?`
|
||||
if !tx.Exists(query, screenId) {
|
||||
return fmt.Errorf("screen does not exist")
|
||||
}
|
||||
query = `UPDATE line SET archived = 1 WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Exec(query, sessionId, screenId)
|
||||
query = `UPDATE line SET archived = 1 WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
@ -1333,19 +1314,13 @@ func ArchiveScreenLines(ctx context.Context, screenId string) (*ModelUpdate, err
|
||||
|
||||
func PurgeScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error) {
|
||||
var lineIds []string
|
||||
var sessionId string
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT sessionid FROM screen WHERE screenid = ?`
|
||||
sessionId = tx.GetString(query, screenId)
|
||||
if sessionId == "" {
|
||||
return fmt.Errorf("screen sessionid does not exist")
|
||||
}
|
||||
query = `SELECT lineid FROM line WHERE sessionid = ? AND screenid = ?`
|
||||
lineIds = tx.SelectStrings(query, sessionId, screenId)
|
||||
query = `DELETE FROM line WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Exec(query, sessionId, screenId)
|
||||
query = `DELETE FROM history WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Exec(query, sessionId, screenId)
|
||||
query := `SELECT lineid FROM line WHERE screenid = ?`
|
||||
lineIds = tx.SelectStrings(query, screenId)
|
||||
query = `DELETE FROM line WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
query = `DELETE FROM history WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
query = `UPDATE screen SET nextlinenum = 1 WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
return nil
|
||||
@ -1353,7 +1328,7 @@ func PurgeScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
go cleanSessionCmds(context.Background(), sessionId)
|
||||
go cleanScreenCmds(context.Background(), screenId)
|
||||
screen, err := GetScreenById(ctx, screenId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1364,21 +1339,20 @@ func PurgeScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error
|
||||
}
|
||||
for _, lineId := range lineIds {
|
||||
line := &LineType{
|
||||
SessionId: sessionId,
|
||||
ScreenId: screenId,
|
||||
LineId: lineId,
|
||||
Remove: true,
|
||||
ScreenId: screenId,
|
||||
LineId: lineId,
|
||||
Remove: true,
|
||||
}
|
||||
screenLines.Lines = append(screenLines.Lines, line)
|
||||
}
|
||||
return &ModelUpdate{Screens: []*ScreenType{screen}, ScreenLines: screenLines}, nil
|
||||
}
|
||||
|
||||
func GetRunningScreenCmds(ctx context.Context, sessionId string, screenId string) ([]*CmdType, error) {
|
||||
func GetRunningScreenCmds(ctx context.Context, screenId string) ([]*CmdType, error) {
|
||||
var rtn []*CmdType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT * from cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE sessionid = ? AND screenid = ?) AND status = ?`
|
||||
rtn = SelectMapsGen[*CmdType](tx, query, sessionId, screenId, CmdStatusRunning)
|
||||
query := `SELECT * from cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE screenid = ?) AND status = ?`
|
||||
rtn = SelectMapsGen[*CmdType](tx, query, screenId, CmdStatusRunning)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
@ -1387,10 +1361,10 @@ func GetRunningScreenCmds(ctx context.Context, sessionId string, screenId string
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func UpdateCmdTermOpts(ctx context.Context, sessionId string, cmdId string, termOpts TermOpts) error {
|
||||
func UpdateCmdTermOpts(ctx context.Context, screenId string, cmdId string, termOpts TermOpts) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `UPDATE cmd SET termopts = ? WHERE sessionid = ? AND cmdid = ?`
|
||||
tx.Exec(query, termOpts, sessionId, cmdId)
|
||||
query := `UPDATE cmd SET termopts = ? WHERE screenid = ? AND cmdid = ?`
|
||||
tx.Exec(query, termOpts, screenId, cmdId)
|
||||
return nil
|
||||
})
|
||||
return txErr
|
||||
@ -1417,25 +1391,24 @@ func ScreenReset(ctx context.Context, screenId string) ([]*RemoteInstance, error
|
||||
})
|
||||
}
|
||||
|
||||
func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error) {
|
||||
func PurgeSession(ctx context.Context, sessionId string) (UpdatePacket, error) {
|
||||
var newActiveSessionId string
|
||||
var screenIds []string
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT sessionid FROM session WHERE sessionid = ?`
|
||||
if !tx.Exists(query, sessionId) {
|
||||
return fmt.Errorf("session does not exist")
|
||||
}
|
||||
query = `SELECT screenid FROM screen WHERE sessionid = ?`
|
||||
screenIds = tx.SelectStrings(query, sessionId)
|
||||
for _, screenId := range screenIds {
|
||||
_, err := PurgeScreen(ctx, screenId, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error purging screen[%s]: %v", screenId, err)
|
||||
}
|
||||
}
|
||||
query = `DELETE FROM session WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM screen WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM history WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM line WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM cmd WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM bookmark_cmd WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
newActiveSessionId, _ = fixActiveSessionId(tx.Context())
|
||||
return nil
|
||||
})
|
||||
@ -1453,6 +1426,9 @@ func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error)
|
||||
}
|
||||
}
|
||||
update.Sessions = append(update.Sessions, &SessionType{SessionId: sessionId, Remove: true})
|
||||
for _, screenId := range screenIds {
|
||||
update.Screens = append(update.Screens, &ScreenType{ScreenId: screenId, Remove: true})
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
@ -1561,7 +1537,7 @@ func GetSessionStats(ctx context.Context, sessionId string) (*SessionStatsType,
|
||||
rtn.NumArchivedScreens = tx.GetInt(query, sessionId)
|
||||
query = `SELECT count(*) FROM line WHERE sessionid = ?`
|
||||
rtn.NumLines = tx.GetInt(query, sessionId)
|
||||
query = `SELECT count(*) FROM cmd WHERE sessionid = ?`
|
||||
query = `SELECT count(*) FROM cmd WHERE screenid IN (select screenid FROM screen WHERE sessionid = ?)`
|
||||
rtn.NumCmds = tx.GetInt(query, sessionId)
|
||||
return nil
|
||||
})
|
||||
@ -1686,11 +1662,11 @@ func UpdateScreen(ctx context.Context, screenId string, editMap map[string]inter
|
||||
return GetScreenById(ctx, screenId)
|
||||
}
|
||||
|
||||
func GetLineResolveItems(ctx context.Context, sessionId string, screenId string) ([]ResolveItem, error) {
|
||||
func GetLineResolveItems(ctx context.Context, screenId string) ([]ResolveItem, error) {
|
||||
var rtn []ResolveItem
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT lineid as id, linenum as num FROM line WHERE sessionid = ? AND screenid = ? ORDER BY linenum`
|
||||
tx.Select(&rtn, query, sessionId, screenId)
|
||||
query := `SELECT lineid as id, linenum as num FROM line WHERE screenid = ? ORDER BY linenum`
|
||||
tx.Select(&rtn, query, screenId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
@ -1699,39 +1675,24 @@ func GetLineResolveItems(ctx context.Context, sessionId string, screenId string)
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func UpdateScreensWithCmdFg(ctx context.Context, sessionId string, cmdId string) ([]*ScreenType, error) {
|
||||
var rtn []*ScreenType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid
|
||||
FROM screen s
|
||||
WHERE
|
||||
s.sessionid = ?
|
||||
AND s.focustype = 'cmd-fg'
|
||||
AND s.selectedline IN (SELECT linenum
|
||||
FROM line l
|
||||
WHERE l.sessionid = s.sessionid
|
||||
AND l.screenid = s.screenid
|
||||
AND l.cmdid = ?
|
||||
)`
|
||||
screenIds := tx.SelectStrings(query, sessionId, cmdId)
|
||||
if len(screenIds) == 0 {
|
||||
return nil
|
||||
func UpdateScreenWithCmdFg(ctx context.Context, screenId string, cmdId string) (*ScreenType, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ScreenType, error) {
|
||||
query := `SELECT screenid
|
||||
FROM screen s
|
||||
WHERE s.screenid = ? AND s.focustype = 'cmd-fg'
|
||||
AND s.selectedline IN (SELECT linenum FROM line l WHERE l.screenid = s.screenid AND l.cmdid = ?)
|
||||
`
|
||||
if !tx.Exists(query, screenId, cmdId) {
|
||||
return nil, nil
|
||||
}
|
||||
for _, screenId := range screenIds {
|
||||
editMap := make(map[string]interface{})
|
||||
editMap[ScreenField_Focus] = ScreenFocusInput
|
||||
screen, err := UpdateScreen(tx.Context(), screenId, editMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rtn = append(rtn, screen)
|
||||
editMap := make(map[string]interface{})
|
||||
editMap[ScreenField_Focus] = ScreenFocusInput
|
||||
screen, err := UpdateScreen(tx.Context(), screenId, editMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil
|
||||
return screen, nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func StoreStateBase(ctx context.Context, state *packet.ShellState) error {
|
||||
@ -1865,12 +1826,12 @@ func UpdateLineRenderer(ctx context.Context, lineId string, renderer string) err
|
||||
}
|
||||
|
||||
// can return nil, nil if line is not found
|
||||
func GetLineById(ctx context.Context, sessionId string, screenId string, lineId string) (*LineType, error) {
|
||||
func GetLineById(ctx context.Context, screenId string, lineId string) (*LineType, error) {
|
||||
var rtn *LineType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
var line LineType
|
||||
query := `SELECT * FROM line WHERE sessionid = ? AND screenid = ? AND lineid = ?`
|
||||
found := tx.Get(&line, query, sessionId, screenId, lineId)
|
||||
query := `SELECT * FROM line WHERE screenid = ? AND lineid = ?`
|
||||
found := tx.Get(&line, query, screenId, lineId)
|
||||
if found {
|
||||
rtn = &line
|
||||
}
|
||||
@ -1891,32 +1852,28 @@ func SetLineArchivedById(ctx context.Context, lineId string, archived bool) erro
|
||||
return txErr
|
||||
}
|
||||
|
||||
func purgeCmdById(ctx context.Context, sessionId string, cmdId string) error {
|
||||
func purgeCmdByScreenId(ctx context.Context, screenId string, cmdId string) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `DELETE FROM cmd WHERE sessionid = ? AND cmdid = ?`
|
||||
tx.Exec(query, sessionId, cmdId)
|
||||
return DeletePtyOutFile(tx.Context(), sessionId, cmdId)
|
||||
query := `DELETE FROM cmd WHERE screenid = ? AND cmdid = ?`
|
||||
tx.Exec(query, screenId, cmdId)
|
||||
return DeletePtyOutFile(tx.Context(), screenId, cmdId)
|
||||
})
|
||||
return txErr
|
||||
}
|
||||
|
||||
func PurgeLinesByIds(ctx context.Context, sessionId string, lineIds []string) error {
|
||||
func PurgeLinesByIds(ctx context.Context, screenId string, lineIds []string) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
for _, lineId := range lineIds {
|
||||
query := `SELECT cmdid FROM line WHERE sessionid = ? AND lineid = ?`
|
||||
cmdId := tx.GetString(query, sessionId, lineId)
|
||||
query = `DELETE FROM line WHERE sessionid = ? AND lineid = ?`
|
||||
tx.Exec(query, sessionId, lineId)
|
||||
query = `DELETE FROM history WHERE sessionid = ? AND lineid = ?`
|
||||
tx.Exec(query, sessionId, lineId)
|
||||
query := `SELECT cmdid FROM line WHERE screenid = ? AND lineid = ?`
|
||||
cmdId := tx.GetString(query, screenId, lineId)
|
||||
query = `DELETE FROM line WHERE screenid = ? AND lineid = ?`
|
||||
tx.Exec(query, screenId, lineId)
|
||||
query = `DELETE FROM history WHERE screenid = ? AND lineid = ?`
|
||||
tx.Exec(query, screenId, lineId)
|
||||
if cmdId != "" {
|
||||
query = `SELECT count(*) FROM line WHERE sessionid = ? AND cmdid = ?`
|
||||
cmdRefCount := tx.GetInt(query, sessionId, cmdId)
|
||||
if cmdRefCount == 0 {
|
||||
err := purgeCmdById(tx.Context(), sessionId, cmdId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := purgeCmdByScreenId(tx.Context(), screenId, cmdId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2084,7 +2041,7 @@ type bookmarkOrderType struct {
|
||||
|
||||
type bookmarkCmdType struct {
|
||||
BookmarkId string
|
||||
SessionId string
|
||||
ScreenId string
|
||||
CmdId string
|
||||
}
|
||||
|
||||
@ -2110,12 +2067,12 @@ func GetBookmarks(ctx context.Context, tag string) ([]*BookmarkType, error) {
|
||||
}
|
||||
}
|
||||
var cmds []bookmarkCmdType
|
||||
query = `SELECT bookmarkid, sessionid, cmdid FROM bookmark_cmd`
|
||||
query = `SELECT bookmarkid, screenid, cmdid FROM bookmark_cmd`
|
||||
tx.Select(&cmds, query)
|
||||
for _, cmd := range cmds {
|
||||
bm := bmMap[cmd.BookmarkId]
|
||||
if bm != nil {
|
||||
bm.Cmds = append(bm.Cmds, base.MakeCommandKey(cmd.SessionId, cmd.CmdId))
|
||||
bm.Cmds = append(bm.Cmds, base.MakeCommandKey(cmd.ScreenId, cmd.CmdId))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -2137,11 +2094,11 @@ func GetBookmarkById(ctx context.Context, bookmarkId string, tag string) (*Bookm
|
||||
query = `SELECT orderidx FROM bookmark_order WHERE bookmarkid = ? AND tag = ?`
|
||||
orderIdx := tx.GetInt(query, bookmarkId, tag)
|
||||
rtn.OrderIdx = int64(orderIdx)
|
||||
query = `SELECT bookmarkid, sessionid, cmdid FROM bookmark_cmd WHERE bookmarkid = ?`
|
||||
query = `SELECT bookmarkid, screenid, cmdid FROM bookmark_cmd WHERE bookmarkid = ?`
|
||||
var cmds []bookmarkCmdType
|
||||
tx.Select(&cmds, query, bookmarkId)
|
||||
for _, cmd := range cmds {
|
||||
rtn.Cmds = append(rtn.Cmds, base.MakeCommandKey(cmd.SessionId, cmd.CmdId))
|
||||
rtn.Cmds = append(rtn.Cmds, base.MakeCommandKey(cmd.ScreenId, cmd.CmdId))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -2188,13 +2145,13 @@ func InsertBookmark(ctx context.Context, bm *BookmarkType) error {
|
||||
query = `INSERT INTO bookmark_order (tag, bookmarkid, orderidx) VALUES (?, ?, ?)`
|
||||
tx.Exec(query, tag, bm.BookmarkId, maxOrder+1)
|
||||
}
|
||||
query = `INSERT INTO bookmark_cmd (bookmarkid, sessionid, cmdid) VALUES (?, ?, ?)`
|
||||
query = `INSERT INTO bookmark_cmd (bookmarkid, screenid, cmdid) VALUES (?, ?, ?)`
|
||||
for _, ck := range bm.Cmds {
|
||||
tx.Exec(query, bm.BookmarkId, ck.GetSessionId(), ck.GetCmdId())
|
||||
tx.Exec(query, bm.BookmarkId, ck.GetGroupId(), ck.GetCmdId())
|
||||
}
|
||||
query = `UPDATE line SET bookmarked = 1 WHERE sessionid = ? AND cmdid = ?`
|
||||
query = `UPDATE line SET bookmarked = 1 WHERE screenid = ? AND cmdid = ?`
|
||||
for _, ck := range bm.Cmds {
|
||||
tx.Exec(query, ck.GetSessionId(), ck.GetCmdId())
|
||||
tx.Exec(query, ck.GetGroupId(), ck.GetCmdId())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -2248,7 +2205,7 @@ func DeleteBookmark(ctx context.Context, bookmarkId string) error {
|
||||
tx.Exec(query, bookmarkId)
|
||||
query = `DELETE FROM bookmark_order WHERE bookmarkid = ?`
|
||||
tx.Exec(query, bookmarkId)
|
||||
query = `UPDATE line SET bookmarked = 0 WHERE bookmarked AND cmdid <> '' AND (sessionid||cmdid) IN (SELECT sessionid||cmdid FROM bookmark_cmd WHERE bookmarkid = ?) `
|
||||
query = `UPDATE line SET bookmarked = 0 WHERE bookmarked AND cmdid <> '' AND (screenid||cmdid) IN (SELECT screenid||cmdid FROM bookmark_cmd WHERE bookmarkid = ?) `
|
||||
tx.Exec(query, bookmarkId)
|
||||
query = `DELETE FROM bookmark_cmd WHERE bookmarkid = ?`
|
||||
tx.Exec(query, bookmarkId)
|
||||
@ -2377,7 +2334,7 @@ func PurgeHistoryByIds(ctx context.Context, historyIds []string) ([]*HistoryItem
|
||||
tx.Exec(query, quickJsonArr(historyIds))
|
||||
for _, hitem := range rtn {
|
||||
if hitem.LineId != "" {
|
||||
err := PurgeLinesByIds(tx.Context(), hitem.SessionId, []string{hitem.LineId})
|
||||
err := PurgeLinesByIds(tx.Context(), hitem.ScreenId, []string{hitem.LineId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -2386,10 +2343,3 @@ func PurgeHistoryByIds(ctx context.Context, historyIds []string) ([]*HistoryItem
|
||||
return rtn, nil
|
||||
})
|
||||
}
|
||||
|
||||
func GetScreenIdFromCmd(ctx context.Context, sessionId string, cmdId string) (string, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (string, error) {
|
||||
query := `SELECT screenid FROM cmd WHERE sessionid = ? AND cmdid = ?`
|
||||
return tx.GetString(query, sessionId, cmdId), nil
|
||||
})
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
"github.com/scripthaus-dev/sh2-server/pkg/scbase"
|
||||
)
|
||||
|
||||
func CreateCmdPtyFile(ctx context.Context, sessionId string, cmdId string, maxSize int64) error {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(sessionId, cmdId)
|
||||
func CreateCmdPtyFile(ctx context.Context, screenId string, cmdId string, maxSize int64) error {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(screenId, cmdId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -24,22 +24,22 @@ func CreateCmdPtyFile(ctx context.Context, sessionId string, cmdId string, maxSi
|
||||
return f.Close()
|
||||
}
|
||||
|
||||
func StatCmdPtyFile(ctx context.Context, sessionId string, cmdId string) (*cirfile.Stat, error) {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(sessionId, cmdId)
|
||||
func StatCmdPtyFile(ctx context.Context, screenId string, cmdId string) (*cirfile.Stat, error) {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(screenId, cmdId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cirfile.StatCirFile(ctx, ptyOutFileName)
|
||||
}
|
||||
|
||||
func AppendToCmdPtyBlob(ctx context.Context, sessionId string, screenId string, cmdId string, data []byte, pos int64) (*PtyDataUpdate, error) {
|
||||
func AppendToCmdPtyBlob(ctx context.Context, screenId string, cmdId string, data []byte, pos int64) (*PtyDataUpdate, error) {
|
||||
if screenId == "" {
|
||||
return nil, fmt.Errorf("cannot append to PtyBlob, screenid is not set")
|
||||
}
|
||||
if pos < 0 {
|
||||
return nil, fmt.Errorf("invalid seek pos '%d' in AppendToCmdPtyBlob", pos)
|
||||
}
|
||||
ptyOutFileName, err := scbase.PtyOutFile(sessionId, cmdId)
|
||||
ptyOutFileName, err := scbase.PtyOutFile(screenId, cmdId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -54,7 +54,6 @@ func AppendToCmdPtyBlob(ctx context.Context, sessionId string, screenId string,
|
||||
}
|
||||
data64 := base64.StdEncoding.EncodeToString(data)
|
||||
update := &PtyDataUpdate{
|
||||
SessionId: sessionId,
|
||||
ScreenId: screenId,
|
||||
CmdId: cmdId,
|
||||
PtyPos: pos,
|
||||
@ -65,8 +64,8 @@ func AppendToCmdPtyBlob(ctx context.Context, sessionId string, screenId string,
|
||||
}
|
||||
|
||||
// returns (offset, data, err)
|
||||
func ReadFullPtyOutFile(ctx context.Context, sessionId string, cmdId string) (int64, []byte, error) {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(sessionId, cmdId)
|
||||
func ReadFullPtyOutFile(ctx context.Context, screenId string, cmdId string) (int64, []byte, error) {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(screenId, cmdId)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
@ -141,8 +140,8 @@ func FullSessionDiskSize() (map[string]SessionDiskSizeType, error) {
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func DeletePtyOutFile(ctx context.Context, sessionId string, cmdId string) error {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(sessionId, cmdId)
|
||||
func DeletePtyOutFile(ctx context.Context, screenId string, cmdId string) error {
|
||||
ptyOutFileName, err := scbase.PtyOutFile(screenId, cmdId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -157,3 +156,12 @@ func DeleteSessionDir(ctx context.Context, sessionId string) error {
|
||||
fmt.Printf("remove-all %s\n", sessionDir)
|
||||
return os.RemoveAll(sessionDir)
|
||||
}
|
||||
|
||||
func DeleteScreenDir(ctx context.Context, screenId string) error {
|
||||
screenDir, err := scbase.EnsureScreenDir(screenId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting screendir: %w", err)
|
||||
}
|
||||
fmt.Printf("remove-all %s\n", screenDir)
|
||||
return os.RemoveAll(screenDir)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
)
|
||||
|
||||
const MaxMigration = 12
|
||||
const MaxMigration = 13
|
||||
const MigratePrimaryScreenVersion = 9
|
||||
|
||||
func MakeMigrate() (*migrate.Migrate, error) {
|
||||
@ -81,7 +81,9 @@ func MigrateUp() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating database backup: %v", err)
|
||||
}
|
||||
startTime := time.Now()
|
||||
err = m.Migrate(MaxMigration)
|
||||
log.Printf("[db] migration took %v\n", time.Since(startTime))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -76,6 +76,11 @@ const (
|
||||
ScreenFocusCmdFg = "cmd-fg"
|
||||
)
|
||||
|
||||
const (
|
||||
CmdStoreTypeSession = "session"
|
||||
CmdStoreTypeScreen = "screen"
|
||||
)
|
||||
|
||||
const MaxTzNameLen = 50
|
||||
|
||||
var globalDBLock = &sync.Mutex{}
|
||||
@ -187,17 +192,26 @@ type FeOptsType struct {
|
||||
TermFontSize int `json:"termfontsize,omitempty"`
|
||||
}
|
||||
|
||||
type ClientMigrationData struct {
|
||||
MigrationType string `json:"migrationtype"`
|
||||
MigrationPos int `json:"migrationpos"`
|
||||
MigrationTotal int `json:"migrationtotal"`
|
||||
MigrationDone bool `json:"migrationdone"`
|
||||
}
|
||||
|
||||
type ClientData struct {
|
||||
ClientId string `json:"clientid"`
|
||||
UserId string `json:"userid"`
|
||||
UserPrivateKeyBytes []byte `json:"-"`
|
||||
UserPublicKeyBytes []byte `json:"-"`
|
||||
UserPrivateKey *ecdsa.PrivateKey `json:"-" dbmap:"-"`
|
||||
UserPublicKey *ecdsa.PublicKey `json:"-" dbmap:"-"`
|
||||
ActiveSessionId string `json:"activesessionid"`
|
||||
WinSize ClientWinSizeType `json:"winsize"`
|
||||
ClientOpts ClientOptsType `json:"clientopts"`
|
||||
FeOpts FeOptsType `json:"feopts"`
|
||||
ClientId string `json:"clientid"`
|
||||
UserId string `json:"userid"`
|
||||
UserPrivateKeyBytes []byte `json:"-"`
|
||||
UserPublicKeyBytes []byte `json:"-"`
|
||||
UserPrivateKey *ecdsa.PrivateKey `json:"-" dbmap:"-"`
|
||||
UserPublicKey *ecdsa.PublicKey `json:"-" dbmap:"-"`
|
||||
ActiveSessionId string `json:"activesessionid"`
|
||||
WinSize ClientWinSizeType `json:"winsize"`
|
||||
ClientOpts ClientOptsType `json:"clientopts"`
|
||||
FeOpts FeOptsType `json:"feopts"`
|
||||
CmdStoreType string `json:"cmdstoretype"`
|
||||
Migration *ClientMigrationData `json:"migration,omitempty" dbmap:"-"`
|
||||
}
|
||||
|
||||
func (ClientData) UseDBMap() {}
|
||||
@ -641,7 +655,6 @@ func (ri *RemoteInstance) ToMap() map[string]interface{} {
|
||||
}
|
||||
|
||||
type LineType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
ScreenId string `json:"screenid"`
|
||||
UserId string `json:"userid"`
|
||||
LineId string `json:"lineid"`
|
||||
@ -657,7 +670,6 @@ type LineType struct {
|
||||
ContentHeight int64 `json:"contentheight,omitempty"`
|
||||
Star bool `json:"star,omitempty"`
|
||||
Bookmarked bool `json:"bookmarked,omitempty"`
|
||||
Pinned bool `json:"pinned,omitempty"`
|
||||
Archived bool `json:"archived,omitempty"`
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
@ -832,12 +844,18 @@ type CmdDoneInfo struct {
|
||||
DurationMs int64 `json:"durationms"`
|
||||
}
|
||||
|
||||
type CmdMapType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
ScreenId string `json:"screenid"`
|
||||
CmdId string `json:"cmdid"`
|
||||
}
|
||||
|
||||
type CmdType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
ScreenId string `json:"screenid"`
|
||||
CmdId string `json:"cmdid"`
|
||||
Remote RemotePtrType `json:"remote"`
|
||||
CmdStr string `json:"cmdstr"`
|
||||
RawCmdStr string `json:"rawcmdstr"`
|
||||
FeState FeStateType `json:"festate"`
|
||||
StatePtr ShellStatePtr `json:"state"`
|
||||
TermOpts TermOpts `json:"termopts"`
|
||||
@ -894,13 +912,13 @@ func (r *RemoteType) FromMap(m map[string]interface{}) bool {
|
||||
|
||||
func (cmd *CmdType) ToMap() map[string]interface{} {
|
||||
rtn := make(map[string]interface{})
|
||||
rtn["sessionid"] = cmd.SessionId
|
||||
rtn["screenid"] = cmd.ScreenId
|
||||
rtn["cmdid"] = cmd.CmdId
|
||||
rtn["remoteownerid"] = cmd.Remote.OwnerId
|
||||
rtn["remoteid"] = cmd.Remote.RemoteId
|
||||
rtn["remotename"] = cmd.Remote.Name
|
||||
rtn["cmdstr"] = cmd.CmdStr
|
||||
rtn["rawcmdstr"] = cmd.RawCmdStr
|
||||
rtn["festate"] = quickJson(cmd.FeState)
|
||||
rtn["statebasehash"] = cmd.StatePtr.BaseHash
|
||||
rtn["statediffhasharr"] = quickJsonArr(cmd.StatePtr.DiffHashArr)
|
||||
@ -917,13 +935,13 @@ func (cmd *CmdType) ToMap() map[string]interface{} {
|
||||
}
|
||||
|
||||
func (cmd *CmdType) FromMap(m map[string]interface{}) bool {
|
||||
quickSetStr(&cmd.SessionId, m, "sessionid")
|
||||
quickSetStr(&cmd.ScreenId, m, "screenid")
|
||||
quickSetStr(&cmd.CmdId, m, "cmdid")
|
||||
quickSetStr(&cmd.Remote.OwnerId, m, "remoteownerid")
|
||||
quickSetStr(&cmd.Remote.RemoteId, m, "remoteid")
|
||||
quickSetStr(&cmd.Remote.Name, m, "remotename")
|
||||
quickSetStr(&cmd.CmdStr, m, "cmdstr")
|
||||
quickSetStr(&cmd.RawCmdStr, m, "rawcmdstr")
|
||||
quickSetJson(&cmd.FeState, m, "festate")
|
||||
quickSetStr(&cmd.StatePtr.BaseHash, m, "statebasehash")
|
||||
quickSetJsonArr(&cmd.StatePtr.DiffHashArr, m, "statediffhasharr")
|
||||
@ -939,9 +957,8 @@ func (cmd *CmdType) FromMap(m map[string]interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func makeNewLineCmd(sessionId string, screenId string, userId string, cmdId string, renderer string) *LineType {
|
||||
func makeNewLineCmd(screenId string, userId string, cmdId string, renderer string) *LineType {
|
||||
rtn := &LineType{}
|
||||
rtn.SessionId = sessionId
|
||||
rtn.ScreenId = screenId
|
||||
rtn.UserId = userId
|
||||
rtn.LineId = scbase.GenPromptUUID()
|
||||
@ -954,9 +971,8 @@ func makeNewLineCmd(sessionId string, screenId string, userId string, cmdId stri
|
||||
return rtn
|
||||
}
|
||||
|
||||
func makeNewLineText(sessionId string, screenId string, userId string, text string) *LineType {
|
||||
func makeNewLineText(screenId string, userId string, text string) *LineType {
|
||||
rtn := &LineType{}
|
||||
rtn.SessionId = sessionId
|
||||
rtn.ScreenId = screenId
|
||||
rtn.UserId = userId
|
||||
rtn.LineId = scbase.GenPromptUUID()
|
||||
@ -968,8 +984,8 @@ func makeNewLineText(sessionId string, screenId string, userId string, text stri
|
||||
return rtn
|
||||
}
|
||||
|
||||
func AddCommentLine(ctx context.Context, sessionId string, screenId string, userId string, commentText string) (*LineType, error) {
|
||||
rtnLine := makeNewLineText(sessionId, screenId, userId, commentText)
|
||||
func AddCommentLine(ctx context.Context, screenId string, userId string, commentText string) (*LineType, error) {
|
||||
rtnLine := makeNewLineText(screenId, userId, commentText)
|
||||
err := InsertLine(ctx, rtnLine, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -977,8 +993,8 @@ func AddCommentLine(ctx context.Context, sessionId string, screenId string, user
|
||||
return rtnLine, nil
|
||||
}
|
||||
|
||||
func AddCmdLine(ctx context.Context, sessionId string, screenId string, userId string, cmd *CmdType, renderer string) (*LineType, error) {
|
||||
rtnLine := makeNewLineCmd(sessionId, screenId, userId, cmd.CmdId, renderer)
|
||||
func AddCmdLine(ctx context.Context, screenId string, userId string, cmd *CmdType, renderer string) (*LineType, error) {
|
||||
rtnLine := makeNewLineCmd(screenId, userId, cmd.CmdId, renderer)
|
||||
err := InsertLine(ctx, rtnLine, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1085,6 +1101,7 @@ func createClientData(tx *TxWrap) error {
|
||||
UserPublicKeyBytes: pubBytes,
|
||||
ActiveSessionId: "",
|
||||
WinSize: ClientWinSizeType{},
|
||||
CmdStoreType: CmdStoreTypeScreen,
|
||||
}
|
||||
query := `INSERT INTO client ( clientid, userid, activesessionid, userpublickeybytes, userprivatekeybytes, winsize)
|
||||
VALUES (:clientid,:userid,:activesessionid,:userpublickeybytes,:userprivatekeybytes,:winsize)`
|
||||
@ -1137,6 +1154,28 @@ func EnsureClientData(ctx context.Context) (*ClientData, error) {
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func GetCmdMigrationInfo(ctx context.Context) (*ClientMigrationData, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ClientMigrationData, error) {
|
||||
cdata := GetMappable[*ClientData](tx, `SELECT * FROM client`)
|
||||
if cdata == nil {
|
||||
return nil, fmt.Errorf("no client data found")
|
||||
}
|
||||
if cdata.CmdStoreType == "session" {
|
||||
total := tx.GetInt(`SELECT count(*) FROM cmd`)
|
||||
posInv := tx.GetInt(`SELECT count(*) FROM cmd_migrate`)
|
||||
mdata := &ClientMigrationData{
|
||||
MigrationType: "cmdscreen",
|
||||
MigrationPos: total - posInv,
|
||||
MigrationTotal: total,
|
||||
MigrationDone: false,
|
||||
}
|
||||
return mdata, nil
|
||||
}
|
||||
// no migration info
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
func SetClientOpts(ctx context.Context, clientOpts ClientOptsType) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `UPDATE client SET clientopts = ?`
|
||||
@ -1145,3 +1184,93 @@ func SetClientOpts(ctx context.Context, clientOpts ClientOptsType) error {
|
||||
})
|
||||
return txErr
|
||||
}
|
||||
|
||||
type cmdMigrationType struct {
|
||||
SessionId string
|
||||
ScreenId string
|
||||
CmdId string
|
||||
}
|
||||
|
||||
func getSliceChunk[T any](slice []T, chunkSize int) ([]T, []T) {
|
||||
if chunkSize >= len(slice) {
|
||||
return slice, nil
|
||||
}
|
||||
return slice[0:chunkSize], slice[chunkSize:]
|
||||
}
|
||||
|
||||
func processChunk(ctx context.Context, mchunk []cmdMigrationType) error {
|
||||
for _, mig := range mchunk {
|
||||
newFile, err := scbase.PtyOutFile(mig.ScreenId, mig.CmdId)
|
||||
if err != nil {
|
||||
log.Printf("ptyoutfile error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
oldFile, err := scbase.PtyOutFile_Sessions(mig.SessionId, mig.CmdId)
|
||||
if err != nil {
|
||||
log.Printf("ptyoutfile_sessions error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
err = os.Rename(oldFile, newFile)
|
||||
if err != nil {
|
||||
log.Printf("error renaming %s => %s: %v\n", oldFile, newFile, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
for _, mig := range mchunk {
|
||||
query := `DELETE FROM cmd_migrate WHERE cmdid = ?`
|
||||
tx.Exec(query, mig.CmdId)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return txErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunCmdScreenMigration() {
|
||||
ctx := context.Background()
|
||||
startTime := time.Now()
|
||||
mdata, err := GetCmdMigrationInfo(ctx)
|
||||
if err != nil {
|
||||
log.Printf("[prompt] error trying to run cmd migration: %v\n", err)
|
||||
return
|
||||
}
|
||||
if mdata == nil || mdata.MigrationType != "cmdscreen" {
|
||||
return
|
||||
}
|
||||
var migrations []cmdMigrationType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
tx.Select(&migrations, `SELECT * FROM cmd_migrate`)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
log.Printf("[prompt] error trying to get cmd migrations: %v\n", txErr)
|
||||
return
|
||||
}
|
||||
log.Printf("[db] got %d cmd migrations\n", len(migrations))
|
||||
for len(migrations) > 0 {
|
||||
var mchunk []cmdMigrationType
|
||||
mchunk, migrations = getSliceChunk(migrations, 5)
|
||||
err = processChunk(ctx, mchunk)
|
||||
if err != nil {
|
||||
log.Printf("[prompt] cmd migration failed on chunk: %v\n%#v\n", err, mchunk)
|
||||
return
|
||||
}
|
||||
}
|
||||
err = os.RemoveAll(scbase.GetSessionsDir())
|
||||
if err != nil {
|
||||
log.Printf("[db] cannot remove old sessions dir %s: %v\n", scbase.GetSessionsDir(), err)
|
||||
}
|
||||
txErr = WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `UPDATE client SET cmdstoretype = 'screen'`
|
||||
tx.Exec(query)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
log.Printf("[db] cannot change client cmdstoretype: %v\n", err)
|
||||
}
|
||||
log.Printf("[db] cmd screen migration done: %v\n", time.Since(startTime))
|
||||
return
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ type UpdatePacket interface {
|
||||
}
|
||||
|
||||
type PtyDataUpdate struct {
|
||||
SessionId string `json:"sessionid,omitempty"`
|
||||
ScreenId string `json:"screenid,omitempty"`
|
||||
CmdId string `json:"cmdid,omitempty"`
|
||||
RemoteId string `json:"remoteid,omitempty"`
|
||||
@ -123,16 +122,16 @@ type CmdLineType struct {
|
||||
}
|
||||
|
||||
type UpdateChannel struct {
|
||||
SessionId string
|
||||
ClientId string
|
||||
Ch chan interface{}
|
||||
ScreenId string
|
||||
ClientId string
|
||||
Ch chan interface{}
|
||||
}
|
||||
|
||||
func (uch UpdateChannel) Match(sessionId string) bool {
|
||||
if sessionId == "" {
|
||||
func (uch UpdateChannel) Match(screenId string) bool {
|
||||
if screenId == "" {
|
||||
return true
|
||||
}
|
||||
return sessionId == uch.SessionId
|
||||
return screenId == uch.ScreenId
|
||||
}
|
||||
|
||||
type UpdateBus struct {
|
||||
@ -148,19 +147,19 @@ func MakeUpdateBus() *UpdateBus {
|
||||
}
|
||||
|
||||
// always returns a new channel
|
||||
func (bus *UpdateBus) RegisterChannel(clientId string, sessionId string) chan interface{} {
|
||||
func (bus *UpdateBus) RegisterChannel(clientId string, screenId string) chan interface{} {
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
uch, found := bus.Channels[clientId]
|
||||
if found {
|
||||
close(uch.Ch)
|
||||
uch.SessionId = sessionId
|
||||
uch.ScreenId = screenId
|
||||
uch.Ch = make(chan interface{}, UpdateChSize)
|
||||
} else {
|
||||
uch = UpdateChannel{
|
||||
ClientId: clientId,
|
||||
SessionId: sessionId,
|
||||
Ch: make(chan interface{}, UpdateChSize),
|
||||
ClientId: clientId,
|
||||
ScreenId: screenId,
|
||||
Ch: make(chan interface{}, UpdateChSize),
|
||||
}
|
||||
}
|
||||
bus.Channels[clientId] = uch
|
||||
@ -177,11 +176,24 @@ func (bus *UpdateBus) UnregisterChannel(clientId string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (bus *UpdateBus) SendUpdate(sessionId string, update interface{}) {
|
||||
func (bus *UpdateBus) SendUpdate(update interface{}) {
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
for _, uch := range bus.Channels {
|
||||
if uch.Match(sessionId) {
|
||||
select {
|
||||
case uch.Ch <- update:
|
||||
|
||||
default:
|
||||
log.Printf("[error] dropped update on updatebus uch clientid=%s\n", uch.ClientId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (bus *UpdateBus) SendScreenUpdate(screenId string, update interface{}) {
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
for _, uch := range bus.Channels {
|
||||
if uch.Match(screenId) {
|
||||
select {
|
||||
case uch.Ch <- update:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user