Fixes #80.
// able to save the torrent, but not load it again to check it.
return nil
}
- if !bytes.Equal(mi.Info.Hash.Bytes(), t.infoHash[:]) {
+ if mi.Info.Hash() != t.infoHash {
log.Fatalf("%x != %x", mi.Info.Hash, t.infoHash[:])
}
return nil
if err != nil {
return
}
- if !bytes.Equal(mi.Info.Hash.Bytes(), ih[:]) {
+ if mi.Info.Hash() != ih {
err = fmt.Errorf("cached torrent has wrong infohash: %x != %x", mi.Info.Hash, ih[:])
return
}
Trackers: mi.AnnounceList,
Info: &mi.Info,
DisplayName: mi.Info.Name,
+ InfoHash: mi.Info.Hash(),
}
-
if len(spec.Trackers) == 0 {
spec.Trackers = [][]string{[]string{mi.Announce}}
} else {
spec.Trackers[0] = append(spec.Trackers[0], mi.Announce)
}
-
- missinggo.CopyExact(&spec.InfoHash, mi.Info.Hash)
return
}
func TestTorrentInitialState(t *testing.T) {
dir, mi := testutil.GreetingTestTorrent()
defer os.RemoveAll(dir)
- tor := newTorrent(func() (ih metainfo.Hash) {
- missinggo.CopyExact(ih[:], mi.Info.Hash)
- return
- }())
+ tor := newTorrent(mi.Info.Hash())
tor.chunkSize = 2
tor.storageOpener = storage.NewFile(dir)
// Needed to lock for asynchronous piece verification.
defer cl.Close()
dir, mi := testutil.GreetingTestTorrent()
defer os.RemoveAll(dir)
- var ts TorrentSpec
- missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
- tt, new, err := cl.AddTorrentSpec(&ts)
+ tt, new, err := cl.AddTorrentSpec(&TorrentSpec{
+ InfoHash: mi.Info.Hash(),
+ })
require.NoError(t, err)
require.True(t, new)
require.Nil(t, tt.Info())
require.NoError(t, err)
require.True(t, new)
require.NotNil(t, tt.Info())
- _, err = os.Stat(filepath.Join(cfg.ConfigDir, "torrents", fmt.Sprintf("%x.torrent", mi.Info.Hash.Bytes())))
+ _, err = os.Stat(filepath.Join(cfg.ConfigDir, "torrents", fmt.Sprintf("%x.torrent", mi.Info.Hash())))
require.NoError(t, err)
- // Contains only the infohash.
- var ts TorrentSpec
- missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
- _, ok := cl.Torrent(ts.InfoHash)
+ _, ok := cl.Torrent(mi.Info.Hash())
require.True(t, ok)
tt.Drop()
- _, ok = cl.Torrent(ts.InfoHash)
+ _, ok = cl.Torrent(mi.Info.Hash())
require.False(t, ok)
- tt, new, err = cl.AddTorrentSpec(&ts)
+ tt, new, err = cl.AddTorrentSpec(&TorrentSpec{
+ InfoHash: mi.Info.Hash(),
+ })
require.NoError(t, err)
require.True(t, new)
// Obtained from the metainfo cache.
os.RemoveAll(dir)
cl, _ := NewClient(&TestingConfig)
defer cl.Close()
- var ts TorrentSpec
- missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
- tt, _, _ := cl.AddTorrentSpec(&ts)
+ tt, _, _ := cl.AddTorrentSpec(&TorrentSpec{
+ InfoHash: mi.Info.Hash(),
+ })
tt.Drop()
assert.EqualValues(t, 0, len(cl.Torrents()))
select {
"Name": info.Name,
"NumPieces": info.NumPieces(),
"PieceLength": info.PieceLength,
- "InfoHash": metainfo.Info.Hash.HexString(),
+ "InfoHash": metainfo.Info.Hash().HexString(),
"NumFiles": len(info.UpvertedFiles()),
"TotalLength": info.TotalLength(),
}
require.NoError(t, err)
defer seeder.Close()
testutil.ExportStatusWriter(seeder, "s")
- _, err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%s", layout.Metainfo.Info.Hash.HexString()))
+ _, err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%s", layout.Metainfo.Info.Hash().HexString()))
require.NoError(t, err)
leecher, err := torrent.NewClient(&torrent.Config{
DisableTrackers: true,
package testutil
import (
- "crypto/sha1"
"fmt"
"io"
"io/ioutil"
"github.com/anacrolix/missinggo"
- "github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/metainfo"
)
if err != nil {
panic(err)
}
- mi.Info.Bytes, _ = bencode.Marshal(&mi.Info.Info)
- h := sha1.New()
- h.Write(mi.Info.Bytes)
- missinggo.CopyExact(&mi.Info.Hash, h.Sum(nil))
+ mi.Info.UpdateBytes()
return
}
--- /dev/null
+package metainfo
+
+import "github.com/anacrolix/torrent/bencode"
+
+// A wrapper around Info that exposes the Bytes directly, in case marshalling
+// and unmarshalling Info doesn't produce the same bytes.
+type InfoEx struct {
+ Info
+ // Set when unmarshalling, and used when marshalling. Call .UpdateBytes to
+ // set it by bencoding Info.
+ Bytes []byte
+}
+
+var (
+ _ bencode.Marshaler = &InfoEx{}
+ _ bencode.Unmarshaler = &InfoEx{}
+)
+
+// Marshals .Info, and sets .Bytes with the result.
+func (ie *InfoEx) UpdateBytes() {
+ var err error
+ ie.Bytes, err = bencode.Marshal(&ie.Info)
+ if err != nil {
+ panic(err)
+ }
+}
+
+// Returns the SHA1 hash of .Bytes.
+func (ie *InfoEx) Hash() Hash {
+ return HashBytes(ie.Bytes)
+}
+
+func (ie *InfoEx) UnmarshalBencode(data []byte) error {
+ ie.Bytes = append([]byte(nil), data...)
+ return bencode.Unmarshal(data, &ie.Info)
+}
+
+func (ie *InfoEx) MarshalBencode() ([]byte, error) {
+ if ie.Bytes == nil {
+ ie.UpdateBytes()
+ }
+ return ie.Bytes, nil
+}
"strings"
"time"
- "github.com/anacrolix/missinggo"
-
"github.com/anacrolix/torrent/bencode"
)
return info.Files
}
-// The info dictionary with its hash and raw bytes exposed, in case
-// remarshalling Info produces a different value.
-type InfoEx struct {
- Info
- Hash Hash // Only set when unmarshalling or UpdateHash.
- Bytes []byte // Only set when unmarshalling or UpdateBytes.
-}
-
-var (
- _ bencode.Marshaler = InfoEx{}
- _ bencode.Unmarshaler = &InfoEx{}
-)
-
-func (ie *InfoEx) UnmarshalBencode(data []byte) error {
- ie.Bytes = append([]byte(nil), data...)
- h := sha1.New()
- _, err := h.Write(ie.Bytes)
- if err != nil {
- panic(err)
- }
- missinggo.CopyExact(&ie.Hash, h.Sum(nil))
- return bencode.Unmarshal(data, &ie.Info)
-}
-
-func (ie InfoEx) MarshalBencode() ([]byte, error) {
- return bencode.Marshal(&ie.Info)
-}
-
type MetaInfo struct {
Info InfoEx `bencode:"info"`
Announce string `bencode:"announce,omitempty"`
mi.Info.PieceLength = 256 * 1024
}
-// Magnetize creates a Magnet from a MetaInfo.
+// Creates a Magnet from a MetaInfo.
func (mi *MetaInfo) Magnet() (m Magnet) {
for _, tier := range mi.AnnounceList {
for _, tracker := range tier {
}
}
m.DisplayName = mi.Info.Name
- m.InfoHash = mi.Info.Hash
+ m.InfoHash = mi.Info.Hash()
return
}
func testFile(t *testing.T, filename string) {
mi, err := LoadFromFile(filename)
- if err != nil {
- t.Fatal(err)
- }
+ require.NoError(t, err)
if len(mi.Info.Files) == 1 {
t.Logf("Single file: %s (length: %d)\n", mi.Info.Name, mi.Info.Files[0].Length)
t.Logf("Tracker: %s\n", tracker)
}
}
- // for _, url := range mi.WebSeedURLs {
- // t.Logf("URL: %s\n", url)
- // }
- b, err := bencode.Marshal(mi.Info)
+ b, err := bencode.Marshal(&mi.Info.Info)
require.NoError(t, err)
- assert.EqualValues(t, b, mi.Info.Bytes)
+ assert.EqualValues(t, string(b), string(mi.Info.Bytes))
}
func TestFile(t *testing.T) {
})
}
-func testMarshalMetainfo(t *testing.T, expected string, mi MetaInfo) {
+func testMarshalMetainfo(t *testing.T, expected string, mi *MetaInfo) {
b, err := bencode.Marshal(mi)
assert.NoError(t, err)
assert.EqualValues(t, expected, string(b))
}
func TestMarshalMetainfoNodes(t *testing.T) {
- testMarshalMetainfo(t, "d4:infod4:name0:12:piece lengthi0e6:piecesleee", MetaInfo{})
- testMarshalMetainfo(t, "d4:infod4:name0:12:piece lengthi0e6:pieceslee5:nodesl12:1.2.3.4:555514:not a hostportee", MetaInfo{
+ testMarshalMetainfo(t, "d4:infod4:name0:12:piece lengthi0e6:piecesleee", &MetaInfo{})
+ testMarshalMetainfo(t, "d4:infod4:name0:12:piece lengthi0e6:pieceslee5:nodesl12:1.2.3.4:555514:not a hostportee", &MetaInfo{
Nodes: []Node{"1.2.3.4:5555", "not a hostport"},
})
}
t.info = &metainfo.InfoEx{
Info: *md,
Bytes: infoBytes,
- Hash: t.infoHash,
}
t.storage, err = t.storageOpener.OpenTorrent(t.info)
if err != nil {