2017-10-01 23:30:48 +02:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2017-10-10 00:54:14 +02:00
|
|
|
"crypto/tls"
|
2017-12-14 21:30:07 +01:00
|
|
|
"net/http"
|
2017-10-01 23:30:48 +02:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"syscall"
|
2017-10-10 00:54:14 +02:00
|
|
|
"time"
|
2017-10-01 23:30:48 +02:00
|
|
|
|
2017-10-10 00:54:14 +02:00
|
|
|
"golang.org/x/crypto/acme/autocert"
|
|
|
|
|
2017-12-14 21:30:07 +01:00
|
|
|
"github.com/genofire/yaja/database"
|
|
|
|
"github.com/genofire/yaja/model/config"
|
2017-10-02 14:38:52 +02:00
|
|
|
|
2017-12-14 21:30:07 +01:00
|
|
|
"github.com/genofire/golang-lib/file"
|
2017-10-10 00:54:14 +02:00
|
|
|
"github.com/genofire/golang-lib/worker"
|
2017-12-14 21:30:07 +01:00
|
|
|
"github.com/genofire/yaja/server"
|
2017-10-01 23:30:48 +02:00
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
2017-10-02 14:38:52 +02:00
|
|
|
var configPath string
|
|
|
|
|
2017-10-10 00:54:14 +02:00
|
|
|
var (
|
2017-12-14 21:30:07 +01:00
|
|
|
configData = &config.Config{}
|
|
|
|
db = &database.State{}
|
2017-10-10 00:54:14 +02:00
|
|
|
statesaveWorker *worker.Worker
|
|
|
|
srv *server.Server
|
|
|
|
certs *tls.Config
|
|
|
|
)
|
|
|
|
|
2017-12-14 21:30:07 +01:00
|
|
|
// serverCmd represents the serve command
|
|
|
|
var serverCmd = &cobra.Command{
|
|
|
|
Use: "server",
|
2017-10-01 23:30:48 +02:00
|
|
|
Short: "Runs the yaja server",
|
2017-10-02 14:38:52 +02:00
|
|
|
Example: "yaja serve -c /etc/yaja.conf",
|
2017-10-01 23:30:48 +02:00
|
|
|
Run: func(cmd *cobra.Command, args []string) {
|
2017-10-10 00:54:14 +02:00
|
|
|
var err error
|
2017-12-14 21:30:07 +01:00
|
|
|
err = file.ReadTOML(configPath, configData)
|
2017-10-02 14:38:52 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("unable to load config file:", err)
|
|
|
|
}
|
|
|
|
|
2017-12-14 21:30:07 +01:00
|
|
|
log.SetLevel(log.DebugLevel)
|
|
|
|
|
|
|
|
err = file.ReadJSON(configData.StatePath, db)
|
2017-10-10 00:54:14 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Warn("unable to load state file:", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
statesaveWorker = worker.NewWorker(time.Minute, func() {
|
2017-12-14 21:30:07 +01:00
|
|
|
file.SaveJSON(configData.StatePath, db)
|
2017-10-10 00:54:14 +02:00
|
|
|
log.Info("save state to:", configData.StatePath)
|
|
|
|
})
|
|
|
|
|
|
|
|
m := autocert.Manager{
|
|
|
|
Cache: autocert.DirCache(configData.TLSDir),
|
|
|
|
Prompt: autocert.AcceptTOS,
|
|
|
|
}
|
|
|
|
|
2017-12-14 21:30:07 +01:00
|
|
|
// https server to handle acme (by letsencrypt)
|
|
|
|
httpServer := &http.Server{
|
|
|
|
Addr: ":https",
|
|
|
|
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
|
|
|
|
}
|
|
|
|
go httpServer.ListenAndServeTLS("", "")
|
2017-10-10 00:54:14 +02:00
|
|
|
|
|
|
|
srv = &server.Server{
|
2017-12-14 21:30:07 +01:00
|
|
|
TLSManager: &m,
|
|
|
|
Database: db,
|
|
|
|
ClientAddr: configData.Address.Client,
|
|
|
|
ServerAddr: configData.Address.Server,
|
2017-10-10 00:54:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
go statesaveWorker.Start()
|
|
|
|
go srv.Start()
|
|
|
|
|
2017-10-02 14:38:52 +02:00
|
|
|
log.Infoln("yaja started ")
|
2017-10-01 23:30:48 +02:00
|
|
|
|
|
|
|
// Wait for INT/TERM
|
|
|
|
sigs := make(chan os.Signal, 1)
|
2017-10-10 00:54:14 +02:00
|
|
|
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1)
|
|
|
|
for sig := range sigs {
|
|
|
|
log.Infoln("received", sig)
|
|
|
|
switch sig {
|
|
|
|
case syscall.SIGTERM:
|
|
|
|
log.Panic("terminated")
|
|
|
|
os.Exit(0)
|
|
|
|
case syscall.SIGQUIT:
|
|
|
|
quit()
|
|
|
|
case syscall.SIGHUP:
|
|
|
|
quit()
|
|
|
|
case syscall.SIGUSR1:
|
|
|
|
reload()
|
|
|
|
}
|
|
|
|
}
|
2017-10-01 23:30:48 +02:00
|
|
|
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-10-10 00:54:14 +02:00
|
|
|
func quit() {
|
|
|
|
srv.Close()
|
|
|
|
statesaveWorker.Close()
|
|
|
|
|
2017-12-14 21:30:07 +01:00
|
|
|
file.SaveJSON(configData.StatePath, db)
|
2017-10-10 00:54:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func reload() {
|
|
|
|
log.Info("start reloading...")
|
2017-12-14 21:30:07 +01:00
|
|
|
var configNewData *config.Config
|
|
|
|
err := file.ReadTOML(configPath, configNewData)
|
2017-10-10 00:54:14 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Warn("unable to load config file:", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-12-14 21:30:07 +01:00
|
|
|
//TODO fetch changing address (to set restart)
|
|
|
|
|
2017-10-10 00:54:14 +02:00
|
|
|
if configNewData.StatePath != configData.StatePath {
|
|
|
|
statesaveWorker.Close()
|
|
|
|
statesaveWorker := worker.NewWorker(time.Minute, func() {
|
2017-12-14 21:30:07 +01:00
|
|
|
file.SaveJSON(configNewData.StatePath, db)
|
2017-10-10 00:54:14 +02:00
|
|
|
log.Info("save state to:", configNewData.StatePath)
|
|
|
|
})
|
|
|
|
go statesaveWorker.Start()
|
|
|
|
}
|
|
|
|
|
|
|
|
restartServer := false
|
|
|
|
|
|
|
|
if configNewData.TLSDir != configData.TLSDir {
|
|
|
|
|
|
|
|
m := autocert.Manager{
|
|
|
|
Cache: autocert.DirCache(configData.TLSDir),
|
|
|
|
Prompt: autocert.AcceptTOS,
|
|
|
|
}
|
|
|
|
|
|
|
|
certs = &tls.Config{GetCertificate: m.GetCertificate}
|
|
|
|
restartServer = true
|
|
|
|
}
|
|
|
|
|
|
|
|
newServer := &server.Server{
|
|
|
|
TLSConfig: certs,
|
2017-12-14 21:30:07 +01:00
|
|
|
Database: db,
|
|
|
|
ClientAddr: configNewData.Address.Client,
|
|
|
|
ServerAddr: configNewData.Address.Server,
|
2017-10-10 00:54:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if restartServer {
|
|
|
|
go srv.Start()
|
|
|
|
//TODO should fetch new server error
|
|
|
|
srv.Close()
|
|
|
|
srv = newServer
|
|
|
|
}
|
|
|
|
|
|
|
|
configData = configNewData
|
|
|
|
log.Info("reloaded")
|
|
|
|
}
|
|
|
|
|
2017-10-01 23:30:48 +02:00
|
|
|
func init() {
|
2017-12-14 21:30:07 +01:00
|
|
|
RootCmd.AddCommand(serverCmd)
|
|
|
|
serverCmd.Flags().StringVarP(&configPath, "config", "c", "yaja.conf", "Path to configuration file")
|
2017-10-01 23:30:48 +02:00
|
|
|
}
|