Merge pull request #149 from thechriswalker/torrent-storage-options
fix `Spec.Storage` and allow per-torrent dir
This commit is contained in:
commit
2f6744c7ac
23
client.go
23
client.go
|
@ -1124,7 +1124,13 @@ func (cl *Client) badPeerIPPort(ip net.IP, port int) bool {
|
|||
}
|
||||
|
||||
// Return a Torrent ready for insertion into a Client.
|
||||
func (cl *Client) newTorrent(ih metainfo.Hash) (t *Torrent) {
|
||||
func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) (t *Torrent) {
|
||||
// use provided storage, if provided
|
||||
storageClient := cl.defaultStorage
|
||||
if specStorage != nil {
|
||||
storageClient = storage.NewClient(specStorage)
|
||||
}
|
||||
|
||||
t = &Torrent{
|
||||
cl: cl,
|
||||
infoHash: ih,
|
||||
|
@ -1134,7 +1140,7 @@ func (cl *Client) newTorrent(ih metainfo.Hash) (t *Torrent) {
|
|||
halfOpen: make(map[string]struct{}),
|
||||
pieceStateChanges: pubsub.NewPubSub(),
|
||||
|
||||
storageOpener: cl.defaultStorage,
|
||||
storageOpener: storageClient,
|
||||
maxEstablishedConns: defaultEstablishedConnsPerTorrent,
|
||||
}
|
||||
t.setChunkSize(defaultChunkSize)
|
||||
|
@ -1150,6 +1156,13 @@ type Handle interface {
|
|||
}
|
||||
|
||||
func (cl *Client) AddTorrentInfoHash(infoHash metainfo.Hash) (t *Torrent, new bool) {
|
||||
return cl.AddTorrentInfoHashWithStorage(infoHash, nil)
|
||||
}
|
||||
|
||||
// Adds a torrent by InfoHash with a custom Storage implementation.
|
||||
// If the torrent already exists then this Storage is ignored and the
|
||||
// existing torrent returned with `new` set to `false`
|
||||
func (cl *Client) AddTorrentInfoHashWithStorage(infoHash metainfo.Hash, specStorage storage.ClientImpl) (t *Torrent, new bool) {
|
||||
cl.mu.Lock()
|
||||
defer cl.mu.Unlock()
|
||||
t, ok := cl.torrents[infoHash]
|
||||
|
@ -1157,7 +1170,7 @@ func (cl *Client) AddTorrentInfoHash(infoHash metainfo.Hash) (t *Torrent, new bo
|
|||
return
|
||||
}
|
||||
new = true
|
||||
t = cl.newTorrent(infoHash)
|
||||
t = cl.newTorrent(infoHash, specStorage)
|
||||
if cl.dHT != nil {
|
||||
go t.dhtAnnouncer()
|
||||
}
|
||||
|
@ -1172,8 +1185,10 @@ func (cl *Client) AddTorrentInfoHash(infoHash metainfo.Hash) (t *Torrent, new bo
|
|||
// trackers will be merged with the existing ones. If the Info isn't yet
|
||||
// known, it will be set. The display name is replaced if the new spec
|
||||
// provides one. Returns new if the torrent wasn't already in the client.
|
||||
// Note that any `Storage` defined on the spec will be ignored if the
|
||||
// torrent is already present (i.e. `new` return value is `true`)
|
||||
func (cl *Client) AddTorrentSpec(spec *TorrentSpec) (t *Torrent, new bool, err error) {
|
||||
t, new = cl.AddTorrentInfoHash(spec.InfoHash)
|
||||
t, new = cl.AddTorrentInfoHashWithStorage(spec.InfoHash, spec.Storage)
|
||||
if spec.DisplayName != "" {
|
||||
t.SetDisplayName(spec.DisplayName)
|
||||
}
|
||||
|
|
|
@ -13,14 +13,39 @@ import (
|
|||
// File-based storage for torrents, that isn't yet bound to a particular
|
||||
// torrent.
|
||||
type fileClientImpl struct {
|
||||
baseDir string
|
||||
pc pieceCompletion
|
||||
baseDir string
|
||||
pathMaker func(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string
|
||||
pc pieceCompletion
|
||||
}
|
||||
|
||||
// The Default path maker just returns the current path
|
||||
func defaultPathMaker(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string {
|
||||
return baseDir
|
||||
}
|
||||
|
||||
func infoHashPathMaker(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string {
|
||||
return filepath.Join(baseDir, infoHash.HexString())
|
||||
}
|
||||
|
||||
// All Torrent data stored in this baseDir
|
||||
func NewFile(baseDir string) ClientImpl {
|
||||
return NewFileWithCustomPathMaker(baseDir, nil)
|
||||
}
|
||||
|
||||
// All Torrent data stored in subdirectorys by infohash
|
||||
func NewFileByInfoHash(baseDir string) ClientImpl {
|
||||
return NewFileWithCustomPathMaker(baseDir, infoHashPathMaker)
|
||||
}
|
||||
|
||||
// Allows passing a function to determine the path for storing torrent data
|
||||
func NewFileWithCustomPathMaker(baseDir string, pathMaker func(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string) ClientImpl {
|
||||
if pathMaker == nil {
|
||||
pathMaker = defaultPathMaker
|
||||
}
|
||||
return &fileClientImpl{
|
||||
baseDir: baseDir,
|
||||
pc: pieceCompletionForDir(baseDir),
|
||||
baseDir: baseDir,
|
||||
pathMaker: pathMaker,
|
||||
pc: pieceCompletionForDir(baseDir),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,12 +54,13 @@ func (me *fileClientImpl) Close() error {
|
|||
}
|
||||
|
||||
func (fs *fileClientImpl) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (TorrentImpl, error) {
|
||||
err := CreateNativeZeroLengthFiles(info, fs.baseDir)
|
||||
dir := fs.pathMaker(fs.baseDir, info, infoHash)
|
||||
err := CreateNativeZeroLengthFiles(info, dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &fileTorrentImpl{
|
||||
fs,
|
||||
dir,
|
||||
info,
|
||||
infoHash,
|
||||
fs.pc,
|
||||
|
@ -43,7 +69,7 @@ func (fs *fileClientImpl) OpenTorrent(info *metainfo.Info, infoHash metainfo.Has
|
|||
|
||||
// File-based torrent storage, not yet bound to a Torrent.
|
||||
type fileTorrentImpl struct {
|
||||
fs *fileClientImpl
|
||||
dir string
|
||||
info *metainfo.Info
|
||||
infoHash metainfo.Hash
|
||||
completion pieceCompletion
|
||||
|
@ -68,12 +94,12 @@ func (fs *fileTorrentImpl) Close() error {
|
|||
// Creates natives files for any zero-length file entries in the info. This is
|
||||
// a helper for file-based storages, which don't address or write to zero-
|
||||
// length files because they have no corresponding pieces.
|
||||
func CreateNativeZeroLengthFiles(info *metainfo.Info, baseDir string) (err error) {
|
||||
func CreateNativeZeroLengthFiles(info *metainfo.Info, dir string) (err error) {
|
||||
for _, fi := range info.UpvertedFiles() {
|
||||
if fi.Length != 0 {
|
||||
continue
|
||||
}
|
||||
name := filepath.Join(append([]string{baseDir, info.Name}, fi.Path...)...)
|
||||
name := filepath.Join(append([]string{dir, info.Name}, fi.Path...)...)
|
||||
os.MkdirAll(filepath.Dir(name), 0750)
|
||||
var f io.Closer
|
||||
f, err = os.Create(name)
|
||||
|
@ -181,5 +207,5 @@ func (fst fileTorrentImplIO) WriteAt(p []byte, off int64) (n int, err error) {
|
|||
}
|
||||
|
||||
func (fts *fileTorrentImpl) fileInfoName(fi metainfo.FileInfo) string {
|
||||
return filepath.Join(append([]string{fts.fs.baseDir, fts.info.Name}, fi.Path...)...)
|
||||
return filepath.Join(append([]string{fts.dir, fts.info.Name}, fi.Path...)...)
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ func TestTorrentString(t *testing.T) {
|
|||
// piece priorities everytime a reader (possibly in another Torrent) changed.
|
||||
func BenchmarkUpdatePiecePriorities(b *testing.B) {
|
||||
cl := &Client{}
|
||||
t := cl.newTorrent(metainfo.Hash{})
|
||||
t := cl.newTorrent(metainfo.Hash{}, nil)
|
||||
t.info = &metainfo.Info{
|
||||
Pieces: make([]byte, 20*13410),
|
||||
PieceLength: 256 << 10,
|
||||
|
|
Loading…
Reference in New Issue