14 "github.com/anacrolix/dht/v2"
15 analog "github.com/anacrolix/log"
17 "github.com/anacrolix/torrent"
18 "github.com/anacrolix/torrent/storage"
21 const TorrentExt = ".torrent"
23 func saveTorrent(t *torrent.Torrent) error {
24 pth := t.InfoHash().HexString() + TorrentExt
25 if _, err := os.Stat(pth); err == nil {
29 t.Metainfo().Write(&b)
30 if err := os.WriteFile(pth, b.Bytes(), 0666); err != nil {
33 return os.Symlink(pth, t.Name()+TorrentExt)
37 log.SetFlags(log.Ldate | log.Ltime)
38 dhtBoot := flag.String("dht", "dht.cypherpunks.ru:8991", "Comma-separated list of DHT bootstrap nodes")
39 addr := flag.String("bind", "[::]:6881", "Address to bind to")
40 pub4 := flag.String("4", "", "External IPv4 address")
41 pub6 := flag.String("6", "", "External IPv6 address")
42 debug := flag.Bool("debug", false, "Enable debug messages")
43 noDHT := flag.Bool("nodht", false, "Disable DHT")
44 verify := flag.Bool("verify", false, "Force verification of provided torrents")
47 dht.DefaultGlobalBootstrapHostPorts = strings.Split(*dhtBoot, ",")
48 cc := torrent.NewDefaultClientConfig()
50 cc.DisableAcceptRateLimiting = true
51 cc.NoDefaultPortForwarding = true
52 cc.DisableWebtorrent = true
53 cc.Logger = analog.Default.WithNames("main", "client")
54 cc.DefaultStorage = storage.NewFileWithCompletion(".", NewBFPieceCompletion())
56 doVerify(cc, flag.Args())
63 cc.PublicIp4 = net.ParseIP(*pub4).To4()
68 cc.PublicIp6 = net.ParseIP(*pub6).To16()
71 cc.SetListenAddr(*addr)
72 client, err := torrent.NewClient(cc)
74 log.Fatalln("torrent.NewClient:", err)
78 needsShutdown := make(chan os.Signal)
79 overallStatusCancel := make(chan struct{})
80 txStatsDumperCancel := make(chan struct{})
81 signal.Notify(needsShutdown, syscall.SIGTERM, syscall.SIGINT)
84 overallStatusCancel <- struct{}{}
85 txStatsDumperCancel <- struct{}{}
89 os.MkdirAll(path.Join(FIFOsDir, PeersDir), 0777)
90 os.MkdirAll(path.Join(FIFOsDir, FilesDir), 0777)
91 log.Println("started", client.PublicIPs())
92 go overallStatus(client, overallStatusCancel)
94 go fifoDHTList(client)
97 go txStatsDumper(client, txStatsDumperCancel)
100 <-txStatsDumperCancel
101 log.Println("finished")