github.com/anacrolix/torrent@v1.61.0/storage/sqlite-piece-completion.go (about)

     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  	sqlite "github.com/go-llsqlite/adapter"
    15  	"github.com/go-llsqlite/adapter/sqlitex"
    16  
    17  	"github.com/anacrolix/torrent/metainfo"
    18  )
    19  
    20  // sqlite is always the default when available.
    21  func NewDefaultPieceCompletionForDir(dir string) (PieceCompletion, error) {
    22  	return NewSqlitePieceCompletion(dir)
    23  }
    24  
    25  type sqlitePieceCompletion struct {
    26  	mu     sync.Mutex
    27  	closed bool
    28  	db     *sqlite.Conn
    29  }
    30  
    31  func (me *sqlitePieceCompletion) Persistent() bool {
    32  	return true
    33  }
    34  
    35  var _ PieceCompletion = (*sqlitePieceCompletion)(nil)
    36  
    37  func NewSqlitePieceCompletion(dir string) (ret *sqlitePieceCompletion, err error) {
    38  	p := filepath.Join(dir, ".torrent.db")
    39  	db, err := sqlite.OpenConn(p, 0)
    40  	if err != nil {
    41  		return
    42  	}
    43  	err = sqlitex.ExecScript(db, `create table if not exists piece_completion(infohash, "index", complete, unique(infohash, "index"))`)
    44  	if err != nil {
    45  		db.Close()
    46  		return
    47  	}
    48  	ret = &sqlitePieceCompletion{db: db}
    49  	return
    50  }
    51  
    52  func (me *sqlitePieceCompletion) Get(pk metainfo.PieceKey) (c Completion, err error) {
    53  	me.mu.Lock()
    54  	defer me.mu.Unlock()
    55  	if me.closed {
    56  		err = errors.New("closed")
    57  		return
    58  	}
    59  	err = sqlitex.Exec(
    60  		me.db, `select complete from piece_completion where infohash=? and "index"=?`,
    61  		func(stmt *sqlite.Stmt) error {
    62  			c.Complete = stmt.ColumnInt(0) != 0
    63  			c.Ok = true
    64  			return nil
    65  		},
    66  		pk.InfoHash.HexString(), pk.Index)
    67  	return
    68  }
    69  
    70  func (me *sqlitePieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
    71  	me.mu.Lock()
    72  	defer me.mu.Unlock()
    73  	if me.closed {
    74  		return errors.New("closed")
    75  	}
    76  	return sqlitex.Exec(
    77  		me.db,
    78  		`insert or replace into piece_completion(infohash, "index", complete) values(?, ?, ?)`,
    79  		nil,
    80  		pk.InfoHash.HexString(), pk.Index, b)
    81  }
    82  
    83  func (me *sqlitePieceCompletion) Close() (err error) {
    84  	me.mu.Lock()
    85  	defer me.mu.Unlock()
    86  	if me.closed {
    87  		return
    88  	}
    89  	err = me.db.Close()
    90  	me.db = nil
    91  	me.closed = true
    92  	return
    93  }