mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
chore: add support for one-way websockets to backend (#16853)
Closes https://github.com/coder/coder/issues/16775 ## Changes made - Added `OneWayWebSocket` function that establishes WebSocket connections that don't allow client-to-server communication - Added tests for the new function - Updated API endpoints to make new WS-based endpoints, and mark previous SSE-based endpoints as deprecated - Updated existing SSE handlers to use the same core logic as the new WS handlers ## Notes - Frontend changes handled via #16855
This commit is contained in:
@ -1098,7 +1098,29 @@ func convertScripts(dbScripts []database.WorkspaceAgentScript) []codersdk.Worksp
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Router /workspaceagents/{workspaceagent}/watch-metadata [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func (api *API) watchWorkspaceAgentMetadata(rw http.ResponseWriter, r *http.Request) {
|
||||
// @Deprecated Use /workspaceagents/{workspaceagent}/watch-metadata-ws instead
|
||||
func (api *API) watchWorkspaceAgentMetadataSSE(rw http.ResponseWriter, r *http.Request) {
|
||||
api.watchWorkspaceAgentMetadata(rw, r, httpapi.ServerSentEventSender)
|
||||
}
|
||||
|
||||
// @Summary Watch for workspace agent metadata updates via WebSockets
|
||||
// @ID watch-for-workspace-agent-metadata-updates-via-websockets
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Success 200 {object} codersdk.ServerSentEvent
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Router /workspaceagents/{workspaceagent}/watch-metadata-ws [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func (api *API) watchWorkspaceAgentMetadataWS(rw http.ResponseWriter, r *http.Request) {
|
||||
api.watchWorkspaceAgentMetadata(rw, r, httpapi.OneWayWebSocketEventSender)
|
||||
}
|
||||
|
||||
func (api *API) watchWorkspaceAgentMetadata(
|
||||
rw http.ResponseWriter,
|
||||
r *http.Request,
|
||||
connect httpapi.EventSender,
|
||||
) {
|
||||
// Allow us to interrupt watch via cancel.
|
||||
ctx, cancel := context.WithCancel(r.Context())
|
||||
defer cancel()
|
||||
@ -1163,7 +1185,7 @@ func (api *API) watchWorkspaceAgentMetadata(rw http.ResponseWriter, r *http.Requ
|
||||
//nolint:ineffassign // Release memory.
|
||||
initialMD = nil
|
||||
|
||||
sseSendEvent, sseSenderClosed, err := httpapi.ServerSentEventSender(rw, r)
|
||||
sendEvent, senderClosed, err := connect(rw, r)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error setting up server-sent events.",
|
||||
@ -1174,14 +1196,14 @@ func (api *API) watchWorkspaceAgentMetadata(rw http.ResponseWriter, r *http.Requ
|
||||
// Prevent handler from returning until the sender is closed.
|
||||
defer func() {
|
||||
cancel()
|
||||
<-sseSenderClosed
|
||||
<-senderClosed
|
||||
}()
|
||||
// Synchronize cancellation from SSE -> context, this lets us simplify the
|
||||
// cancellation logic.
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-sseSenderClosed:
|
||||
case <-senderClosed:
|
||||
cancel()
|
||||
}
|
||||
}()
|
||||
@ -1193,7 +1215,7 @@ func (api *API) watchWorkspaceAgentMetadata(rw http.ResponseWriter, r *http.Requ
|
||||
|
||||
log.Debug(ctx, "sending metadata", "num", len(values))
|
||||
|
||||
_ = sseSendEvent(ctx, codersdk.ServerSentEvent{
|
||||
_ = sendEvent(codersdk.ServerSentEvent{
|
||||
Type: codersdk.ServerSentEventTypeData,
|
||||
Data: convertWorkspaceAgentMetadata(values),
|
||||
})
|
||||
@ -1225,7 +1247,7 @@ func (api *API) watchWorkspaceAgentMetadata(rw http.ResponseWriter, r *http.Requ
|
||||
if err != nil {
|
||||
if !database.IsQueryCanceledError(err) {
|
||||
log.Error(ctx, "failed to get metadata", slog.Error(err))
|
||||
_ = sseSendEvent(ctx, codersdk.ServerSentEvent{
|
||||
_ = sendEvent(codersdk.ServerSentEvent{
|
||||
Type: codersdk.ServerSentEventTypeError,
|
||||
Data: codersdk.Response{
|
||||
Message: "Failed to get metadata.",
|
||||
|
Reference in New Issue
Block a user