From f6d1652360d28e184fe2d313f32da1916e7c7a4d Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sun, 3 May 2015 11:30:27 +0100 Subject: [PATCH] Added support for trackerless metainfo files Based on the official spec (http://www.bittorrent.org/beps/bep_0005.html) trackerless metainfo files do not contain announce key. Instead nodes key has to be specified. This PR adds support for nodes key into metainfo package. It also contains a test metainfo file. --- metainfo/_testdata/trackerless.torrent | 1 + metainfo/builder.go | 57 +++++++++++++++++++------- metainfo/metainfo.go | 3 +- 3 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 metainfo/_testdata/trackerless.torrent diff --git a/metainfo/_testdata/trackerless.torrent b/metainfo/_testdata/trackerless.torrent new file mode 100644 index 00000000..b90f253e --- /dev/null +++ b/metainfo/_testdata/trackerless.torrent @@ -0,0 +1 @@ +d7:comment19:This is just a test10:created by12:Johnny Bravo13:creation datei1430648794e8:encoding5:UTF-84:infod6:lengthi1128e4:name12:testfile.bin12:piece lengthi32768e6:pieces20:Õˆë =‘UŒäiÎ^æ °Eâ?ÇÒe5:nodesll35:udp://tracker.openbittorrent.com:8035:udp://tracker.openbittorrent.com:80eee \ No newline at end of file diff --git a/metainfo/builder.go b/metainfo/builder.go index b697f88f..96df1939 100644 --- a/metainfo/builder.go +++ b/metainfo/builder.go @@ -67,6 +67,11 @@ func (b *Builder) AddAnnounceGroup(group []string) { b.announce_list = append(b.announce_list, group) } +// Add DHT nodes URLs for trackerless mode +func (b *Builder) AddDhtNodes(group []string) { + b.node_list = append(b.node_list, group) +} + // Sets creation date. The default is time.Now() when the .Build method was // called. func (b *Builder) SetCreationDate(date time.Time) { @@ -203,20 +208,18 @@ func (b *Builder) check_parameters() error { return errors.New("no files were queued") } - // let's clean up the announce_list - newal := make([][]string, 0, len(b.announce_list)) - for _, ag := range b.announce_list { - ag = remove_empty_strings(ag) + // let's clean up the announce_list and node_list + b.announce_list = cleanUpLists(b.announce_list) + b.node_list = cleanUpLists(b.node_list) - // discard empty announce groups - if len(ag) == 0 { - continue - } - newal = append(newal, ag) + if len(b.announce_list) == 0 && len(b.node_list) == 0 { + return errors.New("no announce group or DHT nodes specified") } - b.announce_list = newal - if len(b.announce_list) == 0 { - return errors.New("no announce groups were specified") + + // Either the node_list or announce_list can be present + // Never the both! + if len(b.announce_list) > 0 && len(b.node_list) > 0 { + return errors.New("announce group and nodes are mutually exclusive") } // and clean up the urls @@ -225,6 +228,20 @@ func (b *Builder) check_parameters() error { return nil } +func cleanUpLists(list [][]string) [][]string { + newList := make([][]string, 0, len(list)) + for _, l := range list { + l = remove_empty_strings(l) + + // discard empty announce groups + if len(l) == 0 { + continue + } + newList = append(newList, l) + } + return newList +} + //---------------------------------------------------------------------------- // Batch //---------------------------------------------------------------------------- @@ -346,10 +363,19 @@ func (b *Batch) Start(w io.Writer, nworkers int) (<-chan error, <-chan int64) { func (b *Batch) write_torrent(w io.Writer) error { var td MetaInfo - td.Announce = b.announce_list[0][0] - if len(b.announce_list) != 1 || len(b.announce_list[0]) != 1 { - td.AnnounceList = b.announce_list + + // Either announce or node lists are allowed - not both + if len(b.announce_list) != 0 { + td.Announce = b.announce_list[0][0] + if len(b.announce_list) != 1 || len(b.announce_list[0]) != 1 { + td.AnnounceList = b.announce_list + } } + + if len(b.node_list) != 0 { + td.Nodes = b.node_list + } + td.CreationDate = b.creation_date.Unix() td.Comment = b.comment td.CreatedBy = b.created_by @@ -420,6 +446,7 @@ type batch_state struct { pieces []byte private bool announce_list [][]string + node_list [][]string creation_date time.Time comment string created_by string diff --git a/metainfo/metainfo.go b/metainfo/metainfo.go index 2f15cacc..ce3246a5 100644 --- a/metainfo/metainfo.go +++ b/metainfo/metainfo.go @@ -144,8 +144,9 @@ func (this InfoEx) MarshalBencode() ([]byte, error) { type MetaInfo struct { Info InfoEx `bencode:"info"` - Announce string `bencode:"announce"` + Announce string `bencode:"announce,omitempty"` AnnounceList [][]string `bencode:"announce-list,omitempty"` + Nodes [][]string `bencode:"nodes,omitempty"` CreationDate int64 `bencode:"creation date,omitempty"` Comment string `bencode:"comment,omitempty"` CreatedBy string `bencode:"created by,omitempty"`