working on session archive/delete

This commit is contained in:
sawka 2022-12-26 16:09:21 -08:00
parent a485294f0b
commit af16ab1aed
5 changed files with 259 additions and 81 deletions

View File

@ -418,8 +418,14 @@ func ScreenArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
if err != nil { if err != nil {
return nil, fmt.Errorf("/screen:archive cannot get updated screen obj: %v", err) return nil, fmt.Errorf("/screen:archive cannot get updated screen obj: %v", err)
} }
update, session := sstore.MakeSingleSessionUpdate(ids.SessionId) bareSession, err := sstore.GetBareSessionById(ctx, ids.SessionId)
session.Screens = append(session.Screens, screen) if err != nil {
return nil, fmt.Errorf("/screen:archive cannot retrieve updated session obj: %v", err)
}
bareSession.Screens = append(bareSession.Screens, screen)
update := sstore.ModelUpdate{
Sessions: []*sstore.SessionType{bareSession},
}
return update, nil return update, nil
} }
} }
@ -502,11 +508,17 @@ func ScreenSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
if err != nil { if err != nil {
return nil, err return nil, err
} }
update, session := sstore.MakeSingleSessionUpdate(ids.SessionId) bareSession, err := sstore.GetBareSessionById(ctx, ids.SessionId)
session.Screens = append(session.Screens, screenObj) if err != nil {
update.Info = &sstore.InfoMsgType{ return nil, fmt.Errorf("/screen:set cannot retrieve session: %v", err)
InfoMsg: fmt.Sprintf("screen updated %s", formatStrs(varsUpdated, "and", false)), }
TimeoutMs: 2000, bareSession.Screens = append(bareSession.Screens, screenObj)
update := sstore.ModelUpdate{
Sessions: []*sstore.SessionType{bareSession},
Info: &sstore.InfoMsgType{
InfoMsg: fmt.Sprintf("screen updated %s", formatStrs(varsUpdated, "and", false)),
TimeoutMs: 2000,
},
} }
return update, nil return update, nil
} }
@ -963,7 +975,7 @@ func ScreenShowAllCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
if screen.ScreenIdx != 0 { if screen.ScreenIdx != 0 {
screenIdxStr = strconv.Itoa(int(screen.ScreenIdx)) screenIdxStr = strconv.Itoa(int(screen.ScreenIdx))
} }
outStr := fmt.Sprintf("%-30s %s %s\n", screen.Name+archivedStr, screen.ScreenId, screenIdxStr) outStr := fmt.Sprintf("%-30s %s %s\n", screen.Name+archivedStr, screen.ScreenId, screenIdxStr)
buf.WriteString(outStr) buf.WriteString(outStr)
} }
return sstore.ModelUpdate{ return sstore.ModelUpdate{
@ -1379,27 +1391,79 @@ func SessionDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = sstore.DeleteSession(ctx, ids.SessionId) update, err := sstore.DeleteSession(ctx, ids.SessionId)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot delete session: %v", err) return nil, fmt.Errorf("cannot delete session: %v", err)
} }
delSession := &sstore.SessionType{SessionId: ids.SessionId, Remove: true}
update := sstore.ModelUpdate{
Sessions: []*sstore.SessionType{delSession},
}
activeSessionId, _ := sstore.GetActiveSessionId(ctx) // ignore error
if activeSessionId == "" {
sessionIds, _ := sstore.GetAllSessionIds(ctx) // ignore error, session is already deleted so that's the main return value
if len(sessionIds) > 0 {
err = sstore.SetActiveSessionId(ctx, sessionIds[0])
if err != nil {
update.ActiveSessionId = sessionIds[0]
}
}
}
return update, nil return update, nil
} }
func SessionArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveUiIds(ctx, pk, 0) // don't force R_Session
if err != nil {
return nil, err
}
sessionId := ""
if len(pk.Args) >= 1 {
ritem, err := resolveSession(ctx, pk.Args[0], ids.SessionId)
if err != nil {
return nil, fmt.Errorf("/session:archive error resolving session %q: %w", pk.Args[0], err)
}
if ritem == nil {
return nil, fmt.Errorf("/session:archive session %q not found", pk.Args[0])
}
sessionId = ritem.Id
} else {
sessionId = ids.SessionId
}
if sessionId == "" {
return nil, fmt.Errorf("/session:archive no sessionid found")
}
archiveVal := true
if len(pk.Args) >= 2 {
archiveVal = resolveBool(pk.Args[1], true)
}
if archiveVal {
update, err := sstore.ArchiveSession(ctx, sessionId)
if err != nil {
return nil, fmt.Errorf("cannot archive session: %v", err)
}
return update, nil
} else {
update, err := sstore.UnArchiveSession(ctx, sessionId)
if err != nil {
return nil, fmt.Errorf("cannot un-archive session: %v", err)
}
return update, nil
}
}
func SessionShowAllCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
sessions, err := sstore.GetBareSessions(ctx)
if err != nil {
return nil, fmt.Errorf("error retrieving sessions: %v", err)
}
var buf bytes.Buffer
for _, session := range sessions {
var archivedStr string
if session.Archived {
archivedStr = " (archived)"
}
sessionIdxStr := "-"
if session.SessionIdx != 0 {
sessionIdxStr = strconv.Itoa(int(session.SessionIdx))
}
outStr := fmt.Sprintf("%-30s %s %s\n", session.Name+archivedStr, session.SessionId, sessionIdxStr)
buf.WriteString(outStr)
}
return sstore.ModelUpdate{
Info: &sstore.InfoMsgType{
InfoTitle: "all sessions",
InfoLines: splitLinesForInfo(buf.String()),
},
}, nil
}
func SessionSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func SessionSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveUiIds(ctx, pk, R_Session) ids, err := resolveUiIds(ctx, pk, R_Session)
if err != nil { if err != nil {
@ -1444,12 +1508,7 @@ func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
if firstArg == "" { if firstArg == "" {
return nil, fmt.Errorf("usage /session [name|id|pos], no param specified") return nil, fmt.Errorf("usage /session [name|id|pos], no param specified")
} }
bareSessions, err := sstore.GetBareSessions(ctx) ritem, err := resolveSession(ctx, firstArg, ids.SessionId)
if err != nil {
return nil, err
}
ritems := sessionsToResolveItems(bareSessions)
ritem, err := genericResolve(firstArg, ids.SessionId, ritems, false, "session")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -2069,11 +2128,3 @@ func resolveSetArg(argName string) (bool, string, string) {
} }
return true, scopeName, varName 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
}

View File

@ -288,6 +288,19 @@ func resolveSessionScreen(ctx context.Context, sessionId string, screenArg strin
return genericResolve(screenArg, curScreenArg, ritems, false, "screen") return genericResolve(screenArg, curScreenArg, ritems, false, "screen")
} }
func resolveSession(ctx context.Context, sessionArg string, curSessionArg string) (*ResolveItem, error) {
bareSessions, err := sstore.GetBareSessions(ctx)
if err != nil {
return nil, err
}
ritems := sessionsToResolveItems(bareSessions)
ritem, err := genericResolve(sessionArg, curSessionArg, ritems, false, "session")
if err != nil {
return nil, err
}
return ritem, nil
}
func resolveLine(ctx context.Context, sessionId string, windowId string, lineArg string, curLineArg string) (*ResolveItem, error) { func resolveLine(ctx context.Context, sessionId string, windowId string, lineArg string, curLineArg string) (*ResolveItem, error) {
lines, err := sstore.GetLineResolveItems(ctx, sessionId, windowId) lines, err := sstore.GetLineResolveItems(ctx, sessionId, windowId)
if err != nil { if err != nil {

View File

@ -237,7 +237,7 @@ func GetHistoryItems(ctx context.Context, sessionId string, windowId string, opt
func GetBareSessions(ctx context.Context) ([]*SessionType, error) { func GetBareSessions(ctx context.Context) ([]*SessionType, error) {
var rtn []*SessionType var rtn []*SessionType
err := WithTx(ctx, func(tx *TxWrap) error { err := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT * FROM session ORDER BY sessionidx` query := `SELECT * FROM session ORDER BY archived, sessionidx, archivedts`
tx.SelectWrap(&rtn, query) tx.SelectWrap(&rtn, query)
return nil return nil
}) })
@ -247,8 +247,8 @@ func GetBareSessions(ctx context.Context) ([]*SessionType, error) {
return rtn, nil return rtn, nil
} }
// does not include archived // does not include archived, finds lowest sessionidx (for resetting active session)
func GetAllSessionIds(ctx context.Context) ([]string, error) { func GetFirstSessionId(ctx context.Context) (string, error) {
var rtn []string var rtn []string
txErr := WithTx(ctx, func(tx *TxWrap) error { txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT sessionid from session WHERE NOT archived ORDER by sessionidx` query := `SELECT sessionid from session WHERE NOT archived ORDER by sessionidx`
@ -256,9 +256,12 @@ func GetAllSessionIds(ctx context.Context) ([]string, error) {
return nil return nil
}) })
if txErr != nil { if txErr != nil {
return nil, txErr return "", txErr
} }
return rtn, nil if len(rtn) == 0 {
return "", nil
}
return rtn[0], nil
} }
func GetBareSessionById(ctx context.Context, sessionId string) (*SessionType, error) { func GetBareSessionById(ctx context.Context, sessionId string) (*SessionType, error) {
@ -281,7 +284,7 @@ func GetAllSessions(ctx context.Context) (*ModelUpdate, error) {
var rtn []*SessionType var rtn []*SessionType
var activeSessionId string var activeSessionId string
txErr := WithTx(ctx, func(tx *TxWrap) error { txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT * FROM session` query := `SELECT * FROM session ORDER BY archived, sessionidx, archivedts`
tx.SelectWrap(&rtn, query) tx.SelectWrap(&rtn, query)
sessionMap := make(map[string]*SessionType) sessionMap := make(map[string]*SessionType)
for _, session := range rtn { for _, session := range rtn {
@ -439,7 +442,7 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo
func SetActiveSessionId(ctx context.Context, sessionId string) error { func SetActiveSessionId(ctx context.Context, sessionId string) error {
txErr := WithTx(ctx, func(tx *TxWrap) error { txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT archived` query := `SELECT sessionid FROM session WHERE sessionid = ?`
if !tx.Exists(query, sessionId) { if !tx.Exists(query, sessionId) {
return fmt.Errorf("cannot switch to session, not found") return fmt.Errorf("cannot switch to session, not found")
} }
@ -507,7 +510,7 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
txErr := WithTx(ctx, func(tx *TxWrap) error { txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT archived` query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT archived`
if !tx.Exists(query, sessionId) { if !tx.Exists(query, sessionId) {
return fmt.Errorf("cannot create screen, no session found") return fmt.Errorf("cannot create screen, no session found (or session archived)")
} }
remoteId := tx.GetString(`SELECT remoteid FROM remote WHERE remotealias = ?`, LocalRemoteAlias) remoteId := tx.GetString(`SELECT remoteid FROM remote WHERE remotealias = ?`, LocalRemoteAlias)
if remoteId == "" { if remoteId == "" {
@ -534,16 +537,19 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
} }
return nil return nil
}) })
if txErr != nil {
return nil, txErr
}
newScreen, err := GetScreenById(ctx, sessionId, newScreenId) newScreen, err := GetScreenById(ctx, sessionId, newScreenId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
update, session := MakeSingleSessionUpdate(sessionId) bareSession, err := GetBareSessionById(ctx, sessionId)
if activate { if err != nil {
session.ActiveScreenId = newScreenId return nil, err
} }
session.Screens = append(session.Screens, newScreen) bareSession.Screens = append(bareSession.Screens, newScreen)
return update, txErr return ModelUpdate{Sessions: []*SessionType{bareSession}}, nil
} }
func GetScreenById(ctx context.Context, sessionId string, screenId string) (*ScreenType, error) { func GetScreenById(ctx context.Context, sessionId string, screenId string) (*ScreenType, error) {
@ -836,9 +842,14 @@ func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (U
tx.ExecWrap(query, screenId, sessionId) tx.ExecWrap(query, screenId, sessionId)
return nil return nil
}) })
update, session := MakeSingleSessionUpdate(sessionId) if txErr != nil {
session.ActiveScreenId = screenId return nil, txErr
return update, txErr }
bareSession, err := GetBareSessionById(ctx, sessionId)
if err != nil {
return nil, err
}
return ModelUpdate{Sessions: []*SessionType{bareSession}}, nil
} }
func CleanWindows(sessionId string) { func CleanWindows(sessionId string) {
@ -905,11 +916,14 @@ func ArchiveScreen(ctx context.Context, sessionId string, screenId string) (Upda
if txErr != nil { if txErr != nil {
return nil, txErr return nil, txErr
} }
update, session := MakeSingleSessionUpdate(sessionId) bareSession, err := GetBareSessionById(ctx, sessionId)
session.ActiveScreenId = newActiveScreenId if err != nil {
return nil, txErr
}
update := ModelUpdate{Sessions: []*SessionType{bareSession}}
newScreen, _ := GetScreenById(ctx, sessionId, screenId) newScreen, _ := GetScreenById(ctx, sessionId, screenId)
if newScreen != nil { if newScreen != nil {
session.Screens = append(session.Screens, newScreen) bareSession.Screens = append(bareSession.Screens, newScreen)
} }
return update, nil return update, nil
} }
@ -957,10 +971,12 @@ func DeleteScreen(ctx context.Context, sessionId string, screenId string) (Updat
return nil, txErr return nil, txErr
} }
go CleanWindows(sessionId) go CleanWindows(sessionId)
update, session := MakeSingleSessionUpdate(sessionId) bareSession, err := GetBareSessionById(ctx, sessionId)
session.ActiveScreenId = newActiveScreenId if err != nil {
session.Screens = append(session.Screens, &ScreenType{SessionId: sessionId, ScreenId: screenId, Remove: true}) return nil, err
return update, nil }
bareSession.Screens = append(bareSession.Screens, &ScreenType{SessionId: sessionId, ScreenId: screenId, Remove: true})
return ModelUpdate{Sessions: []*SessionType{bareSession}}, nil
} }
func GetRemoteState(ctx context.Context, sessionId string, windowId string, remotePtr RemotePtrType) (*packet.ShellState, *ShellStatePtr, error) { func GetRemoteState(ctx context.Context, sessionId string, windowId string, remotePtr RemotePtrType) (*packet.ShellState, *ShellStatePtr, error) {
@ -1138,7 +1154,7 @@ func reorderStrings(strs []string, toMove string, newIndex int) []string {
func ReIndexSessions(ctx context.Context, sessionId string, newIndex int) error { func ReIndexSessions(ctx context.Context, sessionId string, newIndex int) error {
txErr := WithTx(ctx, func(tx *TxWrap) error { txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT sessionid FROM session ORDER BY sessionidx, name, sessionid` query := `SELECT sessionid FROM session WHERE NOT archived ORDER BY sessionidx, name, sessionid`
ids := tx.SelectStrings(query) ids := tx.SelectStrings(query)
if sessionId != "" { if sessionId != "" {
ids = reorderStrings(ids, sessionId, newIndex) ids = reorderStrings(ids, sessionId, newIndex)
@ -1158,13 +1174,17 @@ func SetSessionName(ctx context.Context, sessionId string, name string) error {
if !tx.Exists(query, sessionId) { if !tx.Exists(query, sessionId) {
return fmt.Errorf("session does not exist") return fmt.Errorf("session does not exist")
} }
query = `SELECT sessionid FROM session WHERE name = ?` query = `SELECT archived FROM session WHERE sessionid = ?`
dupSessionId := tx.GetString(query, name) isArchived := tx.GetBool(query, sessionId)
if dupSessionId == sessionId { if !isArchived {
return nil query = `SELECT sessionid FROM session WHERE name = ? AND NOT archived`
} dupSessionId := tx.GetString(query, name)
if dupSessionId != "" { if dupSessionId == sessionId {
return fmt.Errorf("invalid duplicate session name '%s'", name) return nil
}
if dupSessionId != "" {
return fmt.Errorf("invalid duplicate session name '%s'", name)
}
} }
query = `UPDATE session SET name = ? WHERE sessionid = ?` query = `UPDATE session SET name = ? WHERE sessionid = ?`
tx.ExecWrap(query, name, sessionId) tx.ExecWrap(query, name, sessionId)
@ -1261,8 +1281,105 @@ func UpdateCmdTermOpts(ctx context.Context, sessionId string, cmdId string, term
return txErr return txErr
} }
func DeleteSession(ctx context.Context, sessionId string) error { func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error) {
return nil var newActiveSessionId 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 = `DELETE FROM session WHERE sessionid = ?`
tx.ExecWrap(query, sessionId)
query = `DELETE FROM screen WHERE sessionid = ?`
tx.ExecWrap(query, sessionId)
query = `DELETE FROM screen_window WHERE sessionid = ?`
tx.ExecWrap(query, sessionId)
query = `DELETE FROM window WHERE sessionid = ?`
tx.ExecWrap(query, sessionId)
query = `DELETE FROM history WHERE sessionid = ?`
tx.ExecWrap(query, sessionId)
query = `DELETE FROM line WHERE sessionid = ?`
tx.ExecWrap(query, sessionId)
query = `DELETE FROM cmd WHERE sessionid = ?`
tx.ExecWrap(query, sessionId)
newActiveSessionId, _ = fixActiveSessionId(tx.Context())
return nil
})
if txErr != nil {
return nil, txErr
}
delErr := DeleteSessionDir(ctx, sessionId)
update := ModelUpdate{}
if newActiveSessionId != "" {
update.ActiveSessionId = newActiveSessionId
}
if delErr != nil {
update.Info = &InfoMsgType{
InfoMsg: fmt.Sprintf("error removing session files: %v", delErr),
}
}
update.Sessions = append(update.Sessions, &SessionType{SessionId: sessionId, Remove: true})
return update, nil
}
func fixActiveSessionId(ctx context.Context) (string, error) {
var newActiveSessionId string
txErr := WithTx(ctx, func(tx *TxWrap) error {
curActiveSessionId := tx.GetString("SELECT activesessionid FROM client")
query := `SELECT sessionid FROM session WHERE sessionid = ? AND NOT archived`
if tx.Exists(query, curActiveSessionId) {
return nil
}
var err error
newActiveSessionId, err = GetFirstSessionId(tx.Context())
if err != nil {
return err
}
tx.ExecWrap("UPDATE client SET activesessionid = ?", newActiveSessionId)
return nil
})
if txErr != nil {
return "", txErr
}
return newActiveSessionId, nil
}
func ArchiveSession(ctx context.Context, sessionId string) (UpdatePacket, error) {
if sessionId == "" {
return nil, fmt.Errorf("invalid blank sessionid")
}
var newActiveSessionId 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 archived FROM session WHERE sessionid = ?`
isArchived := tx.GetBool(query, sessionId)
if isArchived {
return nil
}
query = `UPDATE session SET archived = 1, archivedts = ? WHERE sessionid = ?`
tx.ExecWrap(query, time.Now().UnixMilli(), sessionId)
newActiveSessionId, _ = fixActiveSessionId(tx.Context())
return nil
})
if txErr != nil {
return nil, txErr
}
bareSession, _ := GetBareSessionById(ctx, sessionId)
update := ModelUpdate{}
if bareSession != nil {
update.Sessions = append(update.Sessions, bareSession)
}
if newActiveSessionId != "" {
update.ActiveSessionId = newActiveSessionId
}
return update, nil
}
func UnArchiveSession(ctx context.Context, sessionId string) (UpdatePacket, error) {
return nil, nil
} }
func GetSessionStats(ctx context.Context, sessionId string) (*SessionStatsType, error) { func GetSessionStats(ctx context.Context, sessionId string) (*SessionStatsType, error) {

View File

@ -135,3 +135,11 @@ func DeletePtyOutFile(ctx context.Context, sessionId string, cmdId string) error
} }
return os.Remove(ptyOutFileName) return os.Remove(ptyOutFileName)
} }
func DeleteSessionDir(ctx context.Context, sessionId string) error {
sessionDir, err := base.EnsureSessionDir(sessionId)
if err != nil {
return fmt.Errorf("error getting sessiondir: %w", err)
}
return os.RemoveAll(sessionDir)
}

View File

@ -49,17 +49,6 @@ func (ModelUpdate) UpdateType() string {
return ModelUpdateStr return ModelUpdateStr
} }
func MakeSingleSessionUpdate(sessionId string) (ModelUpdate, *SessionType) {
session := &SessionType{
SessionId: sessionId,
NotifyNum: -1,
}
update := ModelUpdate{
Sessions: []*SessionType{session},
}
return update, session
}
func ReadHistoryDataFromUpdate(update UpdatePacket) (string, string, *RemotePtrType) { func ReadHistoryDataFromUpdate(update UpdatePacket) (string, string, *RemotePtrType) {
modelUpdate, ok := update.(ModelUpdate) modelUpdate, ok := update.(ModelUpdate)
if !ok { if !ok {