]> Sergey Matveev's repositories - btrtrc.git/blob - spec.go
Get infohash selection working when adding v2 torrents
[btrtrc.git] / spec.go
1 package torrent
2
3 import (
4         "fmt"
5         g "github.com/anacrolix/generics"
6         infohash_v2 "github.com/anacrolix/torrent/types/infohash-v2"
7
8         "github.com/anacrolix/torrent/metainfo"
9         pp "github.com/anacrolix/torrent/peer_protocol"
10         "github.com/anacrolix/torrent/storage"
11 )
12
13 // Specifies a new torrent for adding to a client, or additions to an existing Torrent. There are
14 // constructor functions for magnet URIs and torrent metainfo files. TODO: This type should be
15 // dismantled into a new Torrent option type, and separate Torrent mutate method(s).
16 type TorrentSpec struct {
17         // The tiered tracker URIs.
18         Trackers [][]string
19         // TODO: Move into a "new" Torrent opt type.
20         InfoHash   metainfo.Hash
21         InfoHashV2 g.Option[infohash_v2.T]
22         InfoBytes  []byte
23         // The name to use if the Name field from the Info isn't available.
24         DisplayName string
25         // WebSeed URLs. For additional options add the URLs separately with Torrent.AddWebSeeds
26         // instead.
27         Webseeds  []string
28         DhtNodes  []string
29         PeerAddrs []string
30         // The combination of the "xs" and "as" fields in magnet links, for now.
31         Sources []string
32         // BEP 52 "piece layers" from metainfo
33         PieceLayers map[string]string
34
35         // The chunk size to use for outbound requests. Defaults to 16KiB if not set. Can only be set
36         // for new Torrents. TODO: Move into a "new" Torrent opt type.
37         ChunkSize pp.Integer
38         // TODO: Move into a "new" Torrent opt type.
39         Storage storage.ClientImpl
40
41         DisableInitialPieceCheck bool
42
43         // Whether to allow data download or upload
44         DisallowDataUpload   bool
45         DisallowDataDownload bool
46 }
47
48 func TorrentSpecFromMagnetUri(uri string) (spec *TorrentSpec, err error) {
49         m, err := metainfo.ParseMagnetUri(uri)
50         if err != nil {
51                 return
52         }
53         spec = &TorrentSpec{
54                 Trackers:    [][]string{m.Trackers},
55                 DisplayName: m.DisplayName,
56                 InfoHash:    m.InfoHash,
57                 Webseeds:    m.Params["ws"],
58                 Sources:     append(m.Params["xs"], m.Params["as"]...),
59                 PeerAddrs:   m.Params["x.pe"], // BEP 9
60                 // TODO: What's the parameter for DHT nodes?
61         }
62         return
63 }
64
65 // The error will be from unmarshalling the info bytes. The TorrentSpec is still filled out as much
66 // as possible in this case.
67 func TorrentSpecFromMetaInfoErr(mi *metainfo.MetaInfo) (*TorrentSpec, error) {
68         info, err := mi.UnmarshalInfo()
69         if err != nil {
70                 err = fmt.Errorf("unmarshalling info: %w", err)
71         }
72         v1Ih := mi.HashInfoBytes()
73         var v2Infohash g.Option[infohash_v2.T]
74         if info.HasV2() {
75                 v2Infohash.Set(infohash_v2.HashBytes(mi.InfoBytes))
76                 if !info.HasV1() {
77                         v1Ih = v2Infohash.Value.ToShort()
78                 }
79         }
80
81         return &TorrentSpec{
82                 Trackers:    mi.UpvertedAnnounceList(),
83                 InfoHash:    v1Ih,
84                 InfoHashV2:  v2Infohash,
85                 PieceLayers: mi.PieceLayers,
86                 InfoBytes:   mi.InfoBytes,
87                 DisplayName: info.Name,
88                 Webseeds:    mi.UrlList,
89                 DhtNodes: func() (ret []string) {
90                         ret = make([]string, 0, len(mi.Nodes))
91                         for _, node := range mi.Nodes {
92                                 ret = append(ret, string(node))
93                         }
94                         return
95                 }(),
96         }, err
97 }
98
99 // Panics if there was anything missing from the metainfo.
100 func TorrentSpecFromMetaInfo(mi *metainfo.MetaInfo) *TorrentSpec {
101         ts, err := TorrentSpecFromMetaInfoErr(mi)
102         if err != nil {
103                 panic(err)
104         }
105         return ts
106 }