github.com/anacrolix/torrent@v1.61.0/cmd/torrent/serve.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"path/filepath"
     7  
     8  	"github.com/anacrolix/bargle"
     9  	"github.com/anacrolix/log"
    10  
    11  	"github.com/anacrolix/torrent"
    12  	"github.com/anacrolix/torrent/bencode"
    13  	"github.com/anacrolix/torrent/metainfo"
    14  	"github.com/anacrolix/torrent/storage"
    15  )
    16  
    17  func serve() (cmd bargle.Command) {
    18  	var filePaths []string
    19  	cmd.Positionals = append(cmd.Positionals, &bargle.Positional{
    20  		Value: bargle.AutoUnmarshaler(&filePaths),
    21  	})
    22  	cmd.Desc = "creates and seeds a torrent from a filepath"
    23  	cmd.DefaultAction = func() error {
    24  		cfg := torrent.NewDefaultClientConfig()
    25  		cfg.Seed = true
    26  		cl, err := torrent.NewClient(cfg)
    27  		if err != nil {
    28  			return fmt.Errorf("new torrent client: %w", err)
    29  		}
    30  		defer cl.Close()
    31  		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    32  			cl.WriteStatus(w)
    33  		})
    34  		for _, filePath := range filePaths {
    35  			totalLength, err := totalLength(filePath)
    36  			if err != nil {
    37  				return fmt.Errorf("calculating total length of %q: %v", filePath, err)
    38  			}
    39  			pieceLength := metainfo.ChoosePieceLength(totalLength)
    40  			info := metainfo.Info{
    41  				PieceLength: pieceLength,
    42  			}
    43  			err = info.BuildFromFilePath(filePath)
    44  			if err != nil {
    45  				return fmt.Errorf("building info from path %q: %w", filePath, err)
    46  			}
    47  			for _, fi := range info.UpvertedFiles() {
    48  				log.Printf("added %q", fi.BestPath())
    49  			}
    50  			mi := metainfo.MetaInfo{
    51  				InfoBytes: bencode.MustMarshal(info),
    52  			}
    53  			pc, err := storage.NewDefaultPieceCompletionForDir(".")
    54  			if err != nil {
    55  				return fmt.Errorf("new piece completion: %w", err)
    56  			}
    57  			defer pc.Close()
    58  			ih := mi.HashInfoBytes()
    59  			to, _ := cl.AddTorrentOpt(torrent.AddTorrentOpts{
    60  				InfoHash: ih,
    61  				Storage: storage.NewFileOpts(storage.NewFileClientOpts{
    62  					ClientBaseDir: filePath,
    63  					FilePathMaker: func(opts storage.FilePathMakerOpts) string {
    64  						return filepath.Join(opts.File.BestPath()...)
    65  					},
    66  					TorrentDirMaker: nil,
    67  					PieceCompletion: pc,
    68  				}),
    69  				InfoBytes: mi.InfoBytes,
    70  			})
    71  			defer to.Drop()
    72  			// TODO: Builtin trackers?
    73  			to.AddTrackers([][]string{{
    74  				`wss://tracker.btorrent.xyz`,
    75  				`wss://tracker.openwebtorrent.com`,
    76  				"http://p4p.arenabg.com:1337/announce",
    77  				"udp://tracker.opentrackr.org:1337/announce",
    78  				"udp://tracker.openbittorrent.com:6969/announce",
    79  			}})
    80  			fmt.Printf("%v: %v\n", to, to.Metainfo().Magnet(&ih, &info))
    81  		}
    82  		select {}
    83  	}
    84  	return
    85  }