ci / module boundaries / boundaries (push) Successful in 6s
ci / api / api (push) Successful in 47s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m2s
ci / db / db (push) Successful in 1m4s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m30s
ci / ts / ts (packages + web) (push) Successful in 2m54s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m14s
70 lines
1.8 KiB
Go
70 lines
1.8 KiB
Go
package library
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"pipu/api/internal/auth"
|
|
"pipu/api/internal/platform/apperr"
|
|
)
|
|
|
|
type ScanStore interface {
|
|
GetSource(context.Context, uuid.UUID) (Source, error)
|
|
RetryFailedAnalysis(context.Context) (int, error)
|
|
}
|
|
type ScanStarter interface {
|
|
Start(Source, string, bool) error
|
|
}
|
|
|
|
// ScanService owns explicit and scheduled scan starts.
|
|
type ScanService struct {
|
|
store ScanStore
|
|
scanner ScanStarter
|
|
board *ProgressBoard
|
|
root func(Source) (string, error)
|
|
}
|
|
|
|
// StartScan запускает скан источника в фоне.
|
|
// RetryAnalysis возвращает в очередь треки, которые анализатор не смог обработать (например, пока диск
|
|
// не был смонтирован).
|
|
func (s *ScanService) RetryAnalysis(ctx context.Context) (int, error) {
|
|
if err := requirePerm(ctx, auth.PermManageLibrary); err != nil {
|
|
return 0, err
|
|
}
|
|
return s.store.RetryFailedAnalysis(ctx)
|
|
}
|
|
|
|
func (s *ScanService) StartScan(ctx context.Context, id uuid.UUID, full bool) (Progress, error) {
|
|
if err := requirePerm(ctx, auth.PermManageLibrary); err != nil {
|
|
return Progress{}, err
|
|
}
|
|
src, err := s.store.GetSource(ctx, id)
|
|
if err != nil {
|
|
return Progress{}, notFound(err)
|
|
}
|
|
if err := s.startScan(src, full); err != nil {
|
|
return Progress{}, err
|
|
}
|
|
p, _ := s.board.Get(id)
|
|
return p, nil
|
|
}
|
|
|
|
func (s *ScanService) startScan(src Source, full bool) error {
|
|
if src.Status != "mounted" {
|
|
return apperr.New(http.StatusConflict, CodeSourceOffline, "source is not connected")
|
|
}
|
|
root, err := s.root(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := s.scanner.Start(src, root, full); errors.Is(err, ErrScanRunning) {
|
|
return apperr.Conflict(CodeScanRunning, "scan is already running")
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|