2020-04-27 16:46:23 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2020-11-08 17:19:25 +00:00
|
|
|
"fmt"
|
2020-04-27 16:46:23 +00:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/ajnavarro/distribyted/config"
|
2020-09-27 19:23:47 +00:00
|
|
|
"github.com/ajnavarro/distribyted/fuse"
|
2020-11-08 17:19:25 +00:00
|
|
|
"github.com/ajnavarro/distribyted/http"
|
2020-05-02 12:06:18 +00:00
|
|
|
"github.com/ajnavarro/distribyted/stats"
|
2020-11-08 17:19:25 +00:00
|
|
|
"github.com/ajnavarro/distribyted/torrent"
|
2020-04-27 16:46:23 +00:00
|
|
|
"github.com/anacrolix/missinggo/v2/filecache"
|
2020-11-08 17:19:25 +00:00
|
|
|
t "github.com/anacrolix/torrent"
|
2020-04-27 16:46:23 +00:00
|
|
|
"github.com/anacrolix/torrent/storage"
|
2020-07-27 09:20:19 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2020-11-08 17:19:25 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
2020-04-27 16:46:23 +00:00
|
|
|
)
|
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
const (
|
|
|
|
configFlag = "config"
|
|
|
|
portFlag = "http-port"
|
|
|
|
)
|
2020-07-14 11:55:08 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
func main() {
|
|
|
|
app := &cli.App{
|
|
|
|
Name: "distribyted",
|
|
|
|
Usage: "Torrent client with on-demand file downloading as a filesystem.",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: configFlag,
|
|
|
|
Value: "./distribyted-data/config.yaml",
|
|
|
|
EnvVars: []string{"DISTRIBYTED_CONFIG"},
|
|
|
|
Usage: "YAML file containing distribyted configuration.",
|
|
|
|
},
|
|
|
|
&cli.IntFlag{
|
|
|
|
Name: portFlag,
|
|
|
|
Value: 4444,
|
|
|
|
EnvVars: []string{"DISTRIBYTED_HTTP_PORT"},
|
|
|
|
Usage: "http port for web interface",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
err := load(c.String(configFlag), c.Int(portFlag))
|
|
|
|
return err
|
|
|
|
},
|
|
|
|
|
|
|
|
HideHelpCommand: true,
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
if err := app.Run(os.Args); err != nil {
|
|
|
|
logrus.Fatal(err)
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
2020-11-08 17:19:25 +00:00
|
|
|
}
|
2020-04-27 16:46:23 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
func newCache(folder string) (*filecache.Cache, error) {
|
|
|
|
if err := os.MkdirAll(folder, 0744); err != nil {
|
|
|
|
return nil, fmt.Errorf("error creating metadata folder: %w", err)
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
return filecache.NewCache(folder)
|
|
|
|
}
|
|
|
|
|
|
|
|
func load(configPath string, port int) error {
|
|
|
|
ch := config.NewHandler(configPath)
|
2020-04-27 16:46:23 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
conf, err := ch.Get()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error loading configuration: %w", err)
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
fc, err := newCache(conf.MetadataFolder)
|
2020-04-27 16:46:23 +00:00
|
|
|
if err != nil {
|
2020-11-08 17:19:25 +00:00
|
|
|
return fmt.Errorf("error creating cache: %w", err)
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
st := storage.NewResourcePieces(fc.AsResourceProvider())
|
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
c, err := torrent.NewClient(st)
|
2020-04-27 16:46:23 +00:00
|
|
|
if err != nil {
|
2020-11-08 17:19:25 +00:00
|
|
|
return fmt.Errorf("error starting torrent client: %w", err)
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 12:06:18 +00:00
|
|
|
ss := stats.NewTorrent()
|
2020-09-27 19:23:47 +00:00
|
|
|
mountService := fuse.NewHandler(c, ss)
|
2020-05-02 12:06:18 +00:00
|
|
|
|
2020-04-27 16:46:23 +00:00
|
|
|
sigChan := make(chan os.Signal)
|
|
|
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-sigChan
|
2020-11-08 17:19:25 +00:00
|
|
|
tryClose(c, mountService)
|
2020-04-27 16:46:23 +00:00
|
|
|
}()
|
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
ch.OnReload(func(c *config.Root, ef config.EventFunc) error {
|
|
|
|
ef("unmounting filesystems")
|
|
|
|
mountService.UnmountAll()
|
2020-05-08 14:37:43 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
ef(fmt.Sprintf("setting cache size to %d MB", c.MaxCacheSize))
|
|
|
|
fc.SetCapacity(c.MaxCacheSize * 1024 * 1024)
|
2020-05-18 17:42:23 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
for _, mp := range c.MountPoints {
|
|
|
|
ef(fmt.Sprintf("mounting %v with %d torrents...", mp.Path, len(mp.Torrents)))
|
2020-11-09 10:33:19 +00:00
|
|
|
if err := mountService.Mount(mp, ef); err != nil {
|
2020-11-08 17:19:25 +00:00
|
|
|
return fmt.Errorf("error mounting folder %v: %w", mp.Path, err)
|
|
|
|
}
|
2020-11-09 10:33:19 +00:00
|
|
|
ef(fmt.Sprintf("%v mounted", mp.Path))
|
2020-11-08 17:19:25 +00:00
|
|
|
}
|
2020-04-27 16:46:23 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
return nil
|
2020-05-08 14:37:43 +00:00
|
|
|
})
|
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
if err := ch.Reload(nil); err != nil {
|
|
|
|
return fmt.Errorf("error reloading configuration: %w", err)
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
2020-08-02 19:38:53 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
defer func() {
|
|
|
|
tryClose(c, mountService)
|
|
|
|
}()
|
|
|
|
|
|
|
|
return http.New(fc, ss, ch, port)
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
2020-07-27 09:20:19 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
func tryClose(c *t.Client, mountService *fuse.Handler) {
|
|
|
|
logrus.Info("closing torrent client...")
|
2020-07-27 09:20:19 +00:00
|
|
|
c.Close()
|
2020-11-08 17:19:25 +00:00
|
|
|
logrus.Info("unmounting fuse filesystem...")
|
|
|
|
mountService.UnmountAll()
|
2020-07-27 09:20:19 +00:00
|
|
|
|
2020-11-08 17:19:25 +00:00
|
|
|
logrus.Info("exiting")
|
2020-07-27 09:20:19 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|