Expose MetaData directly so it can be bencoded from external packages
This commit is contained in:
parent
a44d2d88c3
commit
9d72fd024e
|
@ -344,7 +344,7 @@ func (b *Batch) Start(w io.Writer, nworkers int) (<-chan error, <-chan int64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Batch) write_torrent(w io.Writer) error {
|
func (b *Batch) write_torrent(w io.Writer) error {
|
||||||
var td torrent_data
|
var td MetaInfo
|
||||||
td.Announce = b.announce_list[0][0]
|
td.Announce = b.announce_list[0][0]
|
||||||
if len(b.announce_list) != 1 || len(b.announce_list[0]) != 1 {
|
if len(b.announce_list) != 1 || len(b.announce_list[0]) != 1 {
|
||||||
td.AnnounceList = b.announce_list
|
td.AnnounceList = b.announce_list
|
||||||
|
|
|
@ -2,75 +2,26 @@ package metainfo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"errors"
|
|
||||||
"github.com/nsf/libtorgo/bencode"
|
"github.com/nsf/libtorgo/bencode"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Information specific to a single file inside the MetaInfo structure..
|
// Information specific to a single file inside the MetaInfo structure.
|
||||||
type FileInfo struct {
|
type FileInfo struct {
|
||||||
Length int64 `bencode:"length"`
|
Length int64 `bencode:"length"`
|
||||||
Path []string `bencode:"path"`
|
Path []string `bencode:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetaInfo is the type you should use when reading torrent files. See Load and
|
|
||||||
// LoadFromFile functions. All the fields are intended to be read-only. If
|
|
||||||
// 'len(Files) == 1', then the FileInfo.Path is nil in that entry.
|
|
||||||
type MetaInfo struct {
|
|
||||||
Info
|
|
||||||
InfoHash []byte
|
|
||||||
AnnounceList [][]string
|
|
||||||
CreationDate time.Time
|
|
||||||
Comment string
|
|
||||||
CreatedBy string
|
|
||||||
Encoding string
|
|
||||||
WebSeedURLs []string
|
|
||||||
InfoBytes []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load a MetaInfo from an io.Reader. Returns a non-nil error in case of
|
// Load a MetaInfo from an io.Reader. Returns a non-nil error in case of
|
||||||
// failure.
|
// failure.
|
||||||
func Load(r io.Reader) (*MetaInfo, error) {
|
func Load(r io.Reader) (*MetaInfo, error) {
|
||||||
var mi MetaInfo
|
var mi MetaInfo
|
||||||
var data torrent_data
|
|
||||||
d := bencode.NewDecoder(r)
|
d := bencode.NewDecoder(r)
|
||||||
err := d.Decode(&data)
|
err := d.Decode(&mi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mi.Info = data.Info.Info
|
|
||||||
mi.InfoBytes = data.Info.Bytes
|
|
||||||
mi.InfoHash = data.Info.Hash
|
|
||||||
if len(data.AnnounceList) > 0 {
|
|
||||||
mi.AnnounceList = data.AnnounceList
|
|
||||||
} else {
|
|
||||||
mi.AnnounceList = [][]string{[]string{data.Announce}}
|
|
||||||
}
|
|
||||||
mi.CreationDate = time.Unix(data.CreationDate, 0)
|
|
||||||
mi.Comment = data.Comment
|
|
||||||
mi.CreatedBy = data.CreatedBy
|
|
||||||
mi.Encoding = data.Encoding
|
|
||||||
if data.URLList != nil {
|
|
||||||
switch v := data.URLList.(type) {
|
|
||||||
case string:
|
|
||||||
mi.WebSeedURLs = []string{v}
|
|
||||||
case []interface{}:
|
|
||||||
var ok bool
|
|
||||||
ss := make([]string, len(v))
|
|
||||||
for i, s := range v {
|
|
||||||
ss[i], ok = s.(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("bad url-list data type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mi.WebSeedURLs = ss
|
|
||||||
default:
|
|
||||||
return nil, errors.New("bad url-list data type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &mi, nil
|
return &mi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +35,7 @@ func LoadFromFile(filename string) (*MetaInfo, error) {
|
||||||
return Load(f)
|
return Load(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The info dictionary.
|
||||||
type Info struct {
|
type Info struct {
|
||||||
PieceLength int64 `bencode:"piece length"`
|
PieceLength int64 `bencode:"piece length"`
|
||||||
Pieces []byte `bencode:"pieces"`
|
Pieces []byte `bencode:"pieces"`
|
||||||
|
@ -93,17 +45,15 @@ type Info struct {
|
||||||
Files []FileInfo `bencode:"files,omitempty"`
|
Files []FileInfo `bencode:"files,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
// The info dictionary with its hash and raw bytes exposed, as these are
|
||||||
// unmarshal structures
|
// important to Bittorrent.
|
||||||
//----------------------------------------------------------------------------
|
type InfoEx struct {
|
||||||
|
|
||||||
type torrent_info_ex struct {
|
|
||||||
Info
|
Info
|
||||||
Hash []byte
|
Hash []byte
|
||||||
Bytes []byte
|
Bytes []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *torrent_info_ex) UnmarshalBencode(data []byte) error {
|
func (this *InfoEx) UnmarshalBencode(data []byte) error {
|
||||||
this.Bytes = make([]byte, 0, len(data))
|
this.Bytes = make([]byte, 0, len(data))
|
||||||
this.Bytes = append(this.Bytes, data...)
|
this.Bytes = append(this.Bytes, data...)
|
||||||
h := sha1.New()
|
h := sha1.New()
|
||||||
|
@ -112,12 +62,12 @@ func (this *torrent_info_ex) UnmarshalBencode(data []byte) error {
|
||||||
return bencode.Unmarshal(data, &this.Info)
|
return bencode.Unmarshal(data, &this.Info)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *torrent_info_ex) MarshalBencode() ([]byte, error) {
|
func (this *InfoEx) MarshalBencode() ([]byte, error) {
|
||||||
return bencode.Marshal(&this.Info)
|
return bencode.Marshal(&this.Info)
|
||||||
}
|
}
|
||||||
|
|
||||||
type torrent_data struct {
|
type MetaInfo struct {
|
||||||
Info torrent_info_ex `bencode:"info"`
|
Info InfoEx `bencode:"info"`
|
||||||
Announce string `bencode:"announce"`
|
Announce string `bencode:"announce"`
|
||||||
AnnounceList [][]string `bencode:"announce-list,omitempty"`
|
AnnounceList [][]string `bencode:"announce-list,omitempty"`
|
||||||
CreationDate int64 `bencode:"creation date,omitempty"`
|
CreationDate int64 `bencode:"creation date,omitempty"`
|
||||||
|
|
|
@ -9,11 +9,11 @@ func test_file(t *testing.T, filename string) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(mi.Files) == 1 {
|
if len(mi.Info.Files) == 1 {
|
||||||
t.Logf("Single file: %s (length: %d)\n", mi.Name, mi.Files[0].Length)
|
t.Logf("Single file: %s (length: %d)\n", mi.Info.Name, mi.Info.Files[0].Length)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Multiple files: %s\n", mi.Name)
|
t.Logf("Multiple files: %s\n", mi.Info.Name)
|
||||||
for _, f := range mi.Files {
|
for _, f := range mi.Info.Files {
|
||||||
t.Logf(" - %s (length: %d)\n", path.Join(f.Path...), f.Length)
|
t.Logf(" - %s (length: %d)\n", path.Join(f.Path...), f.Length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,9 @@ func test_file(t *testing.T, filename string) {
|
||||||
t.Logf("Tracker: %s\n", tracker)
|
t.Logf("Tracker: %s\n", tracker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, url := range mi.WebSeedURLs {
|
// for _, url := range mi.WebSeedURLs {
|
||||||
t.Logf("URL: %s\n", url)
|
// t.Logf("URL: %s\n", url)
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue