--- /dev/null
+package main
+
+import (
+ "flag"
+ "log"
+ "net"
+ "os"
+ "os/signal"
+ "strings"
+ "sync"
+ "syscall"
+
+ "github.com/anacrolix/dht/v2"
+ analog "github.com/anacrolix/log"
+ "golang.org/x/time/rate"
+
+ "github.com/anacrolix/torrent"
+ "github.com/anacrolix/torrent/storage"
+)
+
+const (
+ TorrentExt = ".torrent"
+ UserAgent = "btrtrc/0.2.0"
+)
+
+var (
+ Cancel = make(chan struct{})
+ Jobs sync.WaitGroup
+)
+
+func main() {
+ log.SetFlags(log.Ldate | log.Ltime)
+ fifosDir := flag.String("fifos", "fifos", "Path to fifos/")
+ txsDir := flag.String("txs", "txs", "Path to txs/")
+ dhtBoot := flag.String("dht", "dht.cypherpunks.ru:8991",
+ "Comma-separated list of DHT bootstrap nodes")
+ addr := flag.String("bind", "[::]:6881", "Address to bind to")
+ pub4 := flag.String("4", "", "External IPv4 address")
+ pub6 := flag.String("6", "", "External IPv6 address")
+ debug := flag.Bool("debug", false, "Enable debug messages")
+ noDHT := flag.Bool("nodht", false, "Disable DHT")
+ rxRate := flag.Int("rx-rate", 0, "Download rate, piece bytes/sec")
+ txRate := flag.Int("rt-rate", 0, "Upload rate, bytes/sec")
+ verify := flag.Bool("verify", false, "Force verification of provided torrents")
+ flag.Parse()
+
+ FIFOsDir = *fifosDir
+ TxsDir = *txsDir
+ os.MkdirAll(TxsDir, 0777)
+ dht.DefaultGlobalBootstrapHostPorts = strings.Split(*dhtBoot, ",")
+ cc := torrent.NewDefaultClientConfig()
+ cc.Debug = *debug
+ cc.DisableAcceptRateLimiting = true
+ cc.NoDefaultPortForwarding = true
+ cc.DisableWebtorrent = true
+ cc.Logger = analog.Default.WithNames("main", "client")
+ cc.HTTPUserAgent = UserAgent
+ cc.ExtendedHandshakeClientVersion = UserAgent
+ cc.DefaultStorage = storage.NewFileWithCompletion(".", NewBFPieceCompletion())
+ if *verify {
+ doVerify(cc, flag.Args())
+ return
+ }
+ cc.Seed = true
+ if *pub4 == "" {
+ cc.DisableIPv4 = true
+ } else {
+ cc.PublicIp4 = net.ParseIP(*pub4).To4()
+ }
+ if *pub6 == "" {
+ cc.DisableIPv6 = true
+ } else {
+ cc.PublicIp6 = net.ParseIP(*pub6).To16()
+ }
+ if *txRate != 0 {
+ cc.UploadRateLimiter = rate.NewLimiter(rate.Limit(*txRate), 256<<10)
+ }
+ if *rxRate != 0 {
+ cc.DownloadRateLimiter = rate.NewLimiter(rate.Limit(*rxRate), 1<<16)
+ }
+ cc.NoDHT = *noDHT
+ cc.SetListenAddr(*addr)
+ client, err := torrent.NewClient(cc)
+ if err != nil {
+ log.Fatalln("torrent.NewClient:", err)
+ }
+ defer client.Close()
+
+ needsShutdown := make(chan os.Signal)
+ signal.Notify(needsShutdown, syscall.SIGTERM, syscall.SIGINT)
+ go func() {
+ <-needsShutdown
+ close(Cancel)
+ client.Close()
+ }()
+
+ fifosPrepare()
+ log.Println("started", client.PublicIPs())
+ Jobs.Add(1)
+ go overallStatus(client)
+ go fifoList(client)
+ go fifoTopSeed(client)
+ go fifoDHTList(client)
+ go fifoAdd(client)
+ go fifoDel(client)
+ Jobs.Add(1)
+ go txStatsDumper(client)
+ <-client.Closed()
+ Jobs.Wait()
+ fifosCleanup()
+ log.Println("finished")
+}