Files
pipu-music/services/api/internal/library/service.go
T
mrleo1nid e158558da3
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
refactor: isolate playback and upload use cases
2026-10-22 13:52:16 +03:00

71 lines
2.2 KiB
Go

package library
import (
"context"
"errors"
"log/slog"
"pipu/api/internal/auth"
"pipu/api/internal/platform/apperr"
)
// Коды ошибок библиотеки.
const (
CodeSourceNotFound = "library.source_not_found"
CodeScanRunning = "library.scan_running"
CodeSourceOffline = "library.source_offline"
CodePatternInvalid = "validation.pattern_invalid"
CodeNFSInvalid = "validation.nfs_invalid"
CodeLocalPathInvalid = "validation.local_path_invalid"
CodeNameInvalid = "validation.name_invalid"
CodeIntervalInvalid = "validation.scan_interval_invalid"
CodeNotFound = "catalog.not_found"
CodeTemplateInvalid = "validation.template_invalid"
CodeTemplateNone = "library.template_unavailable"
)
// Config — пути к хранилищам в файловой системе api.
type Config struct {
LibraryRoot string // точки монтирования NFS: <root>/<source_id>
HostRoot string // LIBRARY_HOST внутри контейнера, для local-источников
}
// Service preserves the API while each use case owns only its dependencies.
type Service struct {
*SourceService
*TemplateService
*ScanService
*Scheduler
}
func NewService(store *Store, scanner *Scanner, board *ProgressBoard, agent Agent, prober Prober, cfg Config, log *slog.Logger) *Service {
sources := &SourceService{store: store, board: board, agent: agent, cfg: cfg, log: log}
scans := &ScanService{store: store, scanner: scanner, board: board, root: sources.Root}
return &Service{
SourceService: sources,
TemplateService: &TemplateService{store: store, prober: prober, root: sources.Root},
ScanService: scans,
Scheduler: &Scheduler{store: store, sources: sources, scans: scans, log: log},
}
}
func forbidden() error { return apperr.Forbidden(auth.CodeForbidden, "not allowed") }
func requirePerm(ctx context.Context, perm auth.Permission) error {
p, ok := auth.PrincipalFrom(ctx)
if !ok {
return apperr.Unauthorized(auth.CodeUnauthorized, "not authenticated")
}
if !auth.Can(p.Role, perm) {
return forbidden()
}
return nil
}
func notFound(err error) error {
if errors.Is(err, ErrNotFound) {
return apperr.NotFound(CodeSourceNotFound, "source not found")
}
return err
}