145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/hacdias/webdav/v4/lib"
|
|
"github.com/spf13/cobra"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
func init() {
|
|
flags := rootCmd.Flags()
|
|
flags.StringP("config", "c", "", "config file path")
|
|
flags.BoolP("tls", "t", lib.DefaultTLS, "enable TLS")
|
|
flags.Bool("auth", lib.DefaultAuth, "enable authentication")
|
|
flags.String("cert", lib.DefaultCert, "path to TLS certificate")
|
|
flags.String("key", lib.DefaultKey, "path to TLS key")
|
|
flags.StringP("address", "a", lib.DefaultAddress, "address to listen on")
|
|
flags.IntP("port", "p", lib.DefaultPort, "port to listen on")
|
|
flags.StringP("prefix", "P", lib.DefaultPrefix, "URL path prefix")
|
|
flags.String("log_format", lib.DefaultLogFormat, "logging format")
|
|
}
|
|
|
|
var rootCmd = &cobra.Command{
|
|
Use: "webdav",
|
|
Short: "A simple to use WebDAV server",
|
|
Long: `If you don't set "config", it will look for a configuration file called
|
|
config.{json, toml, yaml, yml} in the following directories:
|
|
|
|
- ./
|
|
- /etc/webdav/
|
|
|
|
The precedence of the configuration values are as follows:
|
|
|
|
- flags
|
|
- environment variables
|
|
- configuration file
|
|
- defaults
|
|
|
|
The environment variables are prefixed by "WD_" followed by the option
|
|
name in caps. So to set "cert" via an env variable, you should
|
|
set WD_CERT.`,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
flags := cmd.Flags()
|
|
|
|
cfgFilename, _ := flags.GetString("config")
|
|
|
|
cfg, err := lib.ParseConfig(cfgFilename, flags)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create HTTP handler from the config
|
|
handler, err := lib.NewHandler(cfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Setup the logger based on the configuration
|
|
err = setupLogger(cfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
// Flush the logger at the end
|
|
_ = zap.L().Sync()
|
|
}()
|
|
|
|
// Build listener
|
|
listener, err := getListener(cfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Trap exiting signals
|
|
quit := make(chan os.Signal, 1)
|
|
|
|
go func() {
|
|
zap.L().Info("listening", zap.String("address", listener.Addr().String()))
|
|
|
|
var err error
|
|
if cfg.TLS {
|
|
err = http.ServeTLS(listener, handler, cfg.Cert, cfg.Key)
|
|
} else {
|
|
err = http.Serve(listener, handler)
|
|
}
|
|
|
|
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
zap.L().Error("failed to start server", zap.Error(err))
|
|
}
|
|
|
|
quit <- os.Interrupt
|
|
}()
|
|
|
|
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
|
|
signal := <-quit
|
|
|
|
zap.L().Info("caught signal, shutting down", zap.Stringer("signal", signal))
|
|
_ = listener.Close()
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func getListener(cfg *lib.Config) (net.Listener, error) {
|
|
var (
|
|
address string
|
|
network string
|
|
)
|
|
|
|
if strings.HasPrefix(cfg.Address, "unix:") {
|
|
address = cfg.Address[5:]
|
|
network = "unix"
|
|
} else {
|
|
address = fmt.Sprintf("%s:%d", cfg.Address, cfg.Port)
|
|
network = "tcp"
|
|
}
|
|
|
|
return net.Listen(network, address)
|
|
}
|
|
|
|
func setupLogger(cfg *lib.Config) error {
|
|
loggerConfig := zap.NewProductionConfig()
|
|
loggerConfig.DisableCaller = true
|
|
if cfg.Debug {
|
|
loggerConfig.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
|
|
}
|
|
loggerConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
loggerConfig.Encoding = cfg.LogFormat
|
|
logger, err := loggerConfig.Build()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
zap.ReplaceGlobals(logger)
|
|
return nil
|
|
}
|