1 // Mounts a FUSE filesystem backed by torrents and magnet links.
17 fusefs "bazil.org/fuse/fs"
18 _ "github.com/anacrolix/envpprof"
19 "github.com/anacrolix/tagflag"
20 "github.com/anacrolix/torrent"
21 "github.com/anacrolix/torrent/fs"
22 "github.com/anacrolix/torrent/util/dirwatch"
27 MetainfoDir string `help:"torrent files in this location describe the contents of the mounted filesystem"`
28 DownloadDir string `help:"location to save torrent data"`
29 MountDir string `help:"location the torrent contents are made available"`
33 ReadaheadBytes tagflag.Bytes
34 ListenAddr *net.TCPAddr
36 MetainfoDir: func() string {
37 _user, err := user.Current()
41 return filepath.Join(_user.HomeDir, ".config/transmission/torrents")
43 ReadaheadBytes: 10 << 20,
44 ListenAddr: &net.TCPAddr{},
48 func exitSignalHandlers(fs *torrentfs.TorrentFS) {
49 c := make(chan os.Signal, 1)
50 signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
54 err := fuse.Unmount(args.MountDir)
61 func addTestPeer(client *torrent.Client) {
62 for _, t := range client.Torrents() {
63 t.AddPeers([]torrent.Peer{{
65 Port: args.TestPeer.Port,
71 os.Exit(mainExitCode())
74 func mainExitCode() int {
76 if args.MountDir == "" {
77 os.Stderr.WriteString("y u no specify mountpoint?\n")
80 log.SetFlags(log.LstdFlags | log.Lshortfile)
81 conn, err := fuse.Mount(args.MountDir)
85 defer fuse.Unmount(args.MountDir)
86 // TODO: Think about the ramifications of exiting not due to a signal.
88 cfg := torrent.NewDefaultClientConfig()
89 cfg.DataDir = args.DownloadDir
90 cfg.DisableTrackers = args.DisableTrackers
91 cfg.NoUpload = true // Ensure that downloads are responsive.
92 cfg.SetListenAddr(args.ListenAddr.String())
93 client, err := torrent.NewClient(cfg)
98 // This is naturally exported via GOPPROF=http.
99 http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
100 client.WriteStatus(w)
102 dw, err := dirwatch.New(args.MetainfoDir)
104 log.Printf("error watching torrent dir: %s", err)
108 for ev := range dw.Events {
111 if ev.TorrentFilePath != "" {
112 _, err := client.AddTorrentFromFile(ev.TorrentFilePath)
114 log.Printf("error adding torrent to client: %s", err)
116 } else if ev.MagnetURI != "" {
117 _, err := client.AddMagnet(ev.MagnetURI)
119 log.Printf("error adding magnet: %s", err)
122 case dirwatch.Removed:
123 T, ok := client.Torrent(ev.InfoHash)
131 fs := torrentfs.New(client)
132 go exitSignalHandlers(fs)
134 if args.TestPeer != nil {
138 time.Sleep(10 * time.Second)
143 if err := fusefs.Serve(conn, fs); err != nil {
147 if err := conn.MountError; err != nil {