]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/torrentfs/main.go
Big visibility/doc clean-up, and extract mmap_span package
[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         "bitbucket.org/anacrolix/go.torrent"
19         "bitbucket.org/anacrolix/go.torrent/fs"
20         metainfo "github.com/nsf/libtorgo/torrent"
21 )
22
23 var (
24         downloadDir     string
25         torrentPath     string
26         mountDir        string
27         disableTrackers = flag.Bool("disableTrackers", false, "disables trackers")
28         testPeer        = flag.String("testPeer", "", "the address for a test peer")
29         pprofAddr       = flag.String("pprofAddr", "", "pprof HTTP server bind address")
30         testPeerAddr    *net.TCPAddr
31 )
32
33 func init() {
34         flag.StringVar(&downloadDir, "downloadDir", "", "location to save torrent data")
35         flag.StringVar(&torrentPath, "torrentPath", func() string {
36                 _user, err := user.Current()
37                 if err != nil {
38                         log.Fatal(err)
39                 }
40                 return filepath.Join(_user.HomeDir, ".config/transmission/torrents")
41         }(), "torrent files in this location describe the contents of the mounted filesystem")
42         flag.StringVar(&mountDir, "mountDir", "", "location the torrent contents are made available")
43 }
44
45 func resolveTestPeerAddr() {
46         if *testPeer == "" {
47                 return
48         }
49         var err error
50         testPeerAddr, err = net.ResolveTCPAddr("tcp4", *testPeer)
51         if err != nil {
52                 log.Fatal(err)
53         }
54 }
55
56 func setSignalHandlers() {
57         c := make(chan os.Signal)
58         signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
59         go func() {
60                 for {
61                         <-c
62                         err := fuse.Unmount(mountDir)
63                         if err != nil {
64                                 log.Print(err)
65                         }
66                 }
67         }()
68 }
69
70 func addTorrent(c *torrent.Client, file string) {
71         metaInfo, err := metainfo.LoadFromFile(file)
72         if err != nil {
73                 log.Print(err)
74                 return
75         }
76         err = c.AddTorrent(metaInfo)
77         if err != nil {
78                 log.Print(err)
79                 return
80         }
81 }
82
83 func addTorrentDir(c *torrent.Client, _path string) {
84         torrentDir, err := os.Open(torrentPath)
85         defer torrentDir.Close()
86         if err != nil {
87                 log.Fatal(err)
88         }
89         names, err := torrentDir.Readdirnames(-1)
90         if err != nil {
91                 log.Fatal(err)
92         }
93         for _, name := range names {
94                 go addTorrent(c, filepath.Join(_path, name))
95         }
96 }
97
98 func addTestPeer(client *torrent.Client) {
99         for _, t := range client.Torrents() {
100                 if testPeerAddr != nil {
101                         if err := client.AddPeers(t.InfoHash, []torrent.Peer{{
102                                 IP:   testPeerAddr.IP,
103                                 Port: testPeerAddr.Port,
104                         }}); err != nil {
105                                 log.Print(err)
106                         }
107                 }
108         }
109 }
110
111 func main() {
112         flag.Parse()
113         if flag.NArg() != 0 {
114                 os.Stderr.WriteString("one does not simply pass positional args\n")
115                 os.Exit(2)
116         }
117         if mountDir == "" {
118                 os.Stderr.WriteString("y u no specify mountpoint?\n")
119                 os.Exit(2)
120         }
121         log.SetFlags(log.LstdFlags | log.Lshortfile)
122         if *pprofAddr != "" {
123                 go http.ListenAndServe(*pprofAddr, nil)
124         }
125         conn, err := fuse.Mount(mountDir)
126         if err != nil {
127                 log.Fatal(err)
128         }
129         defer fuse.Unmount(mountDir)
130         // TODO: Think about the ramifications of exiting not due to a signal.
131         setSignalHandlers()
132         defer conn.Close()
133         client := &torrent.Client{
134                 DataDir:         downloadDir,
135                 DisableTrackers: *disableTrackers,
136         }
137         client.Start()
138         addTorrentDir(client, torrentPath)
139         resolveTestPeerAddr()
140         fs := torrentfs.New(client)
141         go func() {
142                 for {
143                         addTestPeer(client)
144                         time.Sleep(10 * time.Second)
145                 }
146         }()
147
148         if err := fusefs.Serve(conn, fs); err != nil {
149                 log.Fatal(err)
150         }
151         <-conn.Ready
152         if err := conn.MountError; err != nil {
153                 log.Fatal(err)
154         }
155 }