}
// TODO(anacrolix): If this fails, I think something harsher should be
// done.
- err = cl.setMetaData(t, info, t.MetaData)
+ err = cl.setMetaData(t, &info, t.MetaData)
if err != nil {
log.Printf("error setting metadata: %s", err)
t.invalidateMetadata()
type TorrentDataOpener func(*metainfo.Info) data.Data
-func (cl *Client) setMetaData(t *torrent, md metainfo.Info, bytes []byte) (err error) {
+func (cl *Client) setMetaData(t *torrent, md *metainfo.Info, bytes []byte) (err error) {
err = t.setMetadata(md, bytes, &cl.mu)
if err != nil {
return
log.Printf("error saving torrent file for %s: %s", t, err)
}
}
+ cl.event.Broadcast()
if strings.Contains(strings.ToLower(md.Name), "porn") {
cl.dropTorrent(t.InfoHash)
err = errors.New("no porn plx")
return
}
close(t.gotMetainfo)
- td := cl.torrentDataOpener(&md)
+ td := cl.torrentDataOpener(md)
err = cl.setStorage(t, td)
return
}
return
}
-func (cl *Client) AddMagnet(uri string) (T Torrent, err error) {
+// For adding new torrents to a client.
+type TorrentSpec struct {
+ Trackers [][]string
+ InfoHash InfoHash
+ Info *metainfo.InfoEx
+ DisplayName string
+}
+
+func TorrentSpecFromMagnetURI(uri string) (spec *TorrentSpec, err error) {
m, err := ParseMagnetURI(uri)
if err != nil {
return
}
- mi, err := cl.torrentCacheMetaInfo(m.InfoHash)
+ spec = &TorrentSpec{
+ Trackers: [][]string{m.Trackers},
+ DisplayName: m.DisplayName,
+ }
+ CopyExact(&spec.InfoHash, &m.InfoHash)
+ return
+}
+
+func TorrentSpecFromMetaInfo(mi *metainfo.MetaInfo) (spec *TorrentSpec) {
+ spec = &TorrentSpec{
+ Trackers: mi.AnnounceList,
+ Info: &mi.Info,
+ }
+ CopyExact(&spec.InfoHash, &mi.Info.Hash)
+ return
+}
+
+func (cl *Client) AddTorrentSpec(spec *TorrentSpec) (T Torrent, new bool, err error) {
+ T.cl = cl
+ cl.mu.Lock()
+ defer cl.mu.Unlock()
+
+ t, ok := cl.torrents[spec.InfoHash]
+ if ok {
+ T.torrent = t
+ return
+ }
+
+ new = true
+
+ if _, ok := cl.bannedTorrents[spec.InfoHash]; ok {
+ err = errors.New("banned torrent")
+ return
+ }
+
+ t, err = newTorrent(spec.InfoHash)
if err != nil {
- log.Printf("error getting cached metainfo for %x: %s", m.InfoHash[:], err)
- } else if mi != nil {
- _, err = cl.AddTorrent(mi)
+ return
+ }
+ if spec.DisplayName != "" {
+ t.DisplayName = spec.DisplayName
+ }
+ if spec.Info != nil {
+ err = cl.setMetaData(t, &spec.Info.Info, spec.Info.Bytes)
+ } else {
+ var mi *metainfo.MetaInfo
+ mi, err = cl.torrentCacheMetaInfo(spec.InfoHash)
if err != nil {
- return
+ log.Printf("error getting cached metainfo: %s", err)
+ } else if mi != nil {
+ t.addTrackers(mi.AnnounceList)
+ err = cl.setMetaData(t, &mi.Info.Info, mi.Info.Bytes)
}
}
- cl.mu.Lock()
- defer cl.mu.Unlock()
- T, err = cl.addOrMergeTorrent(m.InfoHash, [][]string{m.Trackers})
if err != nil {
return
}
- if m.DisplayName != "" {
- T.DisplayName = m.DisplayName
+
+ cl.torrents[spec.InfoHash] = t
+ T.torrent = t
+
+ T.torrent.pruneTimer = time.AfterFunc(0, func() {
+ cl.pruneConnectionsUnlocked(T.torrent)
+ })
+ t.addTrackers(spec.Trackers)
+ if !cl.disableTrackers {
+ go cl.announceTorrentTrackers(T.torrent)
+ }
+ if cl.dHT != nil {
+ go cl.announceTorrentDHT(T.torrent, true)
}
return
}
return
}
-func (me *Client) addOrMergeTorrent(ih InfoHash, announceList [][]string) (T Torrent, err error) {
- if _, ok := me.bannedTorrents[ih]; ok {
- err = errors.New("banned torrent")
- return
- }
- T.cl = me
- var ok bool
- T.torrent, ok = me.torrents[ih]
- if ok {
- T.torrent.addTrackers(announceList)
- } else {
- T.torrent, err = newTorrent(ih, announceList, me.halfOpenLimit)
- if err != nil {
- return
- }
- me.torrents[ih] = T.torrent
- if !me.disableTrackers {
- go me.announceTorrentTrackers(T.torrent)
- }
- if me.dHT != nil {
- go me.announceTorrentDHT(T.torrent, true)
- }
- T.torrent.pruneTimer = time.AfterFunc(0, func() {
- me.pruneConnectionsUnlocked(T.torrent)
- })
- }
- return
-}
-
-// Adds a torrent to the client.
-func (me *Client) AddTorrent(metaInfo *metainfo.MetaInfo) (t Torrent, err error) {
- var ih InfoHash
- CopyExact(&ih, metaInfo.Info.Hash)
- me.mu.Lock()
- defer me.mu.Unlock()
- t, err = me.addOrMergeTorrent(ih, metaInfo.AnnounceList)
- if err != nil {
- return
- }
- if !t.torrent.haveInfo() {
- err = me.setMetaData(t.torrent, metaInfo.Info.Info, metaInfo.Info.Bytes)
- if err != nil {
- return
- }
- }
- return
-}
-
-func (me *Client) AddTorrentFromFile(name string) (t Torrent, err error) {
- mi, err := metainfo.LoadFromFile(name)
- if err != nil {
- err = fmt.Errorf("error loading metainfo from file: %s", err)
- return
- }
- return me.AddTorrent(mi)
-}
-
// Returns true when peers are required, or false if the torrent is closing.
func (cl *Client) waitWantPeers(t *torrent) bool {
cl.mu.Lock()
me.mu.Unlock()
return
}
+
+func (me *Client) AddMagnet(uri string) (T Torrent, err error) {
+ spec, err := TorrentSpecFromMagnetURI(uri)
+ if err != nil {
+ return
+ }
+ T, _, err = me.AddTorrentSpec(spec)
+ return
+}
+
+func (me *Client) AddTorrent(mi *metainfo.MetaInfo) (T Torrent, err error) {
+ T, _, err = me.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
+ return
+}
+
+func (me *Client) AddTorrentFromFile(filename string) (T Torrent, err error) {
+ mi, err := metainfo.LoadFromFile(filename)
+ if err != nil {
+ return
+ }
+ T, _, err = me.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
+ return
+}
"github.com/anacrolix/libtorgo/bencode"
)
+func init() {
+ log.SetFlags(log.LstdFlags | log.Lshortfile)
+}
+
var TestingConfig = Config{
- ListenAddr: ":0",
+ ListenAddr: "localhost:0",
NoDHT: true,
DisableTrackers: true,
NoDefaultBlocklist: true,
}
func TestClientDefault(t *testing.T) {
- cl, err := NewClient(&Config{
- NoDefaultBlocklist: true,
- ListenAddr: ":0",
- })
+ cl, err := NewClient(&TestingConfig)
if err != nil {
t.Fatal(err)
}
defer cl.Close()
dir, mi := testutil.GreetingTestTorrent()
defer os.RemoveAll(dir)
- tt, err := cl.AddTorrent(mi)
+ tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
if err != nil {
t.Fatal(err)
}
+ if !new {
+ t.FailNow()
+ }
tt.Drop()
}
tor, err := newTorrent(func() (ih InfoHash) {
util.CopyExact(ih[:], mi.Info.Hash)
return
- }(), nil, 0)
+ }())
if err != nil {
t.Fatal(err)
}
- err = tor.setMetadata(mi.Info.Info, mi.Info.Bytes, nil)
+ err = tor.setMetadata(&mi.Info.Info, mi.Info.Bytes, nil)
if err != nil {
t.Fatal(err)
}
func TestTwoClientsArbitraryPorts(t *testing.T) {
for i := 0; i < 2; i++ {
- cl, err := NewClient(&Config{
- ListenAddr: ":0",
- })
+ cl, err := NewClient(&TestingConfig)
if err != nil {
t.Fatal(err)
}
func TestAddDropManyTorrents(t *testing.T) {
cl, _ := NewClient(&TestingConfig)
defer cl.Close()
- var m Magnet
for i := range iter.N(1000) {
- binary.PutVarint(m.InfoHash[:], int64(i))
- cl.AddMagnet(m.String())
+ var spec TorrentSpec
+ binary.PutVarint(spec.InfoHash[:], int64(i))
+ tt, new, err := cl.AddTorrentSpec(&spec)
+ if err != nil {
+ t.Error(err)
+ }
+ if !new {
+ t.FailNow()
+ }
+ defer tt.Drop()
}
}
t.Fatal(err)
}
defer seeder.Close()
- seeder.AddTorrent(mi)
+ seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
leecherDataDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
cfg.TorrentDataOpener = blob.NewStore(leecherDataDir).OpenTorrent
leecher, _ := NewClient(&cfg)
defer leecher.Close()
- leecherGreeting, _ := leecher.AddTorrent(mi)
+ leecherGreeting, _, _ := leecher.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
leecherGreeting.AddPeers([]Peer{
Peer{
IP: util.AddrIP(seeder.ListenAddr()),