]> Sergey Matveev's repositories - btrtrc.git/blob - storage/sqlite-piece-completion.go
eb2e1c3d9d47ec29dde5ba22a1d7a9f8f97eda7a
[btrtrc.git] / storage / sqlite-piece-completion.go
1 // modernc.org/sqlite depends on modernc.org/libc which doesn't work for JS (and probably wasm but I
2 // think JS is the stronger signal).
3
4 //go:build cgo && !nosqlite
5 // +build cgo,!nosqlite
6
7 package storage
8
9 import (
10         "errors"
11         "path/filepath"
12         "sync"
13
14         "crawshaw.io/sqlite"
15         "crawshaw.io/sqlite/sqlitex"
16         "github.com/anacrolix/torrent/metainfo"
17 )
18
19 // sqlite is always the default when available.
20 func NewDefaultPieceCompletionForDir(dir string) (PieceCompletion, error) {
21         return NewSqlitePieceCompletion(dir)
22 }
23
24 type sqlitePieceCompletion struct {
25         mu     sync.Mutex
26         closed bool
27         db     *sqlite.Conn
28 }
29
30 var _ PieceCompletion = (*sqlitePieceCompletion)(nil)
31
32 func NewSqlitePieceCompletion(dir string) (ret *sqlitePieceCompletion, err error) {
33         p := filepath.Join(dir, ".torrent.db")
34         db, err := sqlite.OpenConn(p, 0)
35         if err != nil {
36                 return
37         }
38         err = sqlitex.ExecScript(db, `create table if not exists piece_completion(infohash, "index", complete, unique(infohash, "index"))`)
39         if err != nil {
40                 db.Close()
41                 return
42         }
43         ret = &sqlitePieceCompletion{db: db}
44         return
45 }
46
47 func (me *sqlitePieceCompletion) Get(pk metainfo.PieceKey) (c Completion, err error) {
48         me.mu.Lock()
49         defer me.mu.Unlock()
50         err = sqlitex.Exec(
51                 me.db, `select complete from piece_completion where infohash=? and "index"=?`,
52                 func(stmt *sqlite.Stmt) error {
53                         c.Complete = stmt.ColumnInt(0) != 0
54                         c.Ok = true
55                         return nil
56                 },
57                 pk.InfoHash.HexString(), pk.Index)
58         return
59 }
60
61 func (me *sqlitePieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
62         me.mu.Lock()
63         defer me.mu.Unlock()
64         if me.closed {
65                 return errors.New("closed")
66         }
67         return sqlitex.Exec(
68                 me.db,
69                 `insert or replace into piece_completion(infohash, "index", complete) values(?, ?, ?)`,
70                 nil,
71                 pk.InfoHash.HexString(), pk.Index, b)
72 }
73
74 func (me *sqlitePieceCompletion) Close() (err error) {
75         me.mu.Lock()
76         defer me.mu.Unlock()
77         if me.closed {
78                 return
79         }
80         err = me.db.Close()
81         me.db = nil
82         me.closed = true
83         return
84 }