|
1 | 1 | package services |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "fmt" |
| 5 | + |
4 | 6 | "github.com/gruntwork-io/runbooks/api" |
5 | 7 | ) |
6 | 8 |
|
7 | | -// WorkspaceService exposes the read-only workspace introspection |
8 | | -// endpoints to the frontend over Wails IPC. These are used by the |
9 | | -// Workspace, RepositoryFileBrowser, ChangedFilesView, DirPicker and |
10 | | -// GitHubPullRequest components. |
11 | | -// |
12 | | -// Stateful actions (register/set-active worktree) stay on the HTTP |
13 | | -// path through M3 because they mutate SessionManager; they'll move |
14 | | -// over in M4 alongside the exec migration. |
15 | | -type WorkspaceService struct{} |
| 9 | +// WorkspaceService exposes workspace introspection + worktree |
| 10 | +// registration to the frontend over Wails IPC. Read-only methods |
| 11 | +// (Tree, Dirs, File, Changes) are session-agnostic and take only a |
| 12 | +// path; mutating methods (Register, SetActive) require a session |
| 13 | +// token so they match the HTTP path's SessionAuthMiddleware |
| 14 | +// semantics. |
| 15 | +type WorkspaceService struct { |
| 16 | + servers *serverManager |
| 17 | +} |
16 | 18 |
|
17 | 19 | // ServiceName satisfies the optional application.ServiceName interface. |
18 | 20 | func (s *WorkspaceService) ServiceName() string { |
@@ -44,3 +46,51 @@ func (s *WorkspaceService) File(absPath string) (*api.WorkspaceFileResponse, err |
44 | 46 | func (s *WorkspaceService) Changes(absPath, singleFile string) (*api.WorkspaceChangesResponse, error) { |
45 | 47 | return api.GetWorkspaceChanges(absPath, singleFile) |
46 | 48 | } |
| 49 | + |
| 50 | +// Register adds a worktree path to the session's registered worktree |
| 51 | +// list. Matches POST /api/workspace/register — used by |
| 52 | +// GitWorkTreeContext when a clone completes or a worktree is discovered |
| 53 | +// on session bootstrap. |
| 54 | +func (s *WorkspaceService) Register(sessionID, path string) error { |
| 55 | + sessions, err := s.authed(sessionID) |
| 56 | + if err != nil { |
| 57 | + return err |
| 58 | + } |
| 59 | + if path == "" { |
| 60 | + return fmt.Errorf("path is required") |
| 61 | + } |
| 62 | + sessions.RegisterWorkTreePath(path) |
| 63 | + return nil |
| 64 | +} |
| 65 | + |
| 66 | +// SetActive sets the explicitly selected active worktree path. |
| 67 | +// Matches POST /api/workspace/set-active — used when the user |
| 68 | +// switches worktrees in the UI so that target="worktree" templates |
| 69 | +// and REPO_FILES resolve against the selected repo. |
| 70 | +func (s *WorkspaceService) SetActive(sessionID, path string) error { |
| 71 | + sessions, err := s.authed(sessionID) |
| 72 | + if err != nil { |
| 73 | + return err |
| 74 | + } |
| 75 | + if path == "" { |
| 76 | + return fmt.Errorf("path is required") |
| 77 | + } |
| 78 | + sessions.SetActiveWorkTreePath(path) |
| 79 | + return nil |
| 80 | +} |
| 81 | + |
| 82 | +// authed mirrors SessionService.authed: resolve the gruntbook's |
| 83 | +// SessionManager and verify the caller's token before any mutation. |
| 84 | +func (s *WorkspaceService) authed(sessionID string) (*api.SessionManager, error) { |
| 85 | + sessions := s.servers.Sessions() |
| 86 | + if sessions == nil { |
| 87 | + return nil, fmt.Errorf("no gruntbook is open") |
| 88 | + } |
| 89 | + if sessionID == "" { |
| 90 | + return nil, fmt.Errorf("missing session token") |
| 91 | + } |
| 92 | + if _, ok := sessions.ValidateToken(sessionID); !ok { |
| 93 | + return nil, fmt.Errorf("invalid or expired session token") |
| 94 | + } |
| 95 | + return sessions, nil |
| 96 | +} |
0 commit comments