Files
tutti/services/tuttid/api/daemon_app_uploads.go
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

234 lines
8.8 KiB
Go

package api
import (
"context"
"net/http"
"time"
tuttigenerated "github.com/tutti-os/tutti/services/tuttid/api/generated"
"github.com/tutti-os/tutti/services/tuttid/apierrors"
workspaceservice "github.com/tutti-os/tutti/services/tuttid/service/workspace"
tuttitypes "github.com/tutti-os/tutti/services/tuttid/types"
)
func registerWorkspaceAppUploadRoutes(mux *http.ServeMux, wrapper *tuttigenerated.ServerInterfaceWrapper) {
mux.HandleFunc("/v1/workspaces/{workspaceID}/apps/{appID}/uploads", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
tuttitypes.WriteMethodNotAllowed(w)
return
}
wrapper.PrepareWorkspaceAppUpload(w, r)
})
mux.HandleFunc("/v1/workspaces/{workspaceID}/apps/{appID}/uploads/{uploadID}/content", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPut {
tuttitypes.WriteMethodNotAllowed(w)
return
}
wrapper.PutWorkspaceAppUploadContent(w, r)
})
mux.HandleFunc("/v1/workspaces/{workspaceID}/apps/{appID}/uploads/{uploadID}", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
tuttitypes.WriteMethodNotAllowed(w)
return
}
wrapper.CancelWorkspaceAppUpload(w, r)
})
mux.HandleFunc("/v1/workspaces/{workspaceID}/apps/{appID}/uploads/{uploadID}/complete", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
tuttitypes.WriteMethodNotAllowed(w)
return
}
wrapper.CompleteWorkspaceAppUpload(w, r)
})
}
func (api DaemonAPI) PrepareWorkspaceAppUpload(
ctx context.Context,
request tuttigenerated.PrepareWorkspaceAppUploadRequestObject,
) (tuttigenerated.PrepareWorkspaceAppUploadResponseObject, error) {
if api.AppCenterService == nil {
return tuttigenerated.PrepareWorkspaceAppUpload503JSONResponse{
ServiceUnavailableErrorJSONResponse: workspaceAppServiceUnavailableError(),
}, nil
}
workspaceID, appID, errResponse := validateWorkspaceAppPath(request.WorkspaceID, request.AppID)
if errResponse != nil {
return tuttigenerated.PrepareWorkspaceAppUpload400JSONResponse{InvalidRequestErrorJSONResponse: *errResponse}, nil
}
if request.Body == nil {
return tuttigenerated.PrepareWorkspaceAppUpload400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(
apierrors.EmptyBody(apierrors.WithDeveloperMessage("empty body")),
),
}, nil
}
session, err := api.AppCenterService.PrepareWorkspaceAppUpload(ctx, workspaceID, appID, workspaceservice.PrepareWorkspaceAppUploadInput{
MimeType: request.Body.MimeType,
Name: request.Body.Name,
Purpose: string(request.Body.Purpose),
SizeBytes: request.Body.SizeBytes,
})
if err != nil {
return writePrepareWorkspaceAppUploadError(err), nil
}
return tuttigenerated.PrepareWorkspaceAppUpload201JSONResponse{
ExpiresAt: session.ExpiresAt,
UploadId: session.UploadID,
}, nil
}
func (api DaemonAPI) PutWorkspaceAppUploadContent(
ctx context.Context,
request tuttigenerated.PutWorkspaceAppUploadContentRequestObject,
) (tuttigenerated.PutWorkspaceAppUploadContentResponseObject, error) {
if api.AppCenterService == nil {
return tuttigenerated.PutWorkspaceAppUploadContent503JSONResponse{
ServiceUnavailableErrorJSONResponse: workspaceAppServiceUnavailableError(),
}, nil
}
workspaceID, appID, errResponse := validateWorkspaceAppPath(request.WorkspaceID, request.AppID)
if errResponse != nil {
return tuttigenerated.PutWorkspaceAppUploadContent400JSONResponse{InvalidRequestErrorJSONResponse: *errResponse}, nil
}
if err := api.AppCenterService.PutWorkspaceAppUploadContent(ctx, workspaceID, appID, request.UploadID, workspaceservice.PutWorkspaceAppUploadContentInput{
Body: request.Body,
}); err != nil {
return writePutWorkspaceAppUploadContentError(err), nil
}
return tuttigenerated.PutWorkspaceAppUploadContent204Response{}, nil
}
func (api DaemonAPI) CompleteWorkspaceAppUpload(
ctx context.Context,
request tuttigenerated.CompleteWorkspaceAppUploadRequestObject,
) (tuttigenerated.CompleteWorkspaceAppUploadResponseObject, error) {
if api.AppCenterService == nil {
return tuttigenerated.CompleteWorkspaceAppUpload503JSONResponse{
ServiceUnavailableErrorJSONResponse: workspaceAppServiceUnavailableError(),
}, nil
}
workspaceID, appID, errResponse := validateWorkspaceAppPath(request.WorkspaceID, request.AppID)
if errResponse != nil {
return tuttigenerated.CompleteWorkspaceAppUpload400JSONResponse{InvalidRequestErrorJSONResponse: *errResponse}, nil
}
file, err := api.AppCenterService.CompleteWorkspaceAppUpload(ctx, workspaceID, appID, request.UploadID, time.Now().UTC())
if err != nil {
return writeCompleteWorkspaceAppUploadError(err), nil
}
return tuttigenerated.CompleteWorkspaceAppUpload200JSONResponse{
File: generatedWorkspaceAppUploadedFile(file),
}, nil
}
func (api DaemonAPI) CancelWorkspaceAppUpload(
ctx context.Context,
request tuttigenerated.CancelWorkspaceAppUploadRequestObject,
) (tuttigenerated.CancelWorkspaceAppUploadResponseObject, error) {
if api.AppCenterService == nil {
return tuttigenerated.CancelWorkspaceAppUpload503JSONResponse{
ServiceUnavailableErrorJSONResponse: workspaceAppServiceUnavailableError(),
}, nil
}
workspaceID, appID, errResponse := validateWorkspaceAppPath(request.WorkspaceID, request.AppID)
if errResponse != nil {
return tuttigenerated.CancelWorkspaceAppUpload400JSONResponse{InvalidRequestErrorJSONResponse: *errResponse}, nil
}
if err := api.AppCenterService.CancelWorkspaceAppUpload(ctx, workspaceID, appID, request.UploadID); err != nil {
return writeCancelWorkspaceAppUploadError(err), nil
}
return tuttigenerated.CancelWorkspaceAppUpload204Response{}, nil
}
func generatedWorkspaceAppUploadedFile(file workspaceservice.WorkspaceAppUploadedFile) tuttigenerated.WorkspaceAppUploadedFile {
return tuttigenerated.WorkspaceAppUploadedFile{
MimeType: file.MimeType,
Name: file.Name,
Path: file.Path,
Sha256: file.SHA256,
SizeBytes: file.SizeBytes,
}
}
func writeCancelWorkspaceAppUploadError(err error) tuttigenerated.CancelWorkspaceAppUploadResponseObject {
protocolErr := apierrors.Classify(err)
switch protocolErr.Code {
case tuttigenerated.WorkspaceNotFound, tuttigenerated.WorkspaceAppNotFound:
return tuttigenerated.CancelWorkspaceAppUpload404JSONResponse{
WorkspaceAppNotFoundErrorJSONResponse: workspaceAppNotFoundError(protocolErr),
}
case tuttigenerated.InvalidRequest:
return tuttigenerated.CancelWorkspaceAppUpload400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(protocolErr),
}
default:
return tuttigenerated.CancelWorkspaceAppUpload502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(protocolErr),
}
}
}
func writePrepareWorkspaceAppUploadError(err error) tuttigenerated.PrepareWorkspaceAppUploadResponseObject {
protocolErr := apierrors.Classify(err)
switch protocolErr.Code {
case tuttigenerated.WorkspaceNotFound, tuttigenerated.WorkspaceAppNotFound:
return tuttigenerated.PrepareWorkspaceAppUpload404JSONResponse{
WorkspaceAppNotFoundErrorJSONResponse: workspaceAppNotFoundError(protocolErr),
}
case tuttigenerated.InvalidRequest:
return tuttigenerated.PrepareWorkspaceAppUpload400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(protocolErr),
}
default:
return tuttigenerated.PrepareWorkspaceAppUpload502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(protocolErr),
}
}
}
func writePutWorkspaceAppUploadContentError(err error) tuttigenerated.PutWorkspaceAppUploadContentResponseObject {
protocolErr := apierrors.Classify(err)
switch protocolErr.Code {
case tuttigenerated.WorkspaceNotFound, tuttigenerated.WorkspaceAppNotFound:
return tuttigenerated.PutWorkspaceAppUploadContent404JSONResponse{
WorkspaceAppNotFoundErrorJSONResponse: workspaceAppNotFoundError(protocolErr),
}
case tuttigenerated.InvalidRequest:
return tuttigenerated.PutWorkspaceAppUploadContent400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(protocolErr),
}
default:
return tuttigenerated.PutWorkspaceAppUploadContent502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(protocolErr),
}
}
}
func writeCompleteWorkspaceAppUploadError(err error) tuttigenerated.CompleteWorkspaceAppUploadResponseObject {
protocolErr := apierrors.Classify(err)
switch protocolErr.Code {
case tuttigenerated.WorkspaceNotFound, tuttigenerated.WorkspaceAppNotFound:
return tuttigenerated.CompleteWorkspaceAppUpload404JSONResponse{
WorkspaceAppNotFoundErrorJSONResponse: workspaceAppNotFoundError(protocolErr),
}
case tuttigenerated.InvalidRequest:
return tuttigenerated.CompleteWorkspaceAppUpload400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(protocolErr),
}
default:
return tuttigenerated.CompleteWorkspaceAppUpload502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(protocolErr),
}
}
}