thread-master/apps/backend/internal/module/scout/usecase/runs.go

97 lines
3.2 KiB
Go
Raw Normal View History

2026-08-13 02:22:24 +00:00
package usecase
import (
"context"
"apps/backend/internal/module/scout/domain"
"github.com/google/uuid"
)
func (s *Service) GetRun(ctx context.Context, ownerUID int64, runID string) (*domain.Run, error) {
if s == nil || s.Repo == nil || runID == "" {
return nil, domain.ErrValidation
}
return s.Repo.GetRun(ctx, ownerUID, runID)
}
// CreateQueuedRun creates one independent run for every scan request. The
// job_id is bound in a second guarded write after job scheduling succeeds.
func (s *Service) CreateQueuedRun(ctx context.Context, ownerUID int64, brief *domain.RunBrief) (*domain.Run, error) {
if s == nil || s.Repo == nil || brief == nil || ownerUID == 0 {
return nil, domain.ErrValidation
}
run := domain.NewRun("run_"+uuid.NewString(), "", ownerUID, *brief, domain.NowNano())
if err := s.Repo.CreateRun(ctx, run); err != nil {
return nil, err
}
return run, nil
}
func (s *Service) BindRunJob(ctx context.Context, ownerUID int64, runID, jobID string) (*domain.Run, error) {
if s == nil || s.Repo == nil || runID == "" || jobID == "" {
return nil, domain.ErrValidation
}
run, err := s.Repo.GetRun(ctx, ownerUID, runID)
if err != nil {
return nil, err
}
if run.JobID != "" && run.JobID != jobID {
return nil, domain.ErrIllegalRunStatus
}
run.JobID = jobID
if err := s.Repo.ReplaceRunGuarded(ctx, ownerUID, runID, []string{domain.RunQueued}, run); err != nil {
return nil, err
}
return run, nil
}
// ListRuns returns only runs owned by ownerUID. Pagination is normalized here
// so every caller (HTTP, worker and tests) observes the same page contract.
func (s *Service) ListRuns(ctx context.Context, ownerUID int64, brandID, mode string, page, pageSize int) (domain.RunPage, error) {
if s == nil || s.Repo == nil {
return domain.RunPage{}, domain.ErrValidation
}
pageInfo := domain.NormalizePage(page, pageSize)
return s.Repo.ListRuns(ctx, domain.RunFilter{
OwnerUID: ownerUID,
BrandID: brandID,
Mode: mode,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
})
}
// ListRunPosts returns the selected run and its independently paged results.
// Repository implementations hide staged results until the run succeeds.
func (s *Service) ListRunPosts(ctx context.Context, ownerUID int64, runID string, page, pageSize int) (domain.RunPostPage, error) {
if s == nil || s.Repo == nil {
return domain.RunPostPage{}, domain.ErrValidation
}
if runID == "" {
return domain.RunPostPage{}, domain.ErrValidation
}
pageInfo := domain.NormalizePage(page, pageSize)
return s.Repo.ListRunPosts(ctx, ownerUID, runID, pageInfo.Page, pageInfo.PageSize)
}
// RemoveRun only permits terminal runs to be removed. Returning the same
// guarded transition error for queued/running keeps the API from exposing
// implementation details while allowing response mapping to a 409 conflict.
func (s *Service) RemoveRun(ctx context.Context, ownerUID int64, runID string) error {
if s == nil || s.Repo == nil {
return domain.ErrValidation
}
if runID == "" {
return domain.ErrValidation
}
r, err := s.Repo.GetRun(ctx, ownerUID, runID)
if err != nil {
return err
}
if !domain.IsRunTerminal(r.Status) {
return domain.ErrIllegalRunStatus
}
return s.Repo.DeleteRun(ctx, ownerUID, runID)
}