(rw http.ResponseWriter, r *http.Request, initial codersdk.DynamicParametersRequest, render dynamicparameters.Renderer)
| 129 | } |
| 130 | |
| 131 | func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request, initial codersdk.DynamicParametersRequest, render dynamicparameters.Renderer) { |
| 132 | ctx, cancel := context.WithTimeout(r.Context(), 30*time.Minute) |
| 133 | defer cancel() |
| 134 | |
| 135 | conn, err := websocket.Accept(rw, r, nil) |
| 136 | if err != nil { |
| 137 | httpapi.Write(ctx, rw, http.StatusUpgradeRequired, codersdk.Response{ |
| 138 | Message: "Failed to accept WebSocket.", |
| 139 | Detail: err.Error(), |
| 140 | }) |
| 141 | return |
| 142 | } |
| 143 | go httpapi.HeartbeatClose(ctx, api.Logger, cancel, conn) |
| 144 | |
| 145 | stream := wsjson.NewStream[codersdk.DynamicParametersRequest, codersdk.DynamicParametersResponse]( |
| 146 | conn, |
| 147 | websocket.MessageText, |
| 148 | websocket.MessageText, |
| 149 | api.Logger, |
| 150 | ) |
| 151 | |
| 152 | // Send an initial form state, computed without any user input. |
| 153 | result, diagnostics := render.Render(ctx, initial.OwnerID, initial.Inputs) |
| 154 | response := codersdk.DynamicParametersResponse{ |
| 155 | ID: -1, // Always start with -1. |
| 156 | Diagnostics: db2sdk.HCLDiagnostics(diagnostics), |
| 157 | } |
| 158 | if result != nil { |
| 159 | response.Parameters = slice.List(result.Parameters, db2sdk.PreviewParameter) |
| 160 | } |
| 161 | err = stream.Send(response) |
| 162 | if err != nil { |
| 163 | stream.Drop() |
| 164 | return |
| 165 | } |
| 166 | |
| 167 | // As the user types into the form, reprocess the state using their input, |
| 168 | // and respond with updates. |
| 169 | updates := stream.Chan() |
| 170 | ownerID := initial.OwnerID |
| 171 | for { |
| 172 | select { |
| 173 | case <-ctx.Done(): |
| 174 | stream.Close(websocket.StatusGoingAway) |
| 175 | return |
| 176 | case update, ok := <-updates: |
| 177 | if !ok { |
| 178 | // The connection has been closed, so there is no one to write to |
| 179 | return |
| 180 | } |
| 181 | |
| 182 | // Take a nil uuid to mean the previous owner ID. |
| 183 | // This just removes the need to constantly send who you are. |
| 184 | if update.OwnerID == uuid.Nil { |
| 185 | update.OwnerID = ownerID |
| 186 | } |
| 187 | |
| 188 | ownerID = update.OwnerID |
no test coverage detected