Support global ENV setting. (#293)
* Support global ENV setting. Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * add viper package Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * fix typo Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * fix testing. Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * fix testing. Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
242
config/config.go
242
config/config.go
@@ -1,12 +1,85 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var defaultConf = []byte(`
|
||||
core:
|
||||
enabled: true # enabale httpd server
|
||||
address: "" # ip address to bind (default: any)
|
||||
port: "8088" # ignore this port number if auto_tls is enabled (listen 443).
|
||||
worker_num: 0 # default worker number is runtime.NumCPU()
|
||||
queue_num: 0 # default queue number is 8192
|
||||
max_notification: 100
|
||||
sync: false # set true if you need get error message from fail push notification in API response.
|
||||
mode: "release"
|
||||
ssl: false
|
||||
cert_path: "cert.pem"
|
||||
key_path: "key.pem"
|
||||
http_proxy: "" # only working for FCM server
|
||||
pid:
|
||||
enabled: false
|
||||
path: "gorush.pid"
|
||||
override: true
|
||||
auto_tls:
|
||||
enabled: false # Automatically install TLS certificates from Let's Encrypt.
|
||||
folder: ".cache" # folder for storing TLS certificates
|
||||
host: "" # which domains the Let's Encrypt will attempt
|
||||
|
||||
grpc:
|
||||
enabled: false # enabale gRPC server
|
||||
port: 9000
|
||||
|
||||
api:
|
||||
push_uri: "/api/push"
|
||||
stat_go_uri: "/api/stat/go"
|
||||
stat_app_uri: "/api/stat/app"
|
||||
config_uri: "/api/config"
|
||||
sys_stat_uri: "/sys/stats"
|
||||
metric_uri: "/metrics"
|
||||
|
||||
android:
|
||||
enabled: true
|
||||
apikey: "YOUR_API_KEY"
|
||||
max_retry: 0 # resend fail notification, default value zero is disabled
|
||||
|
||||
ios:
|
||||
enabled: false
|
||||
key_path: "key.pem"
|
||||
password: "" # certificate password, default as empty string.
|
||||
production: false
|
||||
max_retry: 0 # resend fail notification, default value zero is disabled
|
||||
|
||||
log:
|
||||
format: "string" # string or json
|
||||
access_log: "stdout" # stdout: output to console, or define log path like "log/access_log"
|
||||
access_level: "debug"
|
||||
error_log: "stderr" # stderr: output to console, or define log path like "log/error_log"
|
||||
error_level: "error"
|
||||
hide_token: true
|
||||
|
||||
stat:
|
||||
engine: "memory" # support memory, redis, boltdb, buntdb or leveldb
|
||||
redis:
|
||||
addr: "localhost:6379"
|
||||
password: ""
|
||||
db: 0
|
||||
boltdb:
|
||||
path: "bolt.db"
|
||||
bucket: "gorush"
|
||||
buntdb:
|
||||
path: "bunt.db"
|
||||
leveldb:
|
||||
path: "level.db"
|
||||
`)
|
||||
|
||||
// ConfYaml is config structure.
|
||||
type ConfYaml struct {
|
||||
Core SectionCore `yaml:"core"`
|
||||
@@ -124,97 +197,108 @@ type SectionGRPC struct {
|
||||
Port string `yaml:"port"`
|
||||
}
|
||||
|
||||
// BuildDefaultPushConf is default config setting.
|
||||
func BuildDefaultPushConf() ConfYaml {
|
||||
// LoadConf load config from file and read in environment variables that match
|
||||
func LoadConf(confPath string) (ConfYaml, error) {
|
||||
var conf ConfYaml
|
||||
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AutomaticEnv() // read in environment variables that match
|
||||
viper.SetEnvPrefix("gorush") // will be uppercased automatically
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
|
||||
if confPath != "" {
|
||||
content, err := ioutil.ReadFile(confPath)
|
||||
|
||||
if err != nil {
|
||||
return conf, err
|
||||
}
|
||||
|
||||
viper.ReadConfig(bytes.NewBuffer(content))
|
||||
} else {
|
||||
// Search config in home directory with name ".gorush" (without extension).
|
||||
viper.AddConfigPath("/etc/gorush/")
|
||||
viper.AddConfigPath("$HOME/.gorush")
|
||||
viper.AddConfigPath(".")
|
||||
viper.SetConfigName("config")
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
} else {
|
||||
// load default config
|
||||
viper.ReadConfig(bytes.NewBuffer(defaultConf))
|
||||
}
|
||||
}
|
||||
|
||||
// Core
|
||||
conf.Core.Address = ""
|
||||
conf.Core.Port = "8088"
|
||||
conf.Core.Enabled = true
|
||||
conf.Core.WorkerNum = int64(runtime.NumCPU())
|
||||
conf.Core.QueueNum = int64(8192)
|
||||
conf.Core.Mode = "release"
|
||||
conf.Core.Sync = false
|
||||
conf.Core.SSL = false
|
||||
conf.Core.CertPath = "cert.pem"
|
||||
conf.Core.KeyPath = "key.pem"
|
||||
conf.Core.MaxNotification = int64(100)
|
||||
conf.Core.HTTPProxy = ""
|
||||
conf.Core.PID.Enabled = false
|
||||
conf.Core.PID.Path = "gorush.pid"
|
||||
conf.Core.PID.Override = false
|
||||
conf.Core.AutoTLS.Enabled = false
|
||||
conf.Core.AutoTLS.Folder = ".cache"
|
||||
conf.Core.AutoTLS.Host = ""
|
||||
conf.Core.Address = viper.GetString("core.address")
|
||||
conf.Core.Port = viper.GetString("core.port")
|
||||
conf.Core.Enabled = viper.GetBool("core.enabled")
|
||||
conf.Core.WorkerNum = int64(viper.GetInt("core.worker_num"))
|
||||
conf.Core.QueueNum = int64(viper.GetInt("core.queue_num"))
|
||||
conf.Core.Mode = viper.GetString("core.mode")
|
||||
conf.Core.Sync = viper.GetBool("core.sync")
|
||||
conf.Core.SSL = viper.GetBool("core.ssl")
|
||||
conf.Core.CertPath = viper.GetString("core.cert_path")
|
||||
conf.Core.KeyPath = viper.GetString("core.key_path")
|
||||
conf.Core.MaxNotification = int64(viper.GetInt("core.max_notification"))
|
||||
conf.Core.HTTPProxy = viper.GetString("core.http_proxy")
|
||||
conf.Core.PID.Enabled = viper.GetBool("core.pid.enabled")
|
||||
conf.Core.PID.Path = viper.GetString("core.pid.path")
|
||||
conf.Core.PID.Override = viper.GetBool("core.pid.override")
|
||||
conf.Core.AutoTLS.Enabled = viper.GetBool("core.auto_tls.enabled")
|
||||
conf.Core.AutoTLS.Folder = viper.GetString("core.auto_tls.folder")
|
||||
conf.Core.AutoTLS.Host = viper.GetString("core.auto_tls.host")
|
||||
|
||||
// Api
|
||||
conf.API.PushURI = "/api/push"
|
||||
conf.API.StatGoURI = "/api/stat/go"
|
||||
conf.API.StatAppURI = "/api/stat/app"
|
||||
conf.API.ConfigURI = "/api/config"
|
||||
conf.API.SysStatURI = "/sys/stats"
|
||||
conf.API.MetricURI = "/metrics"
|
||||
conf.API.PushURI = viper.GetString("api.push_uri")
|
||||
conf.API.StatGoURI = viper.GetString("api.stat_go_uri")
|
||||
conf.API.StatAppURI = viper.GetString("api.stat_app_uri")
|
||||
conf.API.ConfigURI = viper.GetString("api.config_uri")
|
||||
conf.API.SysStatURI = viper.GetString("api.sys_stat_uri")
|
||||
conf.API.MetricURI = viper.GetString("api.metric_uri")
|
||||
|
||||
// Android
|
||||
conf.Android.Enabled = false
|
||||
conf.Android.APIKey = ""
|
||||
conf.Android.MaxRetry = 0
|
||||
conf.Android.Enabled = viper.GetBool("android.enabled")
|
||||
conf.Android.APIKey = viper.GetString("android.apikey")
|
||||
conf.Android.MaxRetry = viper.GetInt("android.max_retry")
|
||||
|
||||
// iOS
|
||||
conf.Ios.Enabled = false
|
||||
conf.Ios.KeyPath = "key.pem"
|
||||
conf.Ios.Password = ""
|
||||
conf.Ios.Production = false
|
||||
conf.Ios.MaxRetry = 0
|
||||
conf.Ios.Enabled = viper.GetBool("ios.enabled")
|
||||
conf.Ios.KeyPath = viper.GetString("ios.key_path")
|
||||
conf.Ios.Password = viper.GetString("ios.password")
|
||||
conf.Ios.Production = viper.GetBool("ios.production")
|
||||
conf.Ios.MaxRetry = viper.GetInt("ios.max_retry")
|
||||
|
||||
// log
|
||||
conf.Log.Format = "string"
|
||||
conf.Log.AccessLog = "stdout"
|
||||
conf.Log.AccessLevel = "debug"
|
||||
conf.Log.ErrorLog = "stderr"
|
||||
conf.Log.ErrorLevel = "error"
|
||||
conf.Log.HideToken = true
|
||||
conf.Log.Format = viper.GetString("log.format")
|
||||
conf.Log.AccessLog = viper.GetString("log.access_log")
|
||||
conf.Log.AccessLevel = viper.GetString("log.access_level")
|
||||
conf.Log.ErrorLog = viper.GetString("log.error_log")
|
||||
conf.Log.ErrorLevel = viper.GetString("log.error_level")
|
||||
conf.Log.HideToken = viper.GetBool("log.hide_token")
|
||||
|
||||
// Stat Engine
|
||||
conf.Stat.Engine = "memory"
|
||||
conf.Stat.Redis.Addr = "localhost:6379"
|
||||
conf.Stat.Redis.Password = ""
|
||||
conf.Stat.Redis.DB = 0
|
||||
conf.Stat.BoltDB.Path = "bolt.db"
|
||||
conf.Stat.BoltDB.Bucket = "gorush"
|
||||
conf.Stat.BuntDB.Path = "bunt.db"
|
||||
conf.Stat.LevelDB.Path = "level.db"
|
||||
conf.Stat.Engine = viper.GetString("stat.engine")
|
||||
conf.Stat.Redis.Addr = viper.GetString("stat.redis.addr")
|
||||
conf.Stat.Redis.Password = viper.GetString("stat.redis.password")
|
||||
conf.Stat.Redis.DB = viper.GetInt("stat.redis.db")
|
||||
conf.Stat.BoltDB.Path = viper.GetString("stat.boltdb.path")
|
||||
conf.Stat.BoltDB.Bucket = viper.GetString("stat.boltdb.bucket")
|
||||
conf.Stat.BuntDB.Path = viper.GetString("stat.buntdb.path")
|
||||
conf.Stat.LevelDB.Path = viper.GetString("stat.leveldb.path")
|
||||
|
||||
// gRPC Server
|
||||
conf.GRPC.Enabled = false
|
||||
conf.GRPC.Port = "9000"
|
||||
return conf
|
||||
}
|
||||
|
||||
// LoadConfYaml provide load yml config.
|
||||
func LoadConfYaml(confPath string) (ConfYaml, error) {
|
||||
var config ConfYaml
|
||||
|
||||
configFile, err := ioutil.ReadFile(confPath)
|
||||
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(configFile, &config)
|
||||
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
|
||||
if config.Core.WorkerNum == int64(0) {
|
||||
config.Core.WorkerNum = int64(runtime.NumCPU())
|
||||
}
|
||||
|
||||
if config.Core.QueueNum == int64(0) {
|
||||
config.Core.QueueNum = int64(8192)
|
||||
}
|
||||
|
||||
return config, nil
|
||||
conf.GRPC.Enabled = viper.GetBool("grpc.enabled")
|
||||
conf.GRPC.Port = viper.GetString("grpc.port")
|
||||
|
||||
if conf.Core.WorkerNum == int64(0) {
|
||||
conf.Core.WorkerNum = int64(runtime.NumCPU())
|
||||
}
|
||||
|
||||
if conf.Core.QueueNum == int64(0) {
|
||||
conf.Core.QueueNum = int64(8192)
|
||||
}
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
@@ -14,29 +12,7 @@ import (
|
||||
// Test file is missing
|
||||
func TestMissingFile(t *testing.T) {
|
||||
filename := "test"
|
||||
_, err := LoadConfYaml(filename)
|
||||
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
// Test wrong json format
|
||||
func TestWrongYAMLormat(t *testing.T) {
|
||||
content := []byte(`Wrong format`)
|
||||
|
||||
filename := "tempfile"
|
||||
|
||||
if err := ioutil.WriteFile(filename, content, 0644); err != nil {
|
||||
log.Fatalf("WriteFile %s: %v", filename, err)
|
||||
}
|
||||
|
||||
// clean up
|
||||
defer func() {
|
||||
err := os.Remove(filename)
|
||||
assert.Nil(t, err)
|
||||
}()
|
||||
|
||||
// parse JSON format error
|
||||
_, err := LoadConfYaml(filename)
|
||||
_, err := LoadConf(filename)
|
||||
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
@@ -48,11 +24,14 @@ type ConfigTestSuite struct {
|
||||
}
|
||||
|
||||
func (suite *ConfigTestSuite) SetupTest() {
|
||||
suite.ConfGorushDefault = BuildDefaultPushConf()
|
||||
var err error
|
||||
suite.ConfGorush, err = LoadConfYaml("config.yml")
|
||||
suite.ConfGorushDefault, err = LoadConf("")
|
||||
if err != nil {
|
||||
panic("failed to load config.yml")
|
||||
panic("failed to load default config.yml")
|
||||
}
|
||||
suite.ConfGorush, err = LoadConf("config.yml")
|
||||
if err != nil {
|
||||
panic("failed to load config.yml from file")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +52,7 @@ func (suite *ConfigTestSuite) TestValidateConfDefault() {
|
||||
// Pid
|
||||
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.PID.Enabled)
|
||||
assert.Equal(suite.T(), "gorush.pid", suite.ConfGorushDefault.Core.PID.Path)
|
||||
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.PID.Override)
|
||||
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Core.PID.Override)
|
||||
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.AutoTLS.Enabled)
|
||||
assert.Equal(suite.T(), ".cache", suite.ConfGorushDefault.Core.AutoTLS.Folder)
|
||||
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.AutoTLS.Host)
|
||||
@@ -87,8 +66,8 @@ func (suite *ConfigTestSuite) TestValidateConfDefault() {
|
||||
assert.Equal(suite.T(), "/metrics", suite.ConfGorushDefault.API.MetricURI)
|
||||
|
||||
// Android
|
||||
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Android.Enabled)
|
||||
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Android.APIKey)
|
||||
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Android.Enabled)
|
||||
assert.Equal(suite.T(), "YOUR_API_KEY", suite.ConfGorushDefault.Android.APIKey)
|
||||
assert.Equal(suite.T(), 0, suite.ConfGorushDefault.Android.MaxRetry)
|
||||
|
||||
// iOS
|
||||
@@ -190,3 +169,16 @@ func (suite *ConfigTestSuite) TestValidateConf() {
|
||||
func TestConfigTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(ConfigTestSuite))
|
||||
}
|
||||
|
||||
func TestLoadConfigFromEnv(t *testing.T) {
|
||||
os.Setenv("GORUSH_CORE_PORT", "9001")
|
||||
os.Setenv("GORUSH_GRPC_ENABLED", "true")
|
||||
os.Setenv("GORUSH_CORE_MAX_NOTIFICATION", "200")
|
||||
ConfGorush, err := LoadConf("config.yml")
|
||||
if err != nil {
|
||||
panic("failed to load config.yml from file")
|
||||
}
|
||||
assert.Equal(t, "9001", ConfGorush.Core.Port)
|
||||
assert.Equal(t, int64(200), ConfGorush.Core.MaxNotification)
|
||||
assert.True(t, ConfGorush.GRPC.Enabled)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user