mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
chore: Add watch workspace endpoint (#1493)
This commit is contained in:
@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
"nhooyr.io/websocket"
|
||||
|
||||
"github.com/coder/coder/coderd/httpapi"
|
||||
"github.com/coder/coder/coderd/httpmw"
|
||||
@ -63,7 +64,7 @@ func (c *Client) Request(ctx context.Context, method, path string, body interfac
|
||||
return nil, xerrors.Errorf("create request: %w", err)
|
||||
}
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: httpmw.AuthCookie,
|
||||
Name: httpmw.SessionTokenKey,
|
||||
Value: c.SessionToken,
|
||||
})
|
||||
if body != nil {
|
||||
@ -80,6 +81,38 @@ func (c *Client) Request(ctx context.Context, method, path string, body interfac
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// dialWebsocket opens a dialWebsocket connection on that path provided.
|
||||
// The caller is responsible for closing the dialWebsocket.Conn.
|
||||
func (c *Client) dialWebsocket(ctx context.Context, path string) (*websocket.Conn, error) {
|
||||
serverURL, err := c.URL.Parse(path)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse path: %w", err)
|
||||
}
|
||||
|
||||
apiURL, err := url.Parse(serverURL.String())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse server url: %w", err)
|
||||
}
|
||||
apiURL.Scheme = "ws"
|
||||
if serverURL.Scheme == "https" {
|
||||
apiURL.Scheme = "wss"
|
||||
}
|
||||
apiURL.Path = path
|
||||
q := apiURL.Query()
|
||||
q.Add(httpmw.SessionTokenKey, c.SessionToken)
|
||||
apiURL.RawQuery = q.Encode()
|
||||
|
||||
//nolint:bodyclose
|
||||
conn, _, err := websocket.Dial(ctx, apiURL.String(), &websocket.DialOptions{
|
||||
HTTPClient: c.HTTPClient,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("dial websocket: %w", err)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// readBodyAsError reads the response as an httpapi.Message, and
|
||||
// wraps it in a codersdk.Error type for easy marshaling.
|
||||
func readBodyAsError(res *http.Response) error {
|
||||
|
@ -188,7 +188,7 @@ func (c *Client) ListenWorkspaceAgent(ctx context.Context, logger slog.Logger) (
|
||||
return agent.Metadata{}, nil, xerrors.Errorf("create cookie jar: %w", err)
|
||||
}
|
||||
jar.SetCookies(serverURL, []*http.Cookie{{
|
||||
Name: httpmw.AuthCookie,
|
||||
Name: httpmw.SessionTokenKey,
|
||||
Value: c.SessionToken,
|
||||
}})
|
||||
httpClient := &http.Client{
|
||||
@ -263,7 +263,7 @@ func (c *Client) DialWorkspaceAgent(ctx context.Context, agentID uuid.UUID, opti
|
||||
return nil, xerrors.Errorf("create cookie jar: %w", err)
|
||||
}
|
||||
jar.SetCookies(serverURL, []*http.Cookie{{
|
||||
Name: httpmw.AuthCookie,
|
||||
Name: httpmw.SessionTokenKey,
|
||||
Value: c.SessionToken,
|
||||
}})
|
||||
httpClient := &http.Client{
|
||||
@ -351,7 +351,7 @@ func (c *Client) WorkspaceAgentReconnectingPTY(ctx context.Context, agentID, rec
|
||||
return nil, xerrors.Errorf("create cookie jar: %w", err)
|
||||
}
|
||||
jar.SetCookies(serverURL, []*http.Cookie{{
|
||||
Name: httpmw.AuthCookie,
|
||||
Name: httpmw.SessionTokenKey,
|
||||
Value: c.SessionToken,
|
||||
}})
|
||||
httpClient := &http.Client{
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
"nhooyr.io/websocket"
|
||||
"nhooyr.io/websocket/wsjson"
|
||||
|
||||
"github.com/coder/coder/coderd/database"
|
||||
)
|
||||
@ -98,6 +100,36 @@ func (c *Client) WorkspaceBuildByName(ctx context.Context, workspace uuid.UUID,
|
||||
return workspaceBuild, json.NewDecoder(res.Body).Decode(&workspaceBuild)
|
||||
}
|
||||
|
||||
func (c *Client) WatchWorkspace(ctx context.Context, id uuid.UUID) (<-chan Workspace, error) {
|
||||
conn, err := c.dialWebsocket(ctx, fmt.Sprintf("/api/v2/workspaces/%s/watch", id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wc := make(chan Workspace, 256)
|
||||
|
||||
go func() {
|
||||
defer close(wc)
|
||||
defer conn.Close(websocket.StatusNormalClosure, "")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
var ws Workspace
|
||||
err := wsjson.Read(ctx, conn, &ws)
|
||||
if err != nil {
|
||||
conn.Close(websocket.StatusInternalError, "failed to read workspace")
|
||||
return
|
||||
}
|
||||
wc <- ws
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return wc, nil
|
||||
}
|
||||
|
||||
// UpdateWorkspaceAutostartRequest is a request to update a workspace's autostart schedule.
|
||||
type UpdateWorkspaceAutostartRequest struct {
|
||||
Schedule string `json:"schedule"`
|
||||
|
Reference in New Issue
Block a user