Skip to content
This repository was archived by the owner on Aug 3, 2024. It is now read-only.

Commit 7eb6971

Browse files
authored
refactor: folders of madness (#34)
1 parent cecf605 commit 7eb6971

File tree

14 files changed

+143
-515
lines changed

14 files changed

+143
-515
lines changed

autoscan.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ import (
1313
// The Scan is used across Triggers, Targets and the Processor.
1414
type Scan struct {
1515
Folder string
16-
File string
1716
Priority int
18-
Retries int
19-
Removed bool
2017
Time time.Time
2118
}
2219

@@ -33,21 +30,10 @@ type HTTPTrigger func(ProcessorFunc) http.Handler
3330
// A Target receives a Scan from the Processor and translates the Scan
3431
// into a format understood by the target.
3532
type Target interface {
36-
Scan([]Scan) error
33+
Scan(Scan) error
3734
Available() error
3835
}
3936

40-
const (
41-
// TVDb provider for use in autoscan.Metadata
42-
TVDb = "tvdb"
43-
44-
// TMDb provider for use in autoscan.Metadata
45-
TMDb = "tmdb"
46-
47-
// IMDb provider for use in autoscan.Metadata
48-
IMDb = "imdb"
49-
)
50-
5137
var (
5238
// ErrTargetUnavailable may occur when a Target goes offline
5339
// or suffers from fatal errors. In this case, the processor

cmd/autoscan/main.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,21 @@ import (
99
"path/filepath"
1010
"time"
1111

12-
"github.com/cloudbox/autoscan/targets/emby"
13-
12+
"github.com/alecthomas/kong"
13+
"github.com/natefinch/lumberjack"
1414
"github.com/rs/zerolog"
1515
"github.com/rs/zerolog/log"
1616
"gopkg.in/yaml.v2"
1717

18-
"github.com/alecthomas/kong"
1918
"github.com/cloudbox/autoscan"
2019
"github.com/cloudbox/autoscan/processor"
20+
"github.com/cloudbox/autoscan/targets/emby"
2121
"github.com/cloudbox/autoscan/targets/plex"
2222
"github.com/cloudbox/autoscan/triggers"
2323
"github.com/cloudbox/autoscan/triggers/bernard"
2424
"github.com/cloudbox/autoscan/triggers/lidarr"
2525
"github.com/cloudbox/autoscan/triggers/radarr"
2626
"github.com/cloudbox/autoscan/triggers/sonarr"
27-
"github.com/natefinch/lumberjack"
2827
)
2928

3029
type config struct {
@@ -163,7 +162,6 @@ func main() {
163162
proc, err := processor.New(processor.Config{
164163
Anchors: c.Anchors,
165164
DatastorePath: cli.Database,
166-
MaxRetries: c.MaxRetries,
167165
MinimumAge: c.MinimumAge,
168166
})
169167

processor/datastore.go

Lines changed: 36 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package processor
33
import (
44
"database/sql"
55
"errors"
6+
"fmt"
67
"time"
78

89
"github.com/cloudbox/autoscan"
@@ -12,18 +13,15 @@ import (
1213
)
1314

1415
type datastore struct {
15-
db *sql.DB
16+
*sql.DB
1617
}
1718

1819
const sqlSchema = `
1920
CREATE TABLE IF NOT EXISTS scan (
2021
"folder" TEXT NOT NULL,
21-
"file" TEXT NOT NULL,
2222
"priority" INTEGER NOT NULL,
2323
"time" DATETIME NOT NULL,
24-
"retries" INTEGER NOT NULL,
25-
"removed" BOOLEAN NOT NULL,
26-
PRIMARY KEY(folder, file)
24+
PRIMARY KEY(folder)
2725
)
2826
`
2927

@@ -38,30 +36,26 @@ func newDatastore(path string) (*datastore, error) {
3836
return nil, err
3937
}
4038

41-
store := &datastore{
42-
db: db,
43-
}
39+
store := &datastore{db}
4440

4541
return store, nil
4642
}
4743

4844
const sqlUpsert = `
49-
INSERT INTO scan (folder, file, priority, time, retries, removed)
50-
VALUES (?, ?, ?, ?, ?, ?)
51-
ON CONFLICT (folder, file) DO UPDATE SET
45+
INSERT INTO scan (folder, priority, time)
46+
VALUES (?, ?, ?)
47+
ON CONFLICT (folder) DO UPDATE SET
5248
priority = MAX(excluded.priority, scan.priority),
53-
time = excluded.time,
54-
retries = excluded.retries,
55-
removed = min(excluded.removed, scan.removed)
49+
time = excluded.time
5650
`
5751

58-
func (store datastore) upsert(tx *sql.Tx, scan autoscan.Scan) error {
59-
_, err := tx.Exec(sqlUpsert, scan.Folder, scan.File, scan.Priority, scan.Time, scan.Retries, scan.Removed)
52+
func (store *datastore) upsert(tx *sql.Tx, scan autoscan.Scan) error {
53+
_, err := tx.Exec(sqlUpsert, scan.Folder, scan.Priority, scan.Time)
6054
return err
6155
}
6256

63-
func (store datastore) Upsert(scans []autoscan.Scan) error {
64-
tx, err := store.db.Begin()
57+
func (store *datastore) Upsert(scans []autoscan.Scan) error {
58+
tx, err := store.Begin()
6559
if err != nil {
6660
return err
6761
}
@@ -79,111 +73,42 @@ func (store datastore) Upsert(scans []autoscan.Scan) error {
7973
return tx.Commit()
8074
}
8175

82-
const sqlGetMatching = `
83-
SELECT folder, file, priority, retries, removed, time FROM scan
84-
WHERE folder = (
85-
SELECT folder
86-
FROM scan
87-
GROUP BY folder
88-
HAVING MAX(time) < ?
89-
ORDER BY priority DESC, time ASC
90-
LIMIT 1
91-
)
76+
const sqlGetAvailableScan = `
77+
SELECT folder, priority, time FROM scan
78+
WHERE time < ?
79+
ORDER BY priority DESC, time ASC
80+
LIMIT 1
9281
`
9382

94-
func (store datastore) GetMatching(minAge time.Duration) (scans []autoscan.Scan, err error) {
95-
rows, err := store.db.Query(sqlGetMatching, now().Add(-1*minAge))
96-
if errors.Is(err, sql.ErrNoRows) {
97-
return scans, nil
98-
}
99-
100-
if err != nil {
101-
return scans, err
102-
}
103-
104-
defer rows.Close()
105-
for rows.Next() {
106-
scan := autoscan.Scan{}
107-
err = rows.Scan(&scan.Folder, &scan.File, &scan.Priority, &scan.Retries, &scan.Removed, &scan.Time)
108-
if err != nil {
109-
return scans, err
110-
}
83+
func (store *datastore) GetAvailableScan(minAge time.Duration) (autoscan.Scan, error) {
84+
row := store.QueryRow(sqlGetAvailableScan, now().Add(-1*minAge))
11185

112-
scans = append(scans, scan)
86+
scan := autoscan.Scan{}
87+
err := row.Scan(&scan.Folder, &scan.Priority, &scan.Time)
88+
switch {
89+
case errors.Is(err, sql.ErrNoRows):
90+
return scan, autoscan.ErrNoScans
91+
case err != nil:
92+
return scan, fmt.Errorf("get matching: %s: %w", err, autoscan.ErrFatal)
11393
}
11494

115-
return scans, rows.Err()
116-
}
117-
118-
const sqlIncrementRetries = `
119-
UPDATE scan
120-
SET retries = retries + 1, time = ?
121-
WHERE folder = ?
122-
`
123-
124-
// Increment the retry count of all the children of a folder.
125-
// Furthermore, we also update the timestamp to the current time
126-
// so the children will not get scanned for 5 minutes.
127-
func (store datastore) incrementRetries(tx *sql.Tx, folder string) error {
128-
_, err := tx.Exec(sqlIncrementRetries, now(), folder)
129-
return err
130-
}
131-
132-
const sqlDeleteRetries = `
133-
DELETE FROM scan
134-
WHERE folder = ? AND retries > ?
135-
`
136-
137-
func (store datastore) deleteRetries(tx *sql.Tx, folder string, maxRetries int) error {
138-
_, err := tx.Exec(sqlDeleteRetries, folder, maxRetries)
139-
return err
140-
}
141-
142-
func (store datastore) Retry(folder string, maxRetries int) error {
143-
tx, err := store.db.Begin()
144-
if err != nil {
145-
return err
146-
}
147-
148-
err = store.incrementRetries(tx, folder)
149-
if err != nil {
150-
if rbErr := tx.Rollback(); rbErr != nil {
151-
panic(rbErr)
152-
}
153-
154-
return err
155-
}
156-
157-
err = store.deleteRetries(tx, folder, maxRetries)
158-
if err != nil {
159-
if rbErr := tx.Rollback(); rbErr != nil {
160-
panic(rbErr)
161-
}
162-
163-
return err
164-
}
165-
166-
return tx.Commit()
95+
return scan, nil
16796
}
16897

16998
const sqlGetAll = `
170-
SELECT folder, file, priority, retries, removed, time FROM scan
99+
SELECT folder, priority, time FROM scan
171100
`
172101

173-
func (store datastore) GetAll() (scans []autoscan.Scan, err error) {
174-
rows, err := store.db.Query(sqlGetAll)
175-
if errors.Is(err, sql.ErrNoRows) {
176-
return scans, nil
177-
}
178-
102+
func (store *datastore) GetAll() (scans []autoscan.Scan, err error) {
103+
rows, err := store.Query(sqlGetAll)
179104
if err != nil {
180105
return scans, err
181106
}
182107

183108
defer rows.Close()
184109
for rows.Next() {
185110
scan := autoscan.Scan{}
186-
err = rows.Scan(&scan.Folder, &scan.File, &scan.Priority, &scan.Retries, &scan.Removed, &scan.Time)
111+
err = rows.Scan(&scan.Folder, &scan.Priority, &scan.Time)
187112
if err != nil {
188113
return scans, err
189114
}
@@ -195,32 +120,16 @@ func (store datastore) GetAll() (scans []autoscan.Scan, err error) {
195120
}
196121

197122
const sqlDelete = `
198-
DELETE FROM scan
199-
WHERE folder=? AND file=?
123+
DELETE FROM scan WHERE folder=?
200124
`
201125

202-
func (store datastore) delete(tx *sql.Tx, scan autoscan.Scan) error {
203-
_, err := tx.Exec(sqlDelete, scan.Folder, scan.File)
204-
return err
205-
}
206-
207-
func (store datastore) Delete(scans []autoscan.Scan) error {
208-
tx, err := store.db.Begin()
126+
func (store *datastore) Delete(scan autoscan.Scan) error {
127+
_, err := store.Exec(sqlDelete, scan.Folder)
209128
if err != nil {
210-
return err
129+
return fmt.Errorf("delete: %s: %w", err, autoscan.ErrFatal)
211130
}
212131

213-
for _, scan := range scans {
214-
if err = store.delete(tx, scan); err != nil {
215-
if rollbackErr := tx.Rollback(); rollbackErr != nil {
216-
panic(rollbackErr)
217-
}
218-
219-
return err
220-
}
221-
}
222-
223-
return tx.Commit()
132+
return nil
224133
}
225134

226135
var now = time.Now

0 commit comments

Comments
 (0)