spec.go 3.1 KB

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