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"
21 "github.com/anacrolix/torrent"
22 "github.com/anacrolix/torrent/fs"
23 "github.com/anacrolix/torrent/util/dirwatch"
28 MetainfoDir string `help:"torrent files in this location describe the contents of the mounted filesystem"`
29 DownloadDir string `help:"location to save torrent data"`
30 MountDir string `help:"location the torrent contents are made available"`
34 ReadaheadBytes tagflag.Bytes
35 ListenAddr *net.TCPAddr
37 MetainfoDir: func() string {
38 _user, err := user.Current()
42 return filepath.Join(_user.HomeDir, ".config/transmission/torrents")
44 ReadaheadBytes: 10 << 20,
45 ListenAddr: &net.TCPAddr{},
49 func exitSignalHandlers(fs *torrentfs.TorrentFS) {
50 c := make(chan os.Signal, 1)
51 signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
55 err := fuse.Unmount(args.MountDir)
62 func addTestPeer(client *torrent.Client) {
63 for _, t := range client.Torrents() {
64 t.AddPeers([]torrent.Peer{{
66 Port: args.TestPeer.Port,
72 os.Exit(mainExitCode())
75 func mainExitCode() int {
77 if args.MountDir == "" {
78 os.Stderr.WriteString("y u no specify mountpoint?\n")
81 log.SetFlags(log.LstdFlags | log.Lshortfile)
82 conn, err := fuse.Mount(args.MountDir)
86 defer fuse.Unmount(args.MountDir)
87 // TODO: Think about the ramifications of exiting not due to a signal.
89 cfg := torrent.NewDefaultClientConfig()
90 cfg.DataDir = args.DownloadDir
91 cfg.DisableTrackers = args.DisableTrackers
92 cfg.NoUpload = true // Ensure that downloads are responsive.
93 cfg.SetListenAddr(args.ListenAddr.String())
94 client, err := torrent.NewClient(cfg)
99 // This is naturally exported via GOPPROF=http.
100 http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
101 client.WriteStatus(w)
103 dw, err := dirwatch.New(args.MetainfoDir)
105 log.Printf("error watching torrent dir: %s", err)
109 for ev := range dw.Events {
112 if ev.TorrentFilePath != "" {
113 _, err := client.AddTorrentFromFile(ev.TorrentFilePath)
115 log.Printf("error adding torrent to client: %s", err)
117 } else if ev.MagnetURI != "" {
118 _, err := client.AddMagnet(ev.MagnetURI)
120 log.Printf("error adding magnet: %s", err)
123 case dirwatch.Removed:
124 T, ok := client.Torrent(ev.InfoHash)
132 fs := torrentfs.New(client)
133 go exitSignalHandlers(fs)
135 if args.TestPeer != nil {
139 time.Sleep(10 * time.Second)
144 if err := fusefs.Serve(conn, fs); err != nil {
148 if err := conn.MountError; err != nil {