cl.event.L = cl.locker()
storageImpl := cfg.DefaultStorage
if storageImpl == nil {
- // We'd use mmap but HFS+ doesn't support sparse files.
- storageImpl = storage.NewFile(cfg.DataDir)
+ // We'd use mmap by default but HFS+ doesn't support sparse files.
+ storageImplCloser := storage.NewFile(cfg.DataDir)
cl.onClose = append(cl.onClose, func() {
- if err := storageImpl.Close(); err != nil {
+ if err := storageImplCloser.Close(); err != nil {
cl.logger.Printf("error closing default storage: %s", err)
}
})
+ storageImpl = storageImplCloser
}
cl.defaultStorage = storage.NewClient(storageImpl)
if cfg.IPBlocklist != nil {
}
}
-func fileCachePieceResourceStorage(fc *filecache.Cache) storage.ClientImpl {
+func fileCachePieceResourceStorage(fc *filecache.Cache) storage.ClientImplCloser {
return storage.NewResourcePieces(fc.AsResourceProvider())
}
}
}
-func testAddTorrentPriorPieceCompletion(t *testing.T, alreadyCompleted bool, csf func(*filecache.Cache) storage.ClientImpl) {
+func testAddTorrentPriorPieceCompletion(t *testing.T, alreadyCompleted bool, csf func(*filecache.Cache) storage.ClientImplCloser) {
fileCacheDir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(fileCacheDir)
DisableTCP bool `long:"disable-tcp"`
// Called to instantiate storage for each added torrent. Builtin backends
// are in the storage package. If not set, the "file" implementation is
- // used.
+ // used (and Closed when the Client is Closed).
DefaultStorage storage.ClientImpl
HeaderObfuscationPolicy HeaderObfuscationPolicy
ih metainfo.Hash
}
-func NewBoltDB(filePath string) ClientImpl {
+func NewBoltDB(filePath string) ClientImplCloser {
db, err := bolt.Open(filepath.Join(filePath, "bolt.db"), 0600, &bolt.Options{
Timeout: time.Second,
})
}
// All Torrent data stored in this baseDir
-func NewFile(baseDir string) ClientImpl {
+func NewFile(baseDir string) ClientImplCloser {
return NewFileWithCompletion(baseDir, pieceCompletionForDir(baseDir))
}
-func NewFileWithCompletion(baseDir string, completion PieceCompletion) ClientImpl {
+func NewFileWithCompletion(baseDir string, completion PieceCompletion) *fileClientImpl {
return newFileWithCustomPathMakerAndCompletion(baseDir, nil, completion)
}
return newFileWithCustomPathMakerAndCompletion(baseDir, pathMaker, pieceCompletionForDir(baseDir))
}
-func newFileWithCustomPathMakerAndCompletion(baseDir string, pathMaker func(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string, completion PieceCompletion) ClientImpl {
+func newFileWithCustomPathMakerAndCompletion(baseDir string, pathMaker func(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string, completion PieceCompletion) *fileClientImpl {
if pathMaker == nil {
pathMaker = defaultPathMaker
}
"github.com/anacrolix/torrent/metainfo"
)
+type ClientImplCloser interface {
+ ClientImpl
+ Close() error
+}
+
// Represents data storage for an unspecified torrent.
type ClientImpl interface {
OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (TorrentImpl, error)
- Close() error
}
// Data storage bound to a torrent.
"github.com/anacrolix/torrent/metainfo"
)
-func testMarkedCompleteMissingOnRead(t *testing.T, csf func(string) ClientImpl) {
+func testMarkedCompleteMissingOnRead(t *testing.T, csf func(string) ClientImplCloser) {
td, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(td)
pc PieceCompletion
}
-func NewMMap(baseDir string) ClientImpl {
+func NewMMap(baseDir string) ClientImplCloser {
return NewMMapWithCompletion(baseDir, pieceCompletionForDir(baseDir))
}
-func NewMMapWithCompletion(baseDir string, completion PieceCompletion) ClientImpl {
+func NewMMapWithCompletion(baseDir string, completion PieceCompletion) *mmapClientImpl {
return &mmapClientImpl{
baseDir: baseDir,
pc: completion,
p resource.Provider
}
-func NewResourcePieces(p resource.Provider) ClientImpl {
+func NewResourcePieces(p resource.Provider) ClientImplCloser {
return &piecePerResource{
p: p,
}
return t.info
}
-// Returns a Reader bound to the torrent's data. All read calls block until
-// the data requested is actually available.
+// Returns a Reader bound to the torrent's data. All read calls block until the data requested is
+// actually available. Note that you probably want to ensure the Torrent Info is available first.
func (t *Torrent) NewReader() Reader {
r := reader{
mu: t.cl.locker(),
Readahead int64
SetReadahead bool
ExportClientStatus bool
- LeecherStorage func(string) storage.ClientImpl
- SeederStorage func(string) storage.ClientImpl
+ LeecherStorage func(string) storage.ClientImplCloser
+ SeederStorage func(string) storage.ClientImplCloser
SeederUploadRateLimiter *rate.Limiter
LeecherDownloadRateLimiter *rate.Limiter
ConfigureSeeder ConfigureClient
}
// cfg.ListenAddr = "localhost:4000"
if ps.SeederStorage != nil {
- cfg.DefaultStorage = ps.SeederStorage(greetingTempDir)
- defer cfg.DefaultStorage.Close()
+ storage := ps.SeederStorage(greetingTempDir)
+ defer storage.Close()
+ cfg.DefaultStorage = storage
} else {
cfg.DataDir = greetingTempDir
}
if ps.LeecherStorage == nil {
cfg.DataDir = leecherDataDir
} else {
- cfg.DefaultStorage = ps.LeecherStorage(leecherDataDir)
+ storage := ps.LeecherStorage(leecherDataDir)
+ defer storage.Close()
+ cfg.DefaultStorage = storage
}
if ps.LeecherDownloadRateLimiter != nil {
cfg.DownloadRateLimiter = ps.LeecherDownloadRateLimiter
type fileCacheClientStorageFactoryParams struct {
Capacity int64
SetCapacity bool
- Wrapper func(*filecache.Cache) storage.ClientImpl
+ Wrapper func(*filecache.Cache) storage.ClientImplCloser
}
func newFileCacheClientStorageFactory(ps fileCacheClientStorageFactoryParams) storageFactory {
- return func(dataDir string) storage.ClientImpl {
+ return func(dataDir string) storage.ClientImplCloser {
fc, err := filecache.NewCache(dataDir)
if err != nil {
panic(err)
}
}
-type storageFactory func(string) storage.ClientImpl
+type storageFactory func(string) storage.ClientImplCloser
func TestClientTransferDefault(t *testing.T) {
testClientTransfer(t, testClientTransferParams{
})
}
-func fileCachePieceResourceStorage(fc *filecache.Cache) storage.ClientImpl {
+func fileCachePieceResourceStorage(fc *filecache.Cache) storage.ClientImplCloser {
return storage.NewResourcePieces(fc.AsResourceProvider())
}
// Seeder storage
for _, ss := range []struct {
name string
- f func(string) storage.ClientImpl
+ f func(string) storage.ClientImplCloser
}{
{"File", storage.NewFile},
{"Mmap", storage.NewMMap},