// Copyright (C) 2017 Marius Schellenberger package main import ( "errors" "git.giftfish.de/ston1th/godrop" "github.com/urfave/cli" logger "log" "net" "os" "os/signal" "syscall" "time" ) const ( blevePath = "bleve" defDataDir = "/var/lib/gowiki" defListen = "127.0.0.1:8090" defLogFile = "gowiki.log" defRunUser = "wiki" defRunGroup = "wiki" ) func server(conf serverConfig) (err error) { dropCfg := godrop.Config{ User: conf.User, Group: conf.Group, Foreground: conf.Foreground, } err = godrop.Drop(dropCfg, func() (net.Listener, error) { return net.Listen("tcp", conf.ListenAddr) }) if err != nil { return } if err = os.Chdir(conf.DataDir); err != nil { return } newLogger(conf.LogFile) l, err := godrop.GetListener() if err != nil { return } srv := NewHTTPServer(l, conf.Version, conf.SecureCookie) err = srv.Start() if err != nil { return } log.Println("gowiki started") sigs := make(chan os.Signal) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) sig := <-sigs log.Println("caught " + sig.String()) go func() { time.Sleep(time.Second * 20) log.Fatal(errors.New("stop timed out: killing")) }() err = srv.Stop() if err != nil { log.Println(err) } log.Println("gowiki stopped") return } var ( verbose bool conf serverConfig ) func run(app *cli.App) { app.Commands = []cli.Command{ { Name: "server", Usage: "start gowiki server", Flags: defaultFlags(serverFlags()), Action: func(c *cli.Context) error { conf.Version = app.Version if err := server(conf); err != nil { logger.Fatal("server: ", err) } return nil }, }, { Name: "dump", Usage: "create a json dump of all articles in the data directory (dump is written to stdout) gowiki needs to be stopped", Flags: defaultFlags(dumpRestoreFlags()), Action: func(c *cli.Context) error { if err := os.Chdir(conf.DataDir); err != nil { logger.Fatal("dump: ", err) } if err := dump(blevePath, verbose); err != nil { logger.Fatal("dump: ", err) } return nil }, }, { Name: "restore", Usage: "restore a json dump to the data directory (dump is read from stdin) gowiki needs to be stopped", Flags: defaultFlags(dumpRestoreFlags()), Action: func(c *cli.Context) error { if err := os.Chdir(conf.DataDir); err != nil { logger.Fatal("restore: ", err) } if err := restore(blevePath, verbose); err != nil { logger.Fatal("restore: ", err) } return nil }, }, } app.Run(os.Args) } type serverConfig struct { DataDir string User string Group string ListenAddr string LogFile string Version string Foreground bool SecureCookie bool } func serverFlags() []cli.Flag { return []cli.Flag{ cli.StringFlag{ Name: "user, u", Value: defRunUser, Usage: "drop privileges to user", Destination: &conf.User, }, cli.StringFlag{ Name: "group, g", Value: defRunGroup, Usage: "drop privileges to group", Destination: &conf.Group, }, cli.StringFlag{ Name: "listen, l", Value: defListen, Usage: "listening
:", Destination: &conf.ListenAddr, }, cli.StringFlag{ Name: "log", Value: defLogFile, Usage: "log file (leave empty for stdout, this only works in combination with -f)", Destination: &conf.LogFile, }, cli.BoolFlag{ Name: "foreground, f", Usage: "do not fork into the background", Destination: &conf.Foreground, }, cli.BoolFlag{ Name: "secure, s", Usage: "enable secure cookie", Destination: &conf.SecureCookie, }, } } func dumpRestoreFlags() []cli.Flag { return []cli.Flag{ cli.BoolFlag{ Name: "verbose, v", Usage: "enable verbose mode", Destination: &verbose, }, } } func defaultFlags(f []cli.Flag) []cli.Flag { return append([]cli.Flag{ cli.StringFlag{ Name: "data, d", Value: defDataDir, Usage: "data directory", Destination: &conf.DataDir, }, }, f...) }