MapyWeb/config/config.go
2021-09-20 03:36:20 -07:00

301 lines
6.8 KiB
Go

package config
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"runtime"
"github.com/rs/zerolog"
"github.com/spf13/viper"
)
const (
// Version roughly represents the applications current version.
Version = "0.2"
// Title is the name of the application used throughout the configuration process.
Title = "mapyweb"
)
var (
// BannerOnly when toggled causes the appllication to only print the banner and version then exit.
BannerOnly = false
// GenConfig when toggled causes the application to write its default config to the cwd and then exit.
GenConfig = false
// NoColor when true will disable the banner and any colored console output.
NoColor bool
)
// "http"
var (
// HTTPBindAddr is defined via our toml configuration file. It is the address that the http server listens on.
HTTPBindAddr string
// HTTPBindPort is defined via our toml configuration file. It is the port that the http server listens on.
HTTPBindPort string
// UseUnixSocket when toggled disables the TCP listener and listens on the given UnixSocketPath.
UseUnixSocket bool
// UnixSocketPath is the path of the unix socket used when UseUnixSocket is toggled.
UnixSocketPath = ""
// HTTPUseSSL determins whether or not we serve HTTPs
HTTPUseSSL bool
// SSLCertFile is our fullchain SSL Certificate
SSLCertFile string
// SSLKeyFile is our SSL Certificate private key
SSLKeyFile string
)
// "db"
var (
UseEmbeddedPostgres bool
SQLHost string
SQLPort string
SQLUsername string
SQLPassword string
SQLDatabase string
DataPath string
)
var (
// Filename returns the current location of our toml config file.
Filename string
)
var (
f *os.File
err error
noColorForce = false
customconfig = false
home string
configLocations []string
)
var (
// Debug is our global debug toggle
Debug bool
prefConfigLocation string
snek *viper.Viper
)
func init() {
if home, err = os.UserHomeDir(); err != nil {
panic(err)
}
prefConfigLocation = home + "/.config/" + Title
snek = viper.New()
}
func writeConfig() {
if runtime.GOOS != "windows" {
if _, err := os.Stat(prefConfigLocation); os.IsNotExist(err) {
if err = os.Mkdir(prefConfigLocation, 0755); err != nil {
println("error writing new config: " + err.Error())
}
}
newconfig := prefConfigLocation + "/" + "config.toml"
if err = snek.SafeWriteConfigAs(newconfig); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
Filename = newconfig
return
}
newconfig := Title
snek.SetConfigName(newconfig)
if err = snek.MergeInConfig(); err != nil {
if err = snek.SafeWriteConfigAs(newconfig + ".toml"); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}
Filename = newconfig
}
// Init will initialize our toml configuration engine and define our default configuration values which can be written to a new configuration file if desired
func Init() {
snek.SetConfigType("toml")
snek.SetConfigName("config")
argParse()
if customconfig {
associate()
return
}
acquireClue()
setDefaults()
for _, loc := range configLocations {
snek.AddConfigPath(loc)
}
if err = snek.MergeInConfig(); err != nil {
writeConfig()
}
if len(Filename) < 1 {
Filename = snek.ConfigFileUsed()
}
associate()
}
func setDefaults() {
var (
// Add new configuration categories here
configSections = []string{"logger", "http", "db"}
deflogdir = home + "/.config/" + Title + "/logs/"
defNoColor = false
)
if runtime.GOOS == "windows" {
deflogdir = "logs/"
defNoColor = true
}
Opt := make(map[string]map[string]interface{})
Opt["logger"] = map[string]interface{}{
"debug": true,
"directory": deflogdir,
"nocolor": defNoColor,
"use_date_filename": true,
}
Opt["http"] = map[string]interface{}{
"use_unix_socket": false,
"unix_socket_path": "/var/run/cokeplate",
"bind_addr": "127.0.0.1",
"bind_port": "8080",
}
Opt["db"] = map[string]interface{}{
"embedded_pgsql": true,
"sql_host": "localhost",
"sql_port": "5432",
"sql_user": "postgres",
"sql_pass": "postgres",
"data_path": "./data",
}
for _, def := range configSections {
snek.SetDefault(def, Opt[def])
}
if GenConfig {
if err = snek.SafeWriteConfigAs("./config.toml"); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
os.Exit(0)
}
}
func acquireClue() {
configLocations = append(configLocations, "./")
if runtime.GOOS != "windows" {
configLocations = append(configLocations, prefConfigLocation)
configLocations = append(configLocations, "/etc/"+Title+"/")
configLocations = append(configLocations, "../")
configLocations = append(configLocations, "../../")
}
}
func loadCustomConfig(path string) {
if f, err = os.Open(path); err != nil {
println("Error opening specified config file: " + path)
panic("config file open fatal error: " + err.Error())
}
buf, err := ioutil.ReadAll(f)
err2 := snek.ReadConfig(bytes.NewBuffer(buf))
switch {
case err != nil:
fmt.Println("config file read fatal error: ", err.Error())
case err2 != nil:
fmt.Println("config file read fatal error: ", err2.Error())
default:
break
}
customconfig = true
}
func printUsage() {
println("\n" + Title + " v" + Version + " Usage\n")
println("-c <config.toml> - Specify config file")
println("--nocolor - disable color and banner ")
println("--banner - show banner + version and exit")
println("--genconfig - write default config to 'default.toml' then exit")
os.Exit(0)
}
// TODO: should probably just make a proper CLI with flags or something
func argParse() {
for i, arg := range os.Args {
switch arg {
case "-h":
printUsage()
case "--genconfig":
GenConfig = true
case "--nocolor":
noColorForce = true
case "--banner":
BannerOnly = true
case "--config":
fallthrough
case "-c":
if len(os.Args) <= i-1 {
panic("syntax error! expected file after -c")
}
loadCustomConfig(os.Args[i+1])
default:
continue
}
}
}
func bl(key string) bool {
return snek.GetBool(key)
}
func st(key string) string {
return snek.GetString(key)
}
func sl(key string) []string {
return snek.GetStringSlice(key)
}
func it(key string) int {
return snek.GetInt(key)
}
func associate() {
HTTPBindAddr = st("http.bind_addr")
HTTPBindPort = st("http.bind_port")
UseUnixSocket = bl("http.use_unix_socket")
SQLPassword = st("db.sql_password")
SQLUsername = st("db.sql_username")
SQLDatabase = st("db.sql_database")
SQLHost = st("db.sql_host")
SQLPort = st("db.sql_port")
DataPath = st("db.data_path")
Debug = bl("logger.debug")
logDir = st("logger.directory")
NoColor = bl("logger.nocolor")
if noColorForce {
NoColor = true
}
// if UseUnixSocket {
// UnixSocketPath = snek.GetString("http.unix_socket_path")
// }
if Debug {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
}