215 lines
5.4 KiB
Go
215 lines
5.4 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"time"
|
|
|
|
"gitea.kazu634.com/kazu634/tver/internal/store"
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
type fakeJobStore struct {
|
|
jobs map[string]store.Job
|
|
subscriptions map[string]store.Subscription
|
|
nextID int64
|
|
lastEpisode store.Episode
|
|
enqueueCalls, statusCalls int
|
|
statusIDs []string
|
|
listStatuses []string
|
|
listLimits []int
|
|
registerCalls int
|
|
registerEpisodes []store.Episode
|
|
registerDownload bool
|
|
registerErr error
|
|
subscribedCalls int
|
|
subscribedIDs []string
|
|
err error
|
|
}
|
|
|
|
func (f *fakeJobStore) ensure() {
|
|
if f.jobs == nil {
|
|
f.jobs = make(map[string]store.Job)
|
|
}
|
|
}
|
|
|
|
func (f *fakeJobStore) Enqueue(_ context.Context, ep store.Episode, source string) (store.Job, bool, error) {
|
|
f.enqueueCalls++
|
|
f.lastEpisode = ep
|
|
if f.err != nil {
|
|
return store.Job{}, false, f.err
|
|
}
|
|
f.ensure()
|
|
if job, ok := f.jobs[ep.ID]; ok {
|
|
return job, false, nil
|
|
}
|
|
f.nextID++
|
|
job := store.Job{ID: f.nextID, EpisodeID: ep.ID, SeriesTitle: ep.SeriesTitle,
|
|
Title: ep.Title, BroadcasterName: ep.BroadcasterName, Source: source,
|
|
Status: "queued", CreatedAt: time.Date(2026, 10, 3, 0, 0, 0, 0, time.UTC)}
|
|
f.jobs[ep.ID] = job
|
|
return job, true, nil
|
|
}
|
|
|
|
func (f *fakeJobStore) EpisodeStatuses(_ context.Context, ids []string) (map[string]string, error) {
|
|
f.statusCalls++
|
|
f.statusIDs = append([]string(nil), ids...)
|
|
if f.err != nil {
|
|
return nil, f.err
|
|
}
|
|
result := make(map[string]string)
|
|
for _, id := range ids {
|
|
if job, ok := f.jobs[id]; ok {
|
|
result[id] = job.Status
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (f *fakeJobStore) ListJobs(_ context.Context, status string, limit int) ([]store.Job, error) {
|
|
f.listStatuses = append(f.listStatuses, status)
|
|
f.listLimits = append(f.listLimits, limit)
|
|
if f.err != nil {
|
|
return nil, f.err
|
|
}
|
|
var result []store.Job
|
|
for _, job := range f.jobs {
|
|
if job.Status == status {
|
|
result = append(result, job)
|
|
}
|
|
}
|
|
sort.Slice(result, func(i, j int) bool { return result[i].ID > result[j].ID })
|
|
if len(result) > limit {
|
|
result = result[:limit]
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (f *fakeJobStore) GetJob(_ context.Context, id int64) (store.Job, error) {
|
|
if f.err != nil {
|
|
return store.Job{}, f.err
|
|
}
|
|
for _, job := range f.jobs {
|
|
if job.ID == id {
|
|
return job, nil
|
|
}
|
|
}
|
|
return store.Job{}, pgx.ErrNoRows
|
|
}
|
|
|
|
func (f *fakeJobStore) Retry(_ context.Context, id int64) error {
|
|
for ep, job := range f.jobs {
|
|
if job.ID == id && (job.Status == "failed" || job.Status == "canceled") {
|
|
job.Status = "queued"
|
|
f.jobs[ep] = job
|
|
return nil
|
|
}
|
|
}
|
|
return store.ErrInvalidTransition
|
|
}
|
|
|
|
func (f *fakeJobStore) RetryEpisode(_ context.Context, id string) error {
|
|
job, ok := f.jobs[id]
|
|
if !ok || (job.Status != "failed" && job.Status != "canceled") {
|
|
return store.ErrInvalidTransition
|
|
}
|
|
job.Status = "queued"
|
|
f.jobs[id] = job
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeJobStore) Cancel(_ context.Context, id int64) error {
|
|
if f.err != nil {
|
|
return f.err
|
|
}
|
|
for ep, job := range f.jobs {
|
|
if job.ID == id && job.Status == "queued" {
|
|
job.Status = "canceled"
|
|
f.jobs[ep] = job
|
|
return nil
|
|
}
|
|
}
|
|
return store.ErrInvalidTransition
|
|
}
|
|
|
|
func (f *fakeJobStore) CancelQueued(ctx context.Context, id int64) error {
|
|
return f.Cancel(ctx, id)
|
|
}
|
|
|
|
var _ JobStore = (*fakeJobStore)(nil)
|
|
|
|
func (f *fakeJobStore) SubscribedSeries(_ context.Context, ids []string) (map[string]bool, error) {
|
|
f.subscribedCalls++
|
|
f.subscribedIDs = append([]string(nil), ids...)
|
|
if f.err != nil {
|
|
return nil, f.err
|
|
}
|
|
result := make(map[string]bool)
|
|
for _, id := range ids {
|
|
_, result[id] = f.subscriptions[id]
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (f *fakeJobStore) RegisterSubscription(_ context.Context, seriesID, title string, episodes []store.Episode, download bool) (bool, error) {
|
|
f.registerCalls++
|
|
f.registerEpisodes = append([]store.Episode(nil), episodes...)
|
|
f.registerDownload = download
|
|
if f.registerErr != nil {
|
|
return false, f.registerErr
|
|
}
|
|
if f.err != nil {
|
|
return false, f.err
|
|
}
|
|
if f.subscriptions == nil {
|
|
f.subscriptions = make(map[string]store.Subscription)
|
|
}
|
|
if _, exists := f.subscriptions[seriesID]; exists {
|
|
return false, nil
|
|
}
|
|
var count int64
|
|
if download {
|
|
count = int64(len(episodes))
|
|
}
|
|
checked := time.Date(2026, 10, 3, 0, 0, 0, 0, time.UTC)
|
|
f.subscriptions[seriesID] = store.Subscription{SeriesID: seriesID, SeriesTitle: title,
|
|
Enabled: true, CreatedAt: checked, LastCheckedAt: &checked, JobCount: count}
|
|
return true, nil
|
|
}
|
|
|
|
func (f *fakeJobStore) ListSubscriptions(_ context.Context) ([]store.Subscription, error) {
|
|
if f.err != nil {
|
|
return nil, f.err
|
|
}
|
|
var result []store.Subscription
|
|
for _, sub := range f.subscriptions {
|
|
result = append(result, sub)
|
|
}
|
|
sort.Slice(result, func(i, j int) bool { return result[i].SeriesID < result[j].SeriesID })
|
|
return result, nil
|
|
}
|
|
|
|
func (f *fakeJobStore) SetSubscriptionEnabled(_ context.Context, seriesID string, enabled bool) error {
|
|
if f.err != nil {
|
|
return f.err
|
|
}
|
|
sub, exists := f.subscriptions[seriesID]
|
|
if !exists {
|
|
return store.ErrInvalidTransition
|
|
}
|
|
sub.Enabled = enabled
|
|
f.subscriptions[seriesID] = sub
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeJobStore) DeleteSubscription(_ context.Context, seriesID string) (bool, error) {
|
|
if f.err != nil {
|
|
return false, f.err
|
|
}
|
|
if _, exists := f.subscriptions[seriesID]; !exists {
|
|
return false, nil
|
|
}
|
|
delete(f.subscriptions, seriesID)
|
|
return true, nil
|
|
}
|