get_last_restorable_session.go RawHistoryFolder
1package usecase
2
3import (
4 "context"
5
6 "github.com/bnema/dumber/internal/domain/entity"
7 "github.com/bnema/dumber/internal/domain/repository"
8 "github.com/bnema/dumber/internal/logging"
9)
10
11const (
12 // maxSessionsToCheck is the number of recent sessions to check for restoration.
13 maxSessionsToCheck = 10
14)
15
16// GetLastRestorableSessionUseCase finds the most recent session that can be auto-restored.
17// A session is restorable if:
18// - It is not the current session
19// - It is not actively running (has ended or crashed without lock file)
20// - It has a valid snapshot with at least one tab
21type GetLastRestorableSessionUseCase struct {
22 sessionRepo repository.SessionRepository
23 stateRepo repository.SessionStateRepository
24}
25
26// NewGetLastRestorableSessionUseCase creates a new GetLastRestorableSessionUseCase.
27func NewGetLastRestorableSessionUseCase(
28 sessionRepo repository.SessionRepository,
29 stateRepo repository.SessionStateRepository,
30) *GetLastRestorableSessionUseCase {
31 return &GetLastRestorableSessionUseCase{
32 sessionRepo: sessionRepo,
33 stateRepo: stateRepo,
34 }
35}
36
37// GetLastRestorableSessionInput contains the parameters for finding a restorable session.
38type GetLastRestorableSessionInput struct {
39 // ExcludeSessionID is the current session ID to exclude from results.
40 ExcludeSessionID entity.SessionID
41}
42
43// GetLastRestorableSessionOutput contains the found restorable session, if any.
44type GetLastRestorableSessionOutput struct {
45 // SessionID is the ID of the restorable session, or empty if none found.
46 SessionID entity.SessionID
47 // State is the session state to restore, or nil if none found.
48 State *entity.SessionState
49}
50
51// Execute finds the most recent restorable session.
52// Returns an empty output (not an error) if no restorable session is found.
53func (uc *GetLastRestorableSessionUseCase) Execute(
54 ctx context.Context,
55 input GetLastRestorableSessionInput,
56) (*GetLastRestorableSessionOutput, error) {
57 log := logging.FromContext(ctx)
58
59 sessions, err := uc.sessionRepo.GetRecent(ctx, maxSessionsToCheck)
60 if err != nil {
61 return nil, err
62 }
63
64 for _, session := range sessions {
65 // Only consider browser sessions
66 if session.Type != entity.SessionTypeBrowser {
67 continue
68 }
69
70 // Skip current session
71 if session.ID == input.ExcludeSessionID {
72 continue
73 }
74
75 // Skip sessions that haven't been ended yet (still running or crashed).
76 if session.IsActive() {
77 log.Debug().
78 Str("session_id", string(session.ID)).
79 Msg("auto-restore: skipping active session")
80 continue
81 }
82
83 // Try to get snapshot
84 state, err := uc.stateRepo.GetSnapshot(ctx, session.ID)
85 if err != nil {
86 log.Debug().
87 Err(err).
88 Str("session_id", string(session.ID)).
89 Msg("auto-restore: failed to get snapshot")
90 continue
91 }
92 if state == nil {
93 continue
94 }
95
96 // Skip sessions with no tabs
97 if len(state.Tabs) == 0 {
98 log.Debug().
99 Str("session_id", string(session.ID)).
100 Msg("auto-restore: skipping session with no tabs")
101 continue
102 }
103
104 // Found a valid restorable session
105 log.Info().
106 Str("session_id", string(session.ID)).
107 Int("tabs", len(state.Tabs)).
108 Int("panes", state.CountPanes()).
109 Msg("auto-restore: found restorable session")
110
111 return &GetLastRestorableSessionOutput{
112 SessionID: session.ID,
113 State: state,
114 }, nil
115 }
116
117 // No restorable session found
118 log.Debug().Msg("auto-restore: no restorable session found")
119 return &GetLastRestorableSessionOutput{}, nil
120}