filebrowser/backend/cmd/root.go

169 lines
4.6 KiB
Go
Raw Normal View History

package cmd
import (
"crypto/tls"
2023-09-03 22:03:00 +00:00
"flag"
2021-12-20 22:16:35 +00:00
"io"
"io/fs"
"log"
"net"
"net/http"
"os"
"os/signal"
2023-06-18 15:04:31 +00:00
"strconv"
"syscall"
2023-09-03 22:03:00 +00:00
"github.com/spf13/pflag"
2020-07-27 17:01:02 +00:00
"github.com/spf13/afero"
"github.com/spf13/cobra"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
2020-05-31 23:12:36 +00:00
2023-09-02 00:22:38 +00:00
"github.com/gtsteffaniak/filebrowser/auth"
2023-06-15 01:08:09 +00:00
"github.com/gtsteffaniak/filebrowser/diskcache"
fbhttp "github.com/gtsteffaniak/filebrowser/http"
"github.com/gtsteffaniak/filebrowser/img"
2023-06-18 15:04:31 +00:00
"github.com/gtsteffaniak/filebrowser/search"
2023-06-15 01:08:09 +00:00
"github.com/gtsteffaniak/filebrowser/settings"
"github.com/gtsteffaniak/filebrowser/users"
)
type dirFS struct {
http.Dir
}
func (d dirFS) Open(name string) (fs.File, error) {
return d.Dir.Open(name)
}
func init() {
2023-09-03 22:03:00 +00:00
// Define a flag for the config option (-c or --config)
configFlag := pflag.StringP("config", "c", "filebrowser.yaml", "Path to the config file")
// Bind the flags to the pflag command line parser
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
log.Println("Initializing with config file:", *configFlag)
settings.Initialize(*configFlag)
}
var rootCmd = &cobra.Command{
2023-09-03 22:03:00 +00:00
Use: "filebrowser",
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
2023-09-01 14:00:02 +00:00
serverConfig := settings.GlobalConfiguration.Server
if !d.hadDB {
2023-09-03 22:03:00 +00:00
quickSetup(d)
}
2023-09-02 02:03:45 +00:00
if serverConfig.NumImageProcessors < 1 {
2020-07-23 00:41:19 +00:00
log.Fatal("Image resize workers count could not be < 1")
}
2023-09-25 01:03:09 +00:00
setupLog(serverConfig.Log)
2023-09-02 02:03:45 +00:00
imgSvc := img.New(serverConfig.NumImageProcessors)
2020-07-27 17:01:02 +00:00
var fileCache diskcache.Interface = diskcache.NewNoOp()
2023-09-01 14:00:02 +00:00
cacheDir := "/tmp"
2020-07-27 17:01:02 +00:00
if cacheDir != "" {
2021-07-26 10:00:05 +00:00
if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet,gomnd
2020-07-27 17:01:02 +00:00
log.Fatalf("can't make directory %s: %s", cacheDir, err)
}
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
}
2023-09-01 14:00:02 +00:00
// initialize indexing and schedule indexing ever n minutes (default 5)
go search.InitializeIndex(serverConfig.IndexingInterval)
_, err := os.Stat(serverConfig.Root)
checkErr(err)
var listener net.Listener
2023-09-02 00:22:38 +00:00
address := serverConfig.Address + ":" + strconv.Itoa(serverConfig.Port)
2020-05-31 23:12:36 +00:00
switch {
2023-09-01 14:00:02 +00:00
case serverConfig.Socket != "":
listener, err = net.Listen("unix", serverConfig.Socket)
checkErr(err)
2020-09-11 14:02:16 +00:00
socketPerm, err := cmd.Flags().GetUint32("socket-perm") //nolint:govet
checkErr(err)
2023-09-01 14:00:02 +00:00
err = os.Chmod(serverConfig.Socket, os.FileMode(socketPerm))
checkErr(err)
2023-09-01 14:00:02 +00:00
case serverConfig.TLSKey != "" && serverConfig.TLSCert != "":
cer, err := tls.LoadX509KeyPair(serverConfig.TLSCert, serverConfig.TLSKey) //nolint:govet
checkErr(err)
2023-09-01 14:00:02 +00:00
listener, err = tls.Listen("tcp", address, &tls.Config{
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cer}},
)
checkErr(err)
2020-05-31 23:12:36 +00:00
default:
2023-09-01 14:00:02 +00:00
listener, err = net.Listen("tcp", address)
checkErr(err)
}
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
go cleanupHandler(listener, sigc)
assetsFs := dirFS{Dir: http.Dir("frontend/dist")}
2023-09-01 14:00:02 +00:00
handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, &serverConfig, assetsFs)
checkErr(err)
defer listener.Close()
log.Println("Listening on", listener.Addr().String())
2023-02-16 08:11:12 +00:00
//nolint: gosec
if err := http.Serve(listener, handler); err != nil {
log.Fatal(err)
}
}, pythonConfig{allowNoDB: true}),
}
2023-09-02 16:05:40 +00:00
func StartFilebrowser() {
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
}
}
2020-05-31 23:12:36 +00:00
func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfacer
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
listener.Close()
os.Exit(0)
}
func setupLog(logMethod string) {
switch logMethod {
case "stdout":
log.SetOutput(os.Stdout)
case "stderr":
log.SetOutput(os.Stderr)
case "":
2021-12-20 22:16:35 +00:00
log.SetOutput(io.Discard)
default:
log.SetOutput(&lumberjack.Logger{
Filename: logMethod,
MaxSize: 100,
MaxAge: 14,
MaxBackups: 10,
})
}
}
2023-09-03 22:03:00 +00:00
func quickSetup(d pythonData) {
2023-09-03 17:28:00 +00:00
settings.GlobalConfiguration.Key = generateKey()
2023-09-02 02:03:45 +00:00
if settings.GlobalConfiguration.Auth.Method == "noauth" {
2023-09-25 01:03:09 +00:00
err := d.store.Auth.Save(&auth.NoAuth{})
checkErr(err)
2023-09-02 00:22:38 +00:00
} else {
2023-09-03 17:28:00 +00:00
settings.GlobalConfiguration.Auth.Method = "password"
2023-09-25 01:03:09 +00:00
err := d.store.Auth.Save(&auth.JSONAuth{})
checkErr(err)
2023-09-02 00:22:38 +00:00
}
2023-09-25 01:03:09 +00:00
err := d.store.Settings.Save(&settings.GlobalConfiguration)
checkErr(err)
2023-09-03 17:28:00 +00:00
err = d.store.Settings.SaveServer(&settings.GlobalConfiguration.Server)
checkErr(err)
2023-09-03 22:03:00 +00:00
username := settings.GlobalConfiguration.AdminUsername
password := settings.GlobalConfiguration.AdminPassword
if username == "" || password == "" {
log.Fatal("username and password cannot be empty during quick setup")
}
user := &users.User{
Username: username,
Password: password,
LockPassword: false,
}
user.Perm.Admin = true
err = d.store.Users.Save(user)
checkErr(err)
}