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