mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
214 lines
5.2 KiB
Go
214 lines
5.2 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"github.com/gorilla/securecookie"
|
|
"github.com/jinzhu/configor"
|
|
"github.com/jinzhu/gorm"
|
|
"github.com/muety/wakapi/models"
|
|
migrate "github.com/rubenv/sql-migrate"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
defaultConfigPath = "config.yml"
|
|
defaultConfigPathLegacy = "config.ini"
|
|
defaultEnvConfigPathLegacy = ".env"
|
|
)
|
|
|
|
var (
|
|
cfg *Config
|
|
cFlag *string
|
|
)
|
|
|
|
type appConfig struct {
|
|
CleanUp bool `default:"false" env:"WAKAPI_CLEANUP"`
|
|
AggregationTime string `yaml:"aggregation_time" default:"02:15" env:"WAKAPI_AGGREGATION_TIME"`
|
|
CustomLanguages map[string]string `yaml:"custom_languages"`
|
|
LanguageColors map[string]string `yaml:"-"`
|
|
}
|
|
|
|
type securityConfig struct {
|
|
// this is actually a pepper (https://en.wikipedia.org/wiki/Pepper_(cryptography))
|
|
PasswordSalt string `yaml:"password_salt" default:"" env:"WAKAPI_PASSWORD_SALT"`
|
|
InsecureCookies bool `yaml:"insecure_cookies" default:"false" env:"WAKAPI_INSECURE_COOKIES"`
|
|
SecureCookie *securecookie.SecureCookie `yaml:"-"`
|
|
}
|
|
|
|
type dbConfig struct {
|
|
Host string `env:"WAKAPI_DB_HOST"`
|
|
Port uint `env:"WAKAPI_DB_PORT"`
|
|
User string `env:"WAKAPI_DB_USER"`
|
|
Password string `env:"WAKAPI_DB_PASSWORD"`
|
|
Name string `default:"wakapi_db.db" env:"WAKAPI_DB_NAME"`
|
|
Dialect string `default:"sqlite3" env:"WAKAPI_DB_TYPE"`
|
|
MaxConn uint `yaml:"max_conn" default:"2" env:"WAKAPI_DB_MAX_CONNECTIONS"`
|
|
}
|
|
|
|
type serverConfig struct {
|
|
Port int `default:"3000" env:"WAKAPI_PORT"`
|
|
ListenIpV4 string `yaml:"listen_ipv4" default:"127.0.0.1" env:"WAKAPI_LISTEN_IPV4"`
|
|
BasePath string `yaml:"base_path" default:"/" env:"WAKAPI_BASE_PATH"`
|
|
}
|
|
|
|
type Config struct {
|
|
Env string `default:"dev" env:"ENVIRONMENT"`
|
|
Version string `yaml:"-"`
|
|
App appConfig
|
|
Security securityConfig
|
|
Db dbConfig
|
|
Server serverConfig
|
|
}
|
|
|
|
func init() {
|
|
cFlag = flag.String("c", defaultConfigPath, "config file location")
|
|
flag.Parse()
|
|
}
|
|
|
|
func (c *Config) IsDev() bool {
|
|
return IsDev(c.Env)
|
|
}
|
|
|
|
func (c *Config) GetMigrationFunc(dbDialect string) models.MigrationFunc {
|
|
switch dbDialect {
|
|
case "sqlite3":
|
|
return func(db *gorm.DB) error {
|
|
migrations := &migrate.FileMigrationSource{
|
|
Dir: "migrations/sqlite3",
|
|
}
|
|
|
|
migrate.SetIgnoreUnknown(true)
|
|
n, err := migrate.Exec(db.DB(), "sqlite3", migrations, migrate.Up)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("applied %d migrations\n", n)
|
|
return nil
|
|
}
|
|
default:
|
|
return func(db *gorm.DB) error {
|
|
db.AutoMigrate(&models.Alias{})
|
|
db.AutoMigrate(&models.Summary{})
|
|
db.AutoMigrate(&models.SummaryItem{})
|
|
db.AutoMigrate(&models.User{})
|
|
db.AutoMigrate(&models.Heartbeat{}).AddForeignKey("user_id", "users(id)", "RESTRICT", "RESTRICT")
|
|
db.AutoMigrate(&models.SummaryItem{}).AddForeignKey("summary_id", "summaries(id)", "CASCADE", "CASCADE")
|
|
db.AutoMigrate(&models.KeyStringValue{})
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) GetFixturesFunc(dbDialect string) models.MigrationFunc {
|
|
return func(db *gorm.DB) error {
|
|
migrations := &migrate.FileMigrationSource{
|
|
Dir: "migrations/common/fixtures",
|
|
}
|
|
|
|
migrate.SetIgnoreUnknown(true)
|
|
n, err := migrate.Exec(db.DB(), dbDialect, migrations, migrate.Up)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("applied %d fixtures\n", n)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func IsDev(env string) bool {
|
|
return env == "dev" || env == "development"
|
|
}
|
|
|
|
func readVersion() string {
|
|
file, err := os.Open("version.txt")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer file.Close()
|
|
|
|
bytes, err := ioutil.ReadAll(file)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
return string(bytes)
|
|
}
|
|
|
|
func readLanguageColors() map[string]string {
|
|
// Read language colors
|
|
// Source: https://raw.githubusercontent.com/ozh/github-colors/master/colors.json
|
|
var colors = make(map[string]string)
|
|
var rawColors map[string]struct {
|
|
Color string `json:"color"`
|
|
Url string `json:"url"`
|
|
}
|
|
|
|
data, err := ioutil.ReadFile("data/colors.json")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := json.Unmarshal(data, &rawColors); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
for k, v := range rawColors {
|
|
colors[strings.ToLower(k)] = v.Color
|
|
}
|
|
|
|
return colors
|
|
}
|
|
|
|
func mustReadConfigLocation() string {
|
|
if _, err := os.Stat(*cFlag); err != nil {
|
|
log.Fatalf("failed to find config file at '%s'\n", *cFlag)
|
|
}
|
|
|
|
return *cFlag
|
|
}
|
|
|
|
func Set(config *Config) {
|
|
cfg = config
|
|
}
|
|
|
|
func Get() *Config {
|
|
return cfg
|
|
}
|
|
|
|
func Load() *Config {
|
|
config := &Config{}
|
|
|
|
maybeMigrateLegacyConfig()
|
|
|
|
if err := configor.New(&configor.Config{}).Load(config, mustReadConfigLocation()); err != nil {
|
|
log.Fatalf("failed to read config: %v\n", err)
|
|
}
|
|
|
|
config.Version = readVersion()
|
|
config.App.LanguageColors = readLanguageColors()
|
|
// TODO: Read keys from env, so that users are not logged out every time the server is restarted
|
|
config.Security.SecureCookie = securecookie.New(
|
|
securecookie.GenerateRandomKey(64),
|
|
securecookie.GenerateRandomKey(32),
|
|
)
|
|
|
|
if strings.HasSuffix(config.Server.BasePath, "/") {
|
|
config.Server.BasePath = config.Server.BasePath[:len(config.Server.BasePath)-1]
|
|
}
|
|
|
|
for k, v := range config.App.CustomLanguages {
|
|
if v == "" {
|
|
config.App.CustomLanguages[k] = "unknown"
|
|
}
|
|
}
|
|
|
|
Set(config)
|
|
return Get()
|
|
}
|