]> Sergey Matveev's repositories - btrtrc.git/blob - spec.go
f1ef584ea78e1bdc66664edcdfbf6d7b5fc9409a
[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         var v2Infohash g.Option[infohash_v2.T]
73         if info.HasV2() {
74                 v2Infohash.Set(infohash_v2.HashBytes(mi.InfoBytes))
75         }
76         return &TorrentSpec{
77                 Trackers:    mi.UpvertedAnnounceList(),
78                 InfoHash:    mi.HashInfoBytes(),
79                 InfoHashV2:  v2Infohash,
80                 PieceLayers: mi.PieceLayers,
81                 InfoBytes:   mi.InfoBytes,
82                 DisplayName: info.Name,
83                 Webseeds:    mi.UrlList,
84                 DhtNodes: func() (ret []string) {
85                         ret = make([]string, 0, len(mi.Nodes))
86                         for _, node := range mi.Nodes {
87                                 ret = append(ret, string(node))
88                         }
89                         return
90                 }(),
91         }, err
92 }
93
94 // Panics if there was anything missing from the metainfo.
95 func TorrentSpecFromMetaInfo(mi *metainfo.MetaInfo) *TorrentSpec {
96         ts, err := TorrentSpecFromMetaInfoErr(mi)
97         if err != nil {
98                 panic(err)
99         }
100         return ts
101 }