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") }