]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/btrtrc/main.go
eb5afaab76ab400a922db8be3ed3e6943321990e
[btrtrc.git] / cmd / btrtrc / main.go
1 package main
2
3 import (
4         "bytes"
5         "flag"
6         "log"
7         "net"
8         "os"
9         "os/signal"
10         "path"
11         "strings"
12         "syscall"
13
14         "github.com/anacrolix/dht/v2"
15         analog "github.com/anacrolix/log"
16
17         "github.com/anacrolix/torrent"
18         "github.com/anacrolix/torrent/storage"
19 )
20
21 const TorrentExt = ".torrent"
22
23 func saveTorrent(t *torrent.Torrent) error {
24         pth := t.InfoHash().HexString() + TorrentExt
25         if _, err := os.Stat(pth); err == nil {
26                 return nil
27         }
28         var b bytes.Buffer
29         t.Metainfo().Write(&b)
30         if err := os.WriteFile(pth, b.Bytes(), 0666); err != nil {
31                 return err
32         }
33         return os.Symlink(pth, t.Name()+TorrentExt)
34 }
35
36 func main() {
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")
45         flag.Parse()
46
47         dht.DefaultGlobalBootstrapHostPorts = strings.Split(*dhtBoot, ",")
48         cc := torrent.NewDefaultClientConfig()
49         cc.Debug = *debug
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())
55         if *verify {
56                 doVerify(cc, flag.Args())
57                 return
58         }
59         cc.Seed = true
60         if *pub4 == "" {
61                 cc.DisableIPv4 = true
62         } else {
63                 cc.PublicIp4 = net.ParseIP(*pub4).To4()
64         }
65         if *pub6 == "" {
66                 cc.DisableIPv6 = true
67         } else {
68                 cc.PublicIp6 = net.ParseIP(*pub6).To16()
69         }
70         cc.NoDHT = *noDHT
71         cc.SetListenAddr(*addr)
72         client, err := torrent.NewClient(cc)
73         if err != nil {
74                 log.Fatalln("torrent.NewClient:", err)
75         }
76         defer client.Close()
77
78         needsShutdown := make(chan os.Signal)
79         overallStatusCancel := make(chan struct{})
80         txStatsDumperCancel := make(chan struct{})
81         signal.Notify(needsShutdown, syscall.SIGTERM, syscall.SIGINT)
82         go func() {
83                 <-needsShutdown
84                 overallStatusCancel <- struct{}{}
85                 txStatsDumperCancel <- struct{}{}
86                 client.Close()
87         }()
88
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)
93         go fifoList(client)
94         go fifoDHTList(client)
95         go fifoAdd(client)
96         go fifoDel(client)
97         go txStatsDumper(client, txStatsDumperCancel)
98         <-client.Closed()
99         <-overallStatusCancel
100         <-txStatsDumperCancel
101         log.Println("finished")
102 }