]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Include piece layers in dynamically generated metainfo
authorMatt Joiner <anacrolix@gmail.com>
Wed, 20 Mar 2024 03:02:41 +0000 (14:02 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Wed, 20 Mar 2024 03:02:41 +0000 (14:02 +1100)
metainfo/metainfo.go
torrent.go

index b20a9efd02f8907f1189d1dba4946cd2333dd8ad..6a5ea1cd906aedee70fe551616f36962c31ada5f 100644 (file)
@@ -24,7 +24,7 @@ type MetaInfo struct {
        CreatedBy    string  `bencode:"created by,omitempty"`
        Encoding     string  `bencode:"encoding,omitempty"`
        UrlList      UrlList `bencode:"url-list,omitempty"` // BEP 19 WebSeeds
-       // BEP 52 (BitTorrent v2): Keys are file merkle roots (pieces root?), and the values are the
+       // BEP 52 (BitTorrent v2): Keys are file merkle roots ("pieces root"s), and the values are the
        // concatenated hashes of the merkle tree layer that corresponds to the piece length.
        PieceLayers map[string]string `bencode:"piece layers,omitempty"`
 }
index e2375a441ea66ef8c7eee4968c426624939055c1..b952e3ce6e13a0b353c85c30a26aecf346a701f2 100644 (file)
@@ -922,7 +922,7 @@ func (t *Torrent) newMetaInfo() metainfo.MetaInfo {
        return metainfo.MetaInfo{
                CreationDate: time.Now().Unix(),
                Comment:      "dynamic metainfo from client",
-               CreatedBy:    "go.torrent",
+               CreatedBy:    "https://github.com/anacrolix/torrent",
                AnnounceList: t.metainfo.UpvertedAnnounceList().Clone(),
                InfoBytes: func() []byte {
                        if t.haveInfo() {
@@ -938,6 +938,7 @@ func (t *Torrent) newMetaInfo() metainfo.MetaInfo {
                        }
                        return ret
                }(),
+               PieceLayers: t.pieceLayers(),
        }
 }
 
@@ -3169,3 +3170,34 @@ func (t *Torrent) getFileByPiecesRoot(hash [32]byte) *File {
        }
        return nil
 }
+
+func (t *Torrent) pieceLayers() (pieceLayers map[string]string) {
+       if t.files == nil {
+               return
+       }
+       files := *t.files
+       g.MakeMapWithCap(&pieceLayers, len(files))
+file:
+       for _, f := range files {
+               if !f.piecesRoot.Ok {
+                       continue
+               }
+               key := f.piecesRoot.Value
+               var value strings.Builder
+               for i := f.BeginPieceIndex(); i < f.EndPieceIndex(); i++ {
+                       hashOpt := t.piece(i).hashV2
+                       if !hashOpt.Ok {
+                               // All hashes must be present. This implementation should handle missing files, so move on to the next file.
+                               continue file
+                       }
+                       value.Write(hashOpt.Value[:])
+               }
+               if value.Len() == 0 {
+                       // Non-empty files are not recorded in piece layers.
+                       continue
+               }
+               // If multiple files have the same root that shouldn't matter.
+               pieceLayers[string(key[:])] = value.String()
+       }
+       return
+}