// Return a Torrent ready for insertion into a Client.
func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) (t *Torrent) {
+ return cl.newTorrentOpt(addTorrentOpts{
+ InfoHash: ih,
+ Storage: specStorage,
+ })
+}
+
+// Return a Torrent ready for insertion into a Client.
+func (cl *Client) newTorrentOpt(opts addTorrentOpts) (t *Torrent) {
// use provided storage, if provided
storageClient := cl.defaultStorage
- if specStorage != nil {
- storageClient = storage.NewClient(specStorage)
+ if opts.Storage != nil {
+ storageClient = storage.NewClient(opts.Storage)
}
t = &Torrent{
cl: cl,
- infoHash: ih,
+ infoHash: opts.InfoHash,
peers: prioritizedPeers{
om: btree.New(32),
getPrio: func(p PeerInfo) peerPriority {
t.networkingEnabled.Set()
t._pendingPieces.NewSet = priorityBitmapStableNewSet
t.logger = cl.logger.WithContextValue(t)
- t.setChunkSize(defaultChunkSize)
+ if opts.ChunkSize == 0 {
+ opts.ChunkSize = defaultChunkSize
+ }
+ t.setChunkSize(opts.ChunkSize)
return
}
return
}
+// 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) AddTorrentOpt(opts addTorrentOpts) (t *Torrent, new bool) {
+ infoHash := opts.InfoHash
+ cl.lock()
+ defer cl.unlock()
+ t, ok := cl.torrents[infoHash]
+ if ok {
+ return
+ }
+ new = true
+
+ t = cl.newTorrentOpt(opts)
+ cl.eachDhtServer(func(s DhtServer) {
+ if cl.config.PeriodicallyAnnounceTorrentsToDht {
+ go t.dhtAnnouncer(s)
+ }
+ })
+ cl.torrents[infoHash] = t
+ cl.clearAcceptLimits()
+ t.updateWantPeersEvent()
+ // Tickle Client.waitAccept, new torrent may want conns.
+ cl.event.Broadcast()
+ return
+}
+
+type addTorrentOpts struct {
+ InfoHash InfoHash
+ Storage storage.ClientImpl
+ ChunkSize pp.Integer
+}
+
// Add or merge a torrent spec. Returns new if the torrent wasn't already in the client. See also
// Torrent.MergeSpec.
func (cl *Client) AddTorrentSpec(spec *TorrentSpec) (t *Torrent, new bool, err error) {
- t, new = cl.AddTorrentInfoHashWithStorage(spec.InfoHash, spec.Storage)
- err = t.MergeSpec(spec)
+ t, new = cl.AddTorrentOpt(addTorrentOpts{
+ InfoHash: spec.InfoHash,
+ Storage: spec.Storage,
+ ChunkSize: spec.ChunkSize,
+ })
+ modSpec := *spec
+ if new {
+ // ChunkSize was already applied by adding a new Torrent, and MergeSpec disallows changing
+ // it.
+ modSpec.ChunkSize = 0
+ }
+ err = t.MergeSpec(&modSpec)
if err != nil && new {
t.Drop()
}
})
}
if spec.ChunkSize != 0 {
- t.setChunkSize(pp.Integer(spec.ChunkSize))
+ panic("chunk size cannot be changed for existing Torrent")
}
t.addTrackers(spec.Trackers)
t.maybeNewConns()
"fmt"
"github.com/anacrolix/torrent/metainfo"
+ pp "github.com/anacrolix/torrent/peer_protocol"
"github.com/anacrolix/torrent/storage"
)
-// Specifies a new torrent for adding to a client. There are helpers for magnet URIs and torrent
-// metainfo files.
+// Specifies a new torrent for adding to a client, or additions to an existing Torrent. There are
+// constructor functions for magnet URIs and torrent metainfo files. TODO: This type should be
+// dismantled into a new Torrent option type, and separate Torrent mutate method(s).
type TorrentSpec struct {
// The tiered tracker URIs.
- Trackers [][]string
+ Trackers [][]string
+ // TODO: Move into a "new" Torrent opt type.
InfoHash metainfo.Hash
InfoBytes []byte
// The name to use if the Name field from the Info isn't available.
// The combination of the "xs" and "as" fields in magnet links, for now.
Sources []string
- // The chunk size to use for outbound requests. Defaults to 16KiB if not set.
- ChunkSize int
+ // The chunk size to use for outbound requests. Defaults to 16KiB if not set. Can only be set
+ // for new Torrents. TODO: Move into a "new" Torrent opt type.
+ ChunkSize pp.Integer
+ // TODO: Move into a "new" Torrent opt type.
+ Storage storage.ClientImpl
+
DisableInitialPieceCheck bool
- Storage storage.ClientImpl
// Whether to allow data download or upload
DisallowDataUpload bool