(rw http.ResponseWriter, r *http.Request)
| 611 | } |
| 612 | |
| 613 | func (a *API) handleRecordingStop(rw http.ResponseWriter, r *http.Request) { |
| 614 | ctx := r.Context() |
| 615 | logger := a.logger.With(agentchat.Fields(ctx)...) |
| 616 | |
| 617 | recordingID, ok := a.decodeRecordingRequest(rw, r) |
| 618 | if !ok { |
| 619 | return |
| 620 | } |
| 621 | |
| 622 | a.closeMu.Lock() |
| 623 | if a.closed { |
| 624 | a.closeMu.Unlock() |
| 625 | httpapi.Write(ctx, rw, http.StatusServiceUnavailable, codersdk.Response{ |
| 626 | Message: "Desktop API is shutting down.", |
| 627 | }) |
| 628 | return |
| 629 | } |
| 630 | a.closeMu.Unlock() |
| 631 | |
| 632 | // Stop recording (idempotent). |
| 633 | // Use a context detached from the HTTP request so that if the |
| 634 | // connection drops, the recording process can still shut down |
| 635 | // gracefully. WithoutCancel preserves request-scoped values. |
| 636 | stopCtx, stopCancel := context.WithTimeout(context.WithoutCancel(r.Context()), 30*time.Second) |
| 637 | defer stopCancel() |
| 638 | artifact, err := a.desktop.StopRecording(stopCtx, recordingID) |
| 639 | if err != nil { |
| 640 | if errors.Is(err, ErrUnknownRecording) { |
| 641 | httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{ |
| 642 | Message: "Recording not found.", |
| 643 | Detail: err.Error(), |
| 644 | }) |
| 645 | return |
| 646 | } |
| 647 | if errors.Is(err, ErrRecordingCorrupted) { |
| 648 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 649 | Message: "Recording is corrupted.", |
| 650 | Detail: err.Error(), |
| 651 | }) |
| 652 | return |
| 653 | } |
| 654 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 655 | Message: "Failed to stop recording.", |
| 656 | Detail: err.Error(), |
| 657 | }) |
| 658 | return |
| 659 | } |
| 660 | defer artifact.Reader.Close() |
| 661 | defer func() { |
| 662 | if artifact.ThumbnailReader != nil { |
| 663 | _ = artifact.ThumbnailReader.Close() |
| 664 | } |
| 665 | }() |
| 666 | |
| 667 | if artifact.Size > workspacesdk.MaxRecordingSize { |
| 668 | logger.Warn(ctx, "recording file exceeds maximum size", |
| 669 | slog.F("recording_id", recordingID), |
| 670 | slog.F("size", artifact.Size), |
nothing calls this directly
no test coverage detected