metainfo.InfoEx.Hash becomes a function, UpdateBytes is added, and Bytes used in marshalling

Fixes #80.
This commit is contained in:
Matt Joiner 2016-05-05 22:40:38 +10:00
parent 533f01147d
commit 2d160b0419
10 changed files with 70 additions and 74 deletions

View File

@ -1465,7 +1465,7 @@ func (cl *Client) saveTorrentFile(t *Torrent) error {
// 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
@ -1570,7 +1570,7 @@ func (cl *Client) torrentCacheMetaInfo(ih metainfo.Hash) (mi *metainfo.MetaInfo,
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
}
@ -1610,15 +1610,13 @@ func TorrentSpecFromMetaInfo(mi *metainfo.MetaInfo) (spec *TorrentSpec) {
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
}

View File

@ -86,10 +86,7 @@ func TestPieceHashSize(t *testing.T) {
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.
@ -637,9 +634,9 @@ func TestAddTorrentSpecMerging(t *testing.T) {
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())
@ -664,17 +661,16 @@ func TestAddTorrentMetainfoInCache(t *testing.T) {
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.
@ -686,9 +682,9 @@ func TestTorrentDroppedBeforeGotInfo(t *testing.T) {
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 {

View File

@ -38,7 +38,7 @@ func main() {
"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(),
}

View File

@ -173,7 +173,7 @@ func TestDownloadOnDemand(t *testing.T) {
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,

View File

@ -6,7 +6,6 @@
package testutil
import (
"crypto/sha1"
"fmt"
"io"
"io/ioutil"
@ -17,7 +16,6 @@ import (
"github.com/anacrolix/missinggo"
"github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/metainfo"
)
@ -44,10 +42,7 @@ func GreetingMetaInfo() (mi *metainfo.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
}

43
metainfo/infoex.go Normal file
View File

@ -0,0 +1,43 @@
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
}

View File

@ -11,8 +11,6 @@ import (
"strings"
"time"
"github.com/anacrolix/missinggo"
"github.com/anacrolix/torrent/bencode"
)
@ -183,34 +181,6 @@ func (info *Info) UpvertedFiles() []FileInfo {
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"`
@ -236,7 +206,7 @@ func (mi *MetaInfo) SetDefaults() {
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 {
@ -244,6 +214,6 @@ func (mi *MetaInfo) Magnet() (m Magnet) {
}
}
m.DisplayName = mi.Info.Name
m.InfoHash = mi.Info.Hash
m.InfoHash = mi.Info.Hash()
return
}

View File

@ -15,9 +15,7 @@ import (
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)
@ -33,13 +31,10 @@ func testFile(t *testing.T, filename string) {
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) {

View File

@ -41,15 +41,15 @@ func TestNodesListPairsBEP5(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"},
})
}

View File

@ -225,7 +225,6 @@ func (t *Torrent) setMetadata(md *metainfo.Info, infoBytes []byte) (err error) {
t.info = &metainfo.InfoEx{
Info: *md,
Bytes: infoBytes,
Hash: t.infoHash,
}
t.storage, err = t.storageOpener.OpenTorrent(t.info)
if err != nil {