2018-05-15 13:54:36 +02:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2018-05-23 14:52:38 +02:00
|
|
|
"math/rand"
|
2018-07-31 15:29:15 +02:00
|
|
|
"net/url"
|
2018-05-23 14:52:38 +02:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
2018-05-15 13:54:36 +02:00
|
|
|
"github.com/joho/godotenv"
|
|
|
|
"github.com/kelseyhightower/envconfig"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/usefathom/fathom/pkg/datastore/sqlstore"
|
|
|
|
)
|
|
|
|
|
2018-05-21 11:54:01 +02:00
|
|
|
// Config wraps the configuration structs for the various application parts
|
2018-05-15 13:54:36 +02:00
|
|
|
type Config struct {
|
|
|
|
Database *sqlstore.Config
|
2018-05-21 11:54:01 +02:00
|
|
|
Secret string
|
2018-05-15 13:54:36 +02:00
|
|
|
}
|
|
|
|
|
2018-07-15 21:09:44 +07:00
|
|
|
// LoadEnv loads env values from the supplied file
|
|
|
|
func LoadEnv(file string) {
|
|
|
|
if file == "" {
|
|
|
|
log.Warn("Missing configuration file. Using defaults.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
absFile, _ := filepath.Abs(file)
|
|
|
|
_, err := os.Stat(absFile)
|
|
|
|
fileNotExists := os.IsNotExist(err)
|
|
|
|
|
|
|
|
if fileNotExists {
|
|
|
|
log.Warnf("Error reading configuration. File `%s` does not exist.", file)
|
|
|
|
return
|
|
|
|
}
|
2018-05-23 09:03:42 +02:00
|
|
|
|
2018-07-15 21:09:44 +07:00
|
|
|
log.Printf("Configuration file: %s", absFile)
|
|
|
|
|
|
|
|
// read file into env values
|
|
|
|
err = godotenv.Load(absFile)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error parsing configuration file: %s", err)
|
2018-05-15 13:54:36 +02:00
|
|
|
}
|
2018-07-15 21:09:44 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse environment into a Config struct
|
|
|
|
func Parse() *Config {
|
|
|
|
var cfg Config
|
2018-05-15 13:54:36 +02:00
|
|
|
|
2018-05-23 09:03:42 +02:00
|
|
|
// with config file loaded into env values, we can now parse env into our config struct
|
2018-07-15 21:09:44 +07:00
|
|
|
err := envconfig.Process("Fathom", &cfg)
|
2018-05-15 13:54:36 +02:00
|
|
|
if err != nil {
|
2018-05-23 09:03:42 +02:00
|
|
|
log.Fatalf("Error parsing configuration from environment: %s", err)
|
2018-05-15 13:54:36 +02:00
|
|
|
}
|
|
|
|
|
2018-07-29 13:32:04 -03:00
|
|
|
if cfg.Database.URL != "" {
|
2018-07-31 15:29:15 +02:00
|
|
|
_, err := url.Parse(cfg.Database.URL)
|
2018-07-29 13:32:04 -03:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error parsing DATABASE_URL from environment: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-15 13:54:36 +02:00
|
|
|
// alias sqlite to sqlite3
|
|
|
|
if cfg.Database.Driver == "sqlite" {
|
|
|
|
cfg.Database.Driver = "sqlite3"
|
|
|
|
}
|
|
|
|
|
2018-05-28 13:03:28 +02:00
|
|
|
// use absolute path to sqlite3 database
|
|
|
|
if cfg.Database.Driver == "sqlite3" {
|
|
|
|
cfg.Database.Name, _ = filepath.Abs(cfg.Database.Name)
|
|
|
|
}
|
|
|
|
|
2018-05-15 13:54:36 +02:00
|
|
|
// if secret key is empty, use a randomly generated one
|
|
|
|
if cfg.Secret == "" {
|
|
|
|
cfg.Secret = randomString(40)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
func randomString(len int) string {
|
|
|
|
bytes := make([]byte, len)
|
|
|
|
for i := 0; i < len; i++ {
|
|
|
|
bytes[i] = byte(65 + rand.Intn(25)) //A=65 and Z = 65+25
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(bytes)
|
|
|
|
}
|