From 5645a0148258a9d9dfdce4c1a65f590bfe62efa8 Mon Sep 17 00:00:00 2001 From: sawka Date: Sun, 25 Dec 2022 13:03:11 -0800 Subject: [PATCH] archived not closed --- db/migrations/000001_init.up.sql | 4 +- db/schema.sql | 5 +- pkg/cmdrunner/cmdrunner.go | 14 ++++- pkg/cmdrunner/resolver.go | 4 +- pkg/sstore/dbops.go | 94 ++++++++++++++++++++++---------- pkg/sstore/sstore.go | 18 +++--- 6 files changed, 92 insertions(+), 47 deletions(-) diff --git a/db/migrations/000001_init.up.sql b/db/migrations/000001_init.up.sql index bdaa2dd2..25bc0f07 100644 --- a/db/migrations/000001_init.up.sql +++ b/db/migrations/000001_init.up.sql @@ -13,7 +13,7 @@ CREATE TABLE session ( sessionidx int NOT NULL, activescreenid varchar(36) NOT NULL, notifynum int NOT NULL, - closed boolean NOT NULL, + archived boolean NOT NULL, ownerid varchar(36) NOT NULL, sharemode varchar(12) NOT NULL, accesskey varchar(36) NOT NULL @@ -43,7 +43,7 @@ CREATE TABLE screen ( ownerid varchar(36) NOT NULL, sharemode varchar(12) NOT NULL, incognito boolean NOT NULL, - closed boolean NOT NULL, + archived boolean NOT NULL, PRIMARY KEY (sessionid, screenid) ); diff --git a/db/schema.sql b/db/schema.sql index 4f2f532c..bb477b14 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -14,7 +14,7 @@ CREATE TABLE session ( sessionidx int NOT NULL, activescreenid varchar(36) NOT NULL, notifynum int NOT NULL, - closed boolean NOT NULL, + archived boolean NOT NULL, ownerid varchar(36) NOT NULL, sharemode varchar(12) NOT NULL, accesskey varchar(36) NOT NULL @@ -42,7 +42,7 @@ CREATE TABLE screen ( ownerid varchar(36) NOT NULL, sharemode varchar(12) NOT NULL, incognito boolean NOT NULL, - closed boolean NOT NULL, + archived boolean NOT NULL, PRIMARY KEY (sessionid, screenid) ); CREATE TABLE screen_window ( @@ -95,6 +95,7 @@ CREATE TABLE line ( ephemeral boolean NOT NULL, contentheight int NOT NULL, star int NOT NULL, + hidden boolean NOT NULL, PRIMARY KEY (sessionid, windowid, lineid) ); CREATE TABLE remote ( diff --git a/pkg/cmdrunner/cmdrunner.go b/pkg/cmdrunner/cmdrunner.go index e76d92ff..59161907 100644 --- a/pkg/cmdrunner/cmdrunner.go +++ b/pkg/cmdrunner/cmdrunner.go @@ -120,6 +120,8 @@ func init() { registerCmdAlias("session:new", SessionOpenCommand) registerCmdFn("session:set", SessionSetCommand) registerCmdFn("session:delete", SessionDeleteCommand) + registerCmdFn("session:archive", SessionArchiveCommand) + registerCmdFn("session:showall", SessionShowAllCommand) registerCmdFn("screen", ScreenCommand) registerCmdFn("screen:close", ScreenCloseCommand) @@ -954,14 +956,14 @@ func ScreenShowAllCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) var buf bytes.Buffer for _, screen := range screenArr { var closedStr string - if screen.Closed { + if screen.Archived { closedStr = " (closed)" } screenIdxStr := "-" if screen.ScreenIdx != 0 { screenIdxStr = strconv.Itoa(int(screen.ScreenIdx)) } - outStr := fmt.Sprintf("%s %-30s %s\n", screen.ScreenId, screen.Name+closedStr, screenIdxStr) + outStr := fmt.Sprintf("%-30s %s %s\n", screen.Name+closedStr, screen.ScreenId, screenIdxStr) buf.WriteString(outStr) } return sstore.ModelUpdate{ @@ -2067,3 +2069,11 @@ func resolveSetArg(argName string) (bool, string, string) { } return true, scopeName, varName } + +func SessionShowAllCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + return nil, nil +} + +func SessionArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + return nil, nil +} diff --git a/pkg/cmdrunner/resolver.go b/pkg/cmdrunner/resolver.go index 7a5edaf0..c2f1c375 100644 --- a/pkg/cmdrunner/resolver.go +++ b/pkg/cmdrunner/resolver.go @@ -58,7 +58,7 @@ func sessionsToResolveItems(sessions []*sstore.SessionType) []ResolveItem { } rtn := make([]ResolveItem, len(sessions)) for idx, session := range sessions { - rtn[idx] = ResolveItem{Name: session.Name, Id: session.SessionId, Hidden: session.Closed} + rtn[idx] = ResolveItem{Name: session.Name, Id: session.SessionId, Hidden: session.Archived} } return rtn } @@ -69,7 +69,7 @@ func screensToResolveItems(screens []*sstore.ScreenType) []ResolveItem { } rtn := make([]ResolveItem, len(screens)) for idx, screen := range screens { - rtn[idx] = ResolveItem{Name: screen.Name, Id: screen.ScreenId, Hidden: screen.Closed} + rtn[idx] = ResolveItem{Name: screen.Name, Id: screen.ScreenId, Hidden: screen.Archived} } return rtn } diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go index fa855d61..1ce6b659 100644 --- a/pkg/sstore/dbops.go +++ b/pkg/sstore/dbops.go @@ -233,7 +233,7 @@ func GetHistoryItems(ctx context.Context, sessionId string, windowId string, opt return rtn, nil } -// includes closed sessions +// includes archived sessions func GetBareSessions(ctx context.Context) ([]*SessionType, error) { var rtn []*SessionType err := WithTx(ctx, func(tx *TxWrap) error { @@ -247,10 +247,11 @@ func GetBareSessions(ctx context.Context) ([]*SessionType, error) { return rtn, nil } +// does not include archived func GetAllSessionIds(ctx context.Context) ([]string, error) { var rtn []string txErr := WithTx(ctx, func(tx *TxWrap) error { - query := `SELECT sessionid from session WHERE NOT closed ORDER by sessionidx` + query := `SELECT sessionid from session WHERE NOT archived ORDER by sessionidx` rtn = tx.SelectStrings(query) return nil }) @@ -288,7 +289,7 @@ func GetAllSessions(ctx context.Context) (*ModelUpdate, error) { session.Full = true } var screens []*ScreenType - query = `SELECT * FROM screen WHERE NOT closed ORDER BY screenidx` + query = `SELECT * FROM screen WHERE NOT archived ORDER BY screenidx` tx.SelectWrap(&screens, query) screenMap := make(map[string][]*ScreenType) for _, screen := range screens { @@ -353,7 +354,7 @@ func GetWindowById(ctx context.Context, sessionId string, windowId string) (*Win return rtnWindow, err } -// includes closed screens +// includes archived screens func GetSessionScreens(ctx context.Context, sessionId string) ([]*ScreenType, error) { var rtn []*ScreenType txErr := WithTx(ctx, func(tx *TxWrap) error { @@ -367,7 +368,7 @@ func GetSessionScreens(ctx context.Context, sessionId string) ([]*ScreenType, er func GetAllSessionScreens(ctx context.Context, sessionId string) ([]*ScreenType, error) { var rtn []*ScreenType txErr := WithTx(ctx, func(tx *TxWrap) error { - query := `SELECT * FROM screen WHERE sessionid = ? ORDER BY closed, screenidx` + query := `SELECT * FROM screen WHERE sessionid = ? ORDER BY archived, screenidx` tx.SelectWrap(&rtn, query, sessionId) return nil }) @@ -417,8 +418,8 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo names := tx.SelectStrings(`SELECT name FROM session`) sessionName = fmtUniqueName(sessionName, "session-%d", len(names)+1, names) maxSessionIdx := tx.GetInt(`SELECT COALESCE(max(sessionidx), 0) FROM session`) - query := `INSERT INTO session (sessionid, name, activescreenid, sessionidx, notifynum, closed, ownerid, sharemode, accesskey) - VALUES (?, ?, '', ?, ?, 0, '', 'local', '')` + query := `INSERT INTO session (sessionid, name, activescreenid, sessionidx, notifynum, archived, ownerid, sharemode, accesskey) + VALUES (?, ?, '', ?, ?, 0, '', 'local', '')` tx.ExecWrap(query, newSessionId, sessionName, maxSessionIdx+1, 0) _, err := InsertScreen(tx.Context(), newSessionId, "", true) if err != nil { @@ -448,7 +449,7 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo func SetActiveSessionId(ctx context.Context, sessionId string) error { txErr := WithTx(ctx, func(tx *TxWrap) error { - query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT closed` + query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT archived` if !tx.Exists(query, sessionId) { return fmt.Errorf("cannot switch to session, not found") } @@ -514,7 +515,7 @@ func fmtUniqueName(name string, defaultFmtStr string, startIdx int, strs []strin func InsertScreen(ctx context.Context, sessionId string, origScreenName string, activate bool) (UpdatePacket, error) { var newScreenId string txErr := WithTx(ctx, func(tx *TxWrap) error { - query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT closed` + query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT archived` if !tx.Exists(query, sessionId) { return fmt.Errorf("cannot create screen, no session found") } @@ -523,11 +524,11 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string, return fmt.Errorf("cannot create screen, no local remote found") } newWindowId := txCreateWindow(tx, sessionId, RemotePtrType{RemoteId: remoteId}) - maxScreenIdx := tx.GetInt(`SELECT COALESCE(max(screenidx), 0) FROM screen WHERE sessionid = ? AND NOT closed`, sessionId) - screenNames := tx.SelectStrings(`SELECT name FROM screen WHERE sessionid = ? AND NOT closed`, sessionId) + maxScreenIdx := tx.GetInt(`SELECT COALESCE(max(screenidx), 0) FROM screen WHERE sessionid = ? AND NOT archived`, sessionId) + screenNames := tx.SelectStrings(`SELECT name FROM screen WHERE sessionid = ? AND NOT archived`, sessionId) screenName := fmtUniqueName(origScreenName, "s%d", maxScreenIdx+1, screenNames) newScreenId = scbase.GenPromptUUID() - query = `INSERT INTO screen (sessionid, screenid, name, activewindowid, screenidx, screenopts, ownerid, sharemode, incognito, closed) VALUES (?, ?, ?, ?, ?, ?, '', 'local', 0, 0)` + query = `INSERT INTO screen (sessionid, screenid, name, activewindowid, screenidx, screenopts, ownerid, sharemode, incognito, archived) VALUES (?, ?, ?, ?, ?, ?, '', 'local', 0, 0)` tx.ExecWrap(query, sessionId, newScreenId, screenName, newWindowId, maxScreenIdx+1, ScreenOptsType{}) layout := LayoutType{Type: LayoutFull} query = `INSERT INTO screen_window (sessionid, screenid, windowid, name, layout, selectedline, anchor, focustype) VALUES (?, ?, ?, ?, ?, ?, ?, ?)` @@ -832,7 +833,7 @@ func getNextId(ids []string, delId string) string { func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (UpdatePacket, error) { txErr := WithTx(ctx, func(tx *TxWrap) error { - query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ? AND NOT closed` + query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ? AND NOT archived` if !tx.Exists(query, sessionId, screenId) { return fmt.Errorf("cannot switch to screen, screen=%s does not exist in session=%s", screenId, sessionId) } @@ -845,7 +846,31 @@ func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (U return update, txErr } -func CleanWindows() { +func CleanWindows(sessionId string) { + txErr := WithTx(context.Background(), func(tx *TxWrap) error { + query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid NOT IN (SELECT windowid FROM screen_window WHERE sessionid = ?)` + removedWindowIds := tx.SelectStrings(query, sessionId, sessionId) + if len(removedWindowIds) == 0 { + return nil + } + for _, windowId := range removedWindowIds { + query = `DELETE FROM window WHERE sessionid = ? AND windowid = ?` + tx.ExecWrap(query, sessionId, windowId) + query = `DELETE FROM history WHERE sessionid = ? AND windowid = ?` + tx.ExecWrap(query, sessionId, windowId) + query = `DELETE FROM line WHERE sessinid = ? AND windowid = ?` + tx.ExecWrap(query, sessionId, windowId) + } + 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.ExecWrap(query, sessionId, sessionId) + fmt.Printf("removed cmds: %v\n", removedCmds) + return nil + }) + if txErr != nil { + fmt.Printf("ERROR cleaning windows sessionid:%s: %v\n", sessionId, txErr) + } } func CloseScreen(ctx context.Context, sessionId string, screenId string) (UpdatePacket, error) { @@ -855,21 +880,21 @@ func CloseScreen(ctx context.Context, sessionId string, screenId string) (Update if !tx.Exists(query, sessionId, screenId) { return fmt.Errorf("cannot close screen (not found)") } - query = `SELECT closed FROM screen WHERE sessionid = ? AND screenid = ?` + query = `SELECT archived FROM screen WHERE sessionid = ? AND screenid = ?` closeVal := tx.GetBool(query, sessionId, screenId) if closeVal { return nil } - query = `SELECT count(*) FROM screen WHERE sessionid = ? AND NOT closed` + query = `SELECT count(*) FROM screen WHERE sessionid = ? AND NOT archived` numScreens := tx.GetInt(query, sessionId) if numScreens <= 1 { return fmt.Errorf("cannot close the last screen in a session") } - query = `UPDATE screen SET closed = 1, screenidx = 0 WHERE sessionid = ? AND screenid = ?` + query = `UPDATE screen SET archived = 1, screenidx = 0 WHERE sessionid = ? AND screenid = ?` tx.ExecWrap(query, sessionId, screenId) 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 closed ORDER BY screenidx`, sessionId) + screenIds := tx.SelectStrings(`SELECT screenid FROM screen WHERE sessionid = ? AND NOT archived ORDER BY screenidx`, sessionId) nextId := getNextId(screenIds, screenId) tx.ExecWrap(`UPDATE session SET activescreenid = ? WHERE sessionid = ?`, nextId, sessionId) newActiveScreenId = nextId @@ -887,15 +912,15 @@ func CloseScreen(ctx context.Context, sessionId string, screenId string) (Update func UnCloseScreen(ctx context.Context, sessionId string, screenId string) error { txErr := WithTx(ctx, func(tx *TxWrap) error { - query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ? AND closed` + query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ? AND archived` if !tx.Exists(query, sessionId, screenId) { - return fmt.Errorf("cannot re-open screen (not found or not closed)") + return fmt.Errorf("cannot re-open screen (not found or not archived)") } origScreenName := tx.GetString(`SELECT name FROM screen WHERE sessionid = ? AND screenid = ?`, sessionId, screenId) - maxScreenIdx := tx.GetInt(`SELECT COALESCE(max(screenidx), 0) FROM screen WHERE sessionid = ? AND NOT closed`, sessionId) - screenNames := tx.SelectStrings(`SELECT name FROM screen WHERE sessionid = ? AND NOT closed`, sessionId) + maxScreenIdx := tx.GetInt(`SELECT COALESCE(max(screenidx), 0) FROM screen WHERE sessionid = ? AND NOT archived`, sessionId) + screenNames := tx.SelectStrings(`SELECT name FROM screen WHERE sessionid = ? AND NOT archived`, sessionId) newScreenName := fmtUniqueName(origScreenName, "s-%d", 2, screenNames) - query = `UPDATE screen SET closed = 0, screenidx = ?, name = ? WHERE sessionid = ? AND screenid = ?` + query = `UPDATE screen SET archived = 0, screenidx = ?, name = ? WHERE sessionid = ? AND screenid = ?` tx.ExecWrap(query, maxScreenIdx+1, newScreenName, sessionId, screenId) return nil }) @@ -905,14 +930,23 @@ func UnCloseScreen(ctx context.Context, sessionId string, screenId string) error func DeleteScreen(ctx context.Context, sessionId string, screenId string) (UpdatePacket, error) { var newActiveScreenId string txErr := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ?` + if !tx.Exists(query, sessionId, screenId) { + return fmt.Errorf("cannot purge screen (not found)") + } + 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 closed ORDER BY screenidx`, sessionId) + screenIds := tx.SelectStrings(`SELECT screenid FROM screen WHERE sessionid = ? AND NOT archived ORDER BY screenidx`, sessionId) nextId := getNextId(screenIds, screenId) tx.ExecWrap(`UPDATE session SET activescreenid = ? WHERE sessionid = ?`, nextId, sessionId) newActiveScreenId = nextId } - query := `DELETE FROM screen_window WHERE sessionid = ? AND screenid = ?` + query = `DELETE FROM screen_window WHERE sessionid = ? AND screenid = ?` tx.ExecWrap(query, sessionId, screenId) query = `DELETE FROM screen WHERE sessionid = ? AND screenid = ?` tx.ExecWrap(query, sessionId, screenId) @@ -921,7 +955,7 @@ func DeleteScreen(ctx context.Context, sessionId string, screenId string) (Updat if txErr != nil { return nil, txErr } - go CleanWindows() + go CleanWindows(sessionId) update, session := MakeSingleSessionUpdate(sessionId) session.ActiveScreenId = newActiveScreenId session.Screens = append(session.Screens, &ScreenType{SessionId: sessionId, ScreenId: screenId, Remove: true}) @@ -1144,7 +1178,7 @@ func SetScreenName(ctx context.Context, sessionId string, screenId string, name if !tx.Exists(query, sessionId, screenId) { return fmt.Errorf("screen does not exist") } - query = `SELECT screenid FROM screen WHERE sessionid = ? AND name = ? AND NOT closed` + query = `SELECT screenid FROM screen WHERE sessionid = ? AND name = ? AND NOT archived` dupScreenId := tx.GetString(query, sessionId, name) if dupScreenId == screenId { return nil @@ -1245,10 +1279,10 @@ func GetSessionStats(ctx context.Context, sessionId string) (*SessionStatsType, if !tx.Exists(query, sessionId) { return fmt.Errorf("not found") } - query = `SELECT count(*) FROM screen WHERE sessionid = ? AND NOT closed` + query = `SELECT count(*) FROM screen WHERE sessionid = ? AND NOT archived` rtn.NumScreens = tx.GetInt(query, sessionId) - query = `SELECT count(*) FROM screen WHERE sessionid = ? AND closed` - rtn.NumClosedScreens = tx.GetInt(query, sessionId) + query = `SELECT count(*) FROM screen WHERE sessionid = ? AND archived` + rtn.NumArchivedScreens = tx.GetInt(query, sessionId) query = `SELECT count(*) FROM window WHERE sessionid = ?` rtn.NumWindows = tx.GetInt(query, sessionId) query = `SELECT count(*) FROM line WHERE sessionid = ?` diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index eb6e3357..88962683 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -152,7 +152,7 @@ type SessionType struct { ShareMode string `json:"sharemode"` AccessKey string `json:"-"` NotifyNum int64 `json:"notifynum"` - Closed bool `json:"closed,omitempty"` + Archived bool `json:"archived,omitempty"` Screens []*ScreenType `json:"screens"` Remotes []*RemoteInstance `json:"remotes"` @@ -162,13 +162,13 @@ type SessionType struct { } type SessionStatsType struct { - SessionId string `json:"sessionid"` - NumScreens int `json:"numscreens"` - NumClosedScreens int `json:"numclosedscreens"` - NumWindows int `json:"numwindows"` - NumLines int `json:"numlines"` - NumCmds int `json:"numcmds"` - DiskStats SessionDiskSizeType `json:"diskstats"` + SessionId string `json:"sessionid"` + NumScreens int `json:"numscreens"` + NumArchivedScreens int `json:"numarchivedscreens"` + NumWindows int `json:"numwindows"` + NumLines int `json:"numlines"` + NumCmds int `json:"numcmds"` + DiskStats SessionDiskSizeType `json:"diskstats"` } type WindowOptsType struct { @@ -357,7 +357,7 @@ type ScreenType struct { OwnerId string `json:"ownerid"` ShareMode string `json:"sharemode"` Incognito bool `json:"incognito,omitempty"` - Closed bool `json:"closed,omitempty"` + Archived bool `json:"archived,omitempty"` Windows []*ScreenWindowType `json:"windows"` // only for updates