]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/torrentfs/main.go
Use rogpeppe's sortimports to fix this goimports ordering madness
[btrtrc.git] / cmd / torrentfs / main.go
1 package main
2
3 import (
4         "flag"
5         "log"
6         "net"
7         "net/http"
8         _ "net/http/pprof"
9         "os"
10         "os/signal"
11         "os/user"
12         "path/filepath"
13         "syscall"
14         "time"
15
16         "bazil.org/fuse"
17         fusefs "bazil.org/fuse/fs"
18         _ "github.com/anacrolix/envpprof"
19
20         "github.com/anacrolix/torrent"
21         "github.com/anacrolix/torrent/fs"
22         "github.com/anacrolix/torrent/util/dirwatch"
23 )
24
25 var (
26         torrentPath = flag.String("torrentPath", func() string {
27                 _user, err := user.Current()
28                 if err != nil {
29                         log.Fatal(err)
30                 }
31                 return filepath.Join(_user.HomeDir, ".config/transmission/torrents")
32         }(), "torrent files in this location describe the contents of the mounted filesystem")
33         downloadDir = flag.String("downloadDir", "", "location to save torrent data")
34         mountDir    = flag.String("mountDir", "", "location the torrent contents are made available")
35
36         disableTrackers = flag.Bool("disableTrackers", false, "disables trackers")
37         testPeer        = flag.String("testPeer", "", "the address for a test peer")
38         readaheadBytes  = flag.Int64("readaheadBytes", 10*1024*1024, "bytes to readahead in each torrent from the last read piece")
39         listenAddr      = flag.String("listenAddr", ":6882", "incoming connection address")
40
41         testPeerAddr *net.TCPAddr
42 )
43
44 func resolveTestPeerAddr() {
45         if *testPeer == "" {
46                 return
47         }
48         var err error
49         testPeerAddr, err = net.ResolveTCPAddr("tcp4", *testPeer)
50         if err != nil {
51                 log.Fatal(err)
52         }
53 }
54
55 func exitSignalHandlers(fs *torrentfs.TorrentFS) {
56         c := make(chan os.Signal)
57         signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
58         for {
59                 <-c
60                 fs.Destroy()
61                 err := fuse.Unmount(*mountDir)
62                 if err != nil {
63                         log.Print(err)
64                 }
65         }
66 }
67
68 func addTestPeer(client *torrent.Client) {
69         for _, t := range client.Torrents() {
70                 if testPeerAddr != nil {
71                         if err := t.AddPeers([]torrent.Peer{{
72                                 IP:   testPeerAddr.IP,
73                                 Port: testPeerAddr.Port,
74                         }}); err != nil {
75                                 log.Print(err)
76                         }
77                 }
78         }
79 }
80
81 func main() {
82         flag.Parse()
83         if flag.NArg() != 0 {
84                 os.Stderr.WriteString("one does not simply pass positional args\n")
85                 os.Exit(2)
86         }
87         if *mountDir == "" {
88                 os.Stderr.WriteString("y u no specify mountpoint?\n")
89                 os.Exit(2)
90         }
91         log.SetFlags(log.LstdFlags | log.Lshortfile)
92         conn, err := fuse.Mount(*mountDir)
93         if err != nil {
94                 log.Fatal(err)
95         }
96         defer fuse.Unmount(*mountDir)
97         // TODO: Think about the ramifications of exiting not due to a signal.
98         defer conn.Close()
99         client, err := torrent.NewClient(&torrent.Config{
100                 DataDir:         *downloadDir,
101                 DisableTrackers: *disableTrackers,
102                 // DownloadStrategy: torrent.NewResponsiveDownloadStrategy(*readaheadBytes),
103                 ListenAddr: *listenAddr,
104                 NoUpload:   true, // Ensure that uploads are responsive.
105         })
106         http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
107                 client.WriteStatus(w)
108         })
109         dw, err := dirwatch.New(*torrentPath)
110         if err != nil {
111                 log.Fatal(err)
112         }
113         go func() {
114                 for ev := range dw.Events {
115                         switch ev.Change {
116                         case dirwatch.Added:
117                                 if ev.TorrentFilePath != "" {
118                                         _, err := client.AddTorrentFromFile(ev.TorrentFilePath)
119                                         if err != nil {
120                                                 log.Printf("error adding torrent to client: %s", err)
121                                         }
122                                 } else if ev.MagnetURI != "" {
123                                         _, err := client.AddMagnet(ev.MagnetURI)
124                                         if err != nil {
125                                                 log.Printf("error adding magnet: %s", err)
126                                         }
127                                 }
128                         case dirwatch.Removed:
129                                 for _, t := range client.Torrents() {
130                                         if t.InfoHash != ev.InfoHash {
131                                                 continue
132                                         }
133                                         t.Drop()
134                                         break
135                                 }
136                         }
137                 }
138         }()
139         resolveTestPeerAddr()
140         fs := torrentfs.New(client)
141         go exitSignalHandlers(fs)
142         go func() {
143                 for {
144                         addTestPeer(client)
145                         time.Sleep(10 * time.Second)
146                 }
147         }()
148
149         if err := fusefs.Serve(conn, fs); err != nil {
150                 log.Fatal(err)
151         }
152         <-conn.Ready
153         if err := conn.MountError; err != nil {
154                 log.Fatal(err)
155         }
156 }