view pkg/config/config.go @ 1000:14425e35e3c2 persistent-import-queue

Wait with start of import queue until configuration is fully loaded.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 22 Oct 2018 17:16:02 +0200
parents 2818ad6c7d32
children a244b18cb916
line wrap: on
line source

package config

import (
	"crypto/sha256"
	"fmt"
	"log"
	"sync"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"

	"gemma.intevation.de/gemma/pkg/common"
)

// This is not part of the persistent config.
var configFile string

func ConfigFile() string { return configFile }

func DBHost() string     { return viper.GetString("db-host") }
func DBPort() uint       { return uint(viper.GetInt32("db-port")) }
func DBName() string     { return viper.GetString("db-name") }
func DBUser() string     { return viper.GetString("db-user") }
func DBPassword() string { return viper.GetString("db-password") }
func DBSSLMode() string  { return viper.GetString("db-ssl") }

func SessionStore() string { return viper.GetString("sessions") }

func Web() string     { return viper.GetString("web") }
func WebHost() string { return viper.GetString("host") }
func WebPort() uint   { return uint(viper.GetInt32("port")) }

func MailHost() string     { return viper.GetString("mail-host") }
func MailPort() uint       { return uint(viper.GetInt32("mail-port")) }
func MailUser() string     { return viper.GetString("mail-user") }
func MailPassword() string { return viper.GetString("mail-password") }
func MailFrom() string     { return viper.GetString("mail-from") }
func MailHelo() string     { return viper.GetString("mail-helo") }

func AllowedOrigins() []string { return viper.GetStringSlice("allowed-origins") }

func Proxies(key string) map[string]interface{} { return viper.GetStringMap(key) }

func GeoServerURL() string      { return viper.GetString("geoserver-url") }
func GeoServerUser() string     { return viper.GetString("geoserver-user") }
func GeoServerPassword() string { return viper.GetString("geoserver-password") }
func GeoServerClean() bool      { return viper.GetBool("geoserver-clean") }

func TmpDir() string { return viper.GetString("tmp-dir") }

var (
	proxyKeyOnce sync.Once
	proxyKey     []byte

	proxyPrefixOnce sync.Once
	proxyPrefix     string
)

func ProxyKey() []byte {
	fetchKey := func() {
		if proxyKey == nil {
			key := []byte(viper.GetString("proxy-key"))
			if len(key) == 0 {
				key = common.GenerateRandomKey(64)
			}
			hash := sha256.New()
			hash.Write(key)
			proxyKey = hash.Sum(nil)
		}
	}
	proxyKeyOnce.Do(fetchKey)
	return proxyKey
}

func ProxyPrefix() string {
	fetchPrefix := func() {
		if proxyPrefix == "" {
			proxyPrefix = fmt.Sprintf("http://%s:%d", WebHost(), WebPort())
		}
	}
	proxyPrefixOnce.Do(fetchPrefix)
	return proxyPrefix
}

var RootCmd = &cobra.Command{
	Use:   "gemma",
	Short: "gemma is a server for waterway monitoring and management",
}

var allowedOrigins = []string{
	// TODO: Fill me!
}

func init() {
	cobra.OnInitialize(initConfig)
	fl := RootCmd.PersistentFlags()
	fl.StringVarP(&configFile, "config", "c", "", "config file (default is $HOME/.gemma.toml)")

	vbind := func(name string) { viper.BindPFlag(name, fl.Lookup(name)) }

	str := func(name, value, usage string) {
		fl.String(name, value, usage)
		vbind(name)
	}
	strP := func(name, shorthand, value, usage string) {
		fl.StringP(name, shorthand, value, usage)
		vbind(name)
	}
	ui := func(name string, value uint, usage string) {
		fl.Uint(name, value, usage)
		vbind(name)
	}
	uiP := func(name, shorthand string, value uint, usage string) {
		fl.UintP(name, shorthand, value, usage)
		vbind(name)
	}
	strSl := func(name string, value []string, usage string) {
		fl.StringSlice(name, value, usage)
		vbind(name)
	}
	bl := func(name string, value bool, usage string) {
		fl.Bool(name, value, usage)
		vbind(name)
	}

	strP("db-host", "H", "localhost", "host of the database")
	uiP("db-port", "P", 5432, "port of the database")
	strP("db-name", "d", "gemma", "name of the database")
	str("db-user", "meta_login", "Metamorphic database user")
	str("db-password", "", "Metamorphic database user password")
	strP("db-ssl", "S", "prefer", "SSL mode of the database")

	strP("sessions", "s", "", "path to the sessions file")

	strP("web", "w", "./web", "path to the web files")
	strP("host", "o", "localhost", "host of the web app")
	uiP("port", "p", 8000, "port of the web app")

	str("mail-host", "localhost", "server to send mail with")
	ui("mail-port", 465, "port of server to send mail with")
	str("mail-user", "gemma", "user to authenticate against mail-host.\n"+
		"Leave empty for trying to send without auth.")
	str("mail-password", "", "password of user to send mail with")
	str("mail-from", "noreply@localhost", "from line of mails")
	str("mail-helo", "localhost", "name of server to send mail from.")

	strSl("allowed-origins", allowedOrigins, "allow access for remote origins")

	str("geoserver-url", "http://localhost:8080/geoserver", "URL to GeoServer")
	str("geoserver-user", "admin", "GeoServer user")
	str("geoserver-password", "geoserver", "GeoServer password")
	bl("geoserver-clean", false, "Clean GeoServer setup")

	str("proxy-key", "", `signing key for proxy URLs. Defaults to random key.`)
	str("proxy-prefix", "", `URL prefix of proxy. Defaults to "http://${web-host}:${web-port}"`)

	str("tmp-dir", "", "Temp directory of gemma server. Defaults to system temp directory.")
}

var (
	configCond  = sync.NewCond(new(sync.Mutex))
	configReady bool
)

func Ready() {
	configCond.L.Lock()
	defer configCond.L.Unlock()
	configReady = true
	configCond.Broadcast()
}

func WaitReady() {
	configCond.L.Lock()
	defer configCond.L.Unlock()
	for !configReady {
		configCond.Wait()
	}
}

func initConfig() {
	// Don't forget to read config either from cfgFile or from home directory!
	if configFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(configFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			log.Fatalf("error: %v\n", err)
		}

		// Search config in home directory with name ".cobra" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigName(".gemma")
	}
	if err := viper.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok && configFile == "" {
			// Don't bother if not found.
			return
		}
		log.Fatalf("Can't read config: %v\n", err)
	}
}