From b4b58697c5da0a1bfe3be8de39d733a80f9f35e8 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sat, 17 Oct 2020 17:38:31 +0800 Subject: [PATCH] add settings files --- conf/lab.ini | 104 +++++++ go.mod | 3 +- go.sum | 22 +- pkg/settings/setting.go | 457 ++++++++++++++++++++++++++++++ pkg/settings/setting_container.go | 13 + 5 files changed, 588 insertions(+), 11 deletions(-) create mode 100644 conf/lab.ini create mode 100644 pkg/settings/setting.go create mode 100644 pkg/settings/setting_container.go diff --git a/conf/lab.ini b/conf/lab.ini new file mode 100644 index 00000000..223b40a7 --- /dev/null +++ b/conf/lab.ini @@ -0,0 +1,104 @@ +[global] +# Application instance name +app_name = lab + +# Either "production", "development" +mode = production + +[server] +# Protocol (http, https, socket) +protocol = http + +# The ip address to bind to, "0.0.0.0" will bind to all interfaces +http_addr = 0.0.0.0 + +# The http port to bind to +http_port = 8080 + +# The domain name used to access lab +domain = localhost + +# The full url used to access lab in browser +root_url = %(protocol)s://%(domain)s:%(http_port)s/ + +# https certification and its key file +cert_file = +cert_key_file = + +# Unix socket path, for "socket" only +unix_socket = + +# Static file root path (relative or absolute) +static_root_path = public + +# Enable GZip +enable_gzip = false + +# Set to true to log each request and execution times +log_request = true + +[database] +# Either "mysql", "postgres" or "sqlite3" +type = mysql + +# Database connection configuration, for "mysql" and "postgres" +host = 127.0.0.1:3306 +name = lab +user = root +passwd = + +# For "postgres" only, Either "disable", "require" or "verify-full" +ssl_mode = disable + +# For "sqlite3" only, absolute path of db file +db_path = + +# Max idle connection number, default is 2 +max_idle_conn = 2 + +# Max opened connection number, default is 0 (unlimited) +max_open_conn = 0 + +# Max connection lifetime (seconds), default is 14400 (4 hours) +conn_max_lifetime = 14400 + +# Set to true to log each sql statement and execution times +log_query = false + +[log] +# Either "console", "file", default is "console" +# Use space to separate multiple modes, e.g. "console file" +mode = console + +# Either "debug", "info", "warn", "error", default is "info" +level = info + +# For "file" only, absolute path of log file +log_path = /var/log/labapp/lab.log + +[uuid] +# Uuid generator type, supports "internal" currently +generator_type = internal + +# For "internal" only, each server must have unique id +server_id = 0 + +[security] +# Used for signing, you must change it to keep your user data safe before you first run lab +secret_key = + +# Set to true to enable two factor authorization +enable_two_factor = true + +# Token expired seconds, default is 604800 (7 days) +token_expired_time = 604800 + +# Temporary token expired seconds, default is 300 (5 minutes) +temporary_token_expired_time = 300 + +# Add X-Request-Id header to response to track user request or error, default is true +request_id_header = true + +[user] +# Set to true to allow users to register account by themselves +enable_register = true diff --git a/go.mod b/go.mod index 9f90b67d..bb5ca229 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,8 @@ require ( github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/gin-gonic/gin v1.6.3 github.com/go-playground/validator/v10 v10.2.0 + github.com/smartystreets/goconvey v1.6.4 // indirect github.com/stretchr/testify v1.4.0 - github.com/urfave/cli v1.22.4 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 + gopkg.in/ini.v1 v1.62.0 ) diff --git a/go.sum b/go.sum index cc126c92..c53760e7 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,6 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -22,8 +18,12 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= @@ -34,10 +34,10 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= @@ -46,11 +46,10 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= -github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -59,8 +58,11 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go new file mode 100644 index 00000000..893974ec --- /dev/null +++ b/pkg/settings/setting.go @@ -0,0 +1,457 @@ +package settings + +import ( + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "gopkg.in/ini.v1" + + "github.com/mayswind/lab/pkg/errs" +) + +const ( + LAB_WORK_DIR = "LAB_WORK_DIR" + LAB_ENVIRONMENT_KEY_PREFIX = "LAB" + DEFAULT_CONFIG_PATH = "/conf/lab.ini" + DEFAULT_STATIC_ROOT_PATH = "public" +) + +type SystemMode string + +const ( + MODE_DEVELOPMENT SystemMode = "development" + MODE_PRODUCTION SystemMode = "production" +) + +type Scheme string + +const ( + SCHEME_HTTP Scheme = "http" + SCHEME_HTTPS Scheme = "https" + SCHEME_SOCKET Scheme = "socket" +) + +type Level string + +const ( + LOGLEVEL_DEBUG Level = "debug" + LOGLEVEL_INFO Level = "info" + LOGLEVEL_WARN Level = "warn" + LOGLEVEL_ERROR Level = "error" +) + +const ( + DBTYPE_MYSQL string = "mysql" + DBTYPE_POSTGRES string = "postgres" + DBTYPE_SQLITE3 string = "sqlite3" +) + +const ( + UUID_GENERATOR_TYPE_INTERNAL string = "internal" +) + +const ( + DEFAULT_APP_NAME string = "lab" + + DEFAULT_HTTP_ADDR string = "0.0.0.0" + DEFAULT_HTTP_PORT int = 8080 + DEFAULT_DOMAIN string = "localhost" + + DEFAULT_DATABASE_HOST string = "127.0.0.1:3306" + DEFAULT_DATABASE_NAME string = "lab" + DEFAULT_DATABASE_MAX_IDLE_CONN int = 2 + DEFAULT_DATABASE_MAX_OPEN_CONN int = 0 + DEFAULT_DATABASE_CONN_MAX_LIFETIME int = 14400 + + DEFAULT_LOG_MODE string = "console" + DEFAULT_LOG_LEVEL Level = LOGLEVEL_INFO + + DEFAULT_SECRET_KEY string = "lab" + DEFAULT_TOKEN_EXPIRED_TIME int = 604800 // 7 days + DEFAULT_TEMPORARY_TOKEN_EXPIRED_TIME int = 300 // 5 minutes +) + +type DatabaseConfig struct { + DatabaseType string + DatabaseHost string + DatabaseName string + DatabaseUser string + DatabasePassword string + + DatabaseSSLMode string + + DatabasePath string + + MaxIdleConnection int + MaxOpenConnection int + ConnectionMaxLifeTime int +} + +type Config struct { + // Global + AppName string + Mode SystemMode + WorkingPath string + + // Server + Protocol Scheme + HttpAddr string + HttpPort int + + Domain string + RootUrl string + + CertFile string + CertKeyFile string + + UnixSocketPath string + + StaticRootPath string + + EnableGZip bool + EnableRequestLog bool + + // Database + DatabaseConfig *DatabaseConfig + EnableQueryLog bool + + // Log + LogModes []string + EnableConsoleLog bool + EnableFileLog bool + + LogLevel Level + FileLogPath string + + // Uuid + UuidGeneratorType string + UuidServerId uint8 + + // Secret + SecretKey string + EnableTwoFactor bool + TokenExpiredTime int + TokenExpiredTimeDuration time.Duration + TemporaryTokenExpiredTime int + TemporaryTokenExpiredTimeDuration time.Duration + EnableRequestIdHeader bool + + // User + EnableUserRegister bool +} + +func LoadConfiguration(configFilePath string) (*Config, error) { + var err error + + cfgFile, err := ini.LoadSources(ini.LoadOptions{}, configFilePath) + + if err != nil { + return nil, err + } + + config := &Config{} + config.WorkingPath, err = getWorkingPath() + + if err != nil { + return nil, err + } + + err = loadGlobalConfiguration(config, cfgFile, "global") + + if err != nil { + return nil, err + } + + err = loadServerConfiguration(config, cfgFile, "server") + + if err != nil { + return nil, err + } + + err = loadDatabaseConfiguration(config, cfgFile, "database") + + if err != nil { + return nil, err + } + + err = loadLogConfiguration(config, cfgFile, "log") + + if err != nil { + return nil, err + } + + err = loadUuidConfiguration(config, cfgFile, "uuid") + + if err != nil { + return nil, err + } + + err = loadSecurityConfiguration(config, cfgFile, "security") + + if err != nil { + return nil, err + } + + err = loadUserConfiguration(config, cfgFile, "user") + + if err != nil { + return nil, err + } + + return config, nil +} + +func GetDefaultConfigFilePath() (string, error) { + workingPath, err := getWorkingPath() + + if err != nil { + return "", err + } + + cfgFilePath := filepath.Join(workingPath, DEFAULT_CONFIG_PATH) + _, err = os.Stat(cfgFilePath) + + if err != nil { + return "", err + } + + return cfgFilePath, nil +} + +func loadGlobalConfiguration(config *Config, configFile *ini.File, sectionName string) error { + config.AppName = getConfigItemStringValue(configFile, sectionName, "app_name", DEFAULT_APP_NAME) + config.Mode = MODE_PRODUCTION + + if getConfigItemStringValue(configFile, sectionName, "mode") == "development" { + config.Mode = MODE_DEVELOPMENT + } + + return nil +} + +func loadServerConfiguration(config *Config, configFile *ini.File, sectionName string) error { + if getConfigItemStringValue(configFile, sectionName, "protocol") == "http" { + config.Protocol = SCHEME_HTTP + + config.HttpAddr = getConfigItemStringValue(configFile, sectionName, "http_addr", DEFAULT_HTTP_ADDR) + config.HttpPort = getConfigItemIntValue(configFile, sectionName, "http_port", DEFAULT_HTTP_PORT) + } else if getConfigItemStringValue(configFile, sectionName, "protocol") == "https" { + config.Protocol = SCHEME_HTTPS + + config.HttpAddr = getConfigItemStringValue(configFile, sectionName, "http_addr", DEFAULT_HTTP_ADDR) + config.HttpPort = getConfigItemIntValue(configFile, sectionName, "http_port", DEFAULT_HTTP_PORT) + + config.CertFile = getConfigItemStringValue(configFile, sectionName, "cert_file") + config.CertKeyFile = getConfigItemStringValue(configFile, sectionName, "cert_key_file") + } else if getConfigItemStringValue(configFile, sectionName, "protocol") == "socket" { + config.Protocol = SCHEME_SOCKET + + config.UnixSocketPath = getConfigItemStringValue(configFile, sectionName, "unix_socket") + } else { + return errs.ErrInvalidProtocol + } + + config.Domain = getConfigItemStringValue(configFile, sectionName, "domain", DEFAULT_DOMAIN) + config.RootUrl = getConfigItemStringValue(configFile, sectionName, "root_url", fmt.Sprintf("%s://%s:%d/", string(config.Protocol), config.Domain, config.HttpPort)) + + if config.RootUrl[len(config.RootUrl)-1] != '/' { + config.RootUrl += "/" + } + + staticRootPath := getConfigItemStringValue(configFile, sectionName, "static_root_path", DEFAULT_STATIC_ROOT_PATH) + finalStaticRootPath, err := getFinalPath(config.WorkingPath, staticRootPath) + + if err != nil { + return err + } + + config.StaticRootPath = finalStaticRootPath + + config.EnableGZip = getConfigItemBoolValue(configFile, sectionName, "enable_gzip", false) + config.EnableRequestLog = getConfigItemBoolValue(configFile, sectionName, "log_request", false) + + return nil +} + +func loadDatabaseConfiguration(config *Config, configFile *ini.File, sectionName string) error { + dbConfig := &DatabaseConfig{} + + dbConfig.DatabaseType = getConfigItemStringValue(configFile, sectionName, "type", DBTYPE_MYSQL) + dbConfig.DatabaseHost = getConfigItemStringValue(configFile, sectionName, "host", DEFAULT_DATABASE_HOST) + dbConfig.DatabaseName = getConfigItemStringValue(configFile, sectionName, "name", DEFAULT_DATABASE_NAME) + dbConfig.DatabaseUser = getConfigItemStringValue(configFile, sectionName, "user") + dbConfig.DatabasePassword = getConfigItemStringValue(configFile, sectionName, "passwd") + + if dbConfig.DatabaseType == DBTYPE_POSTGRES { + dbConfig.DatabaseSSLMode = getConfigItemStringValue(configFile, sectionName, "ssl_mode") + } + + if dbConfig.DatabaseType == DBTYPE_SQLITE3 { + dbConfig.DatabasePath = getConfigItemStringValue(configFile, sectionName, "db_path") + } + + dbConfig.MaxIdleConnection = getConfigItemIntValue(configFile, sectionName, "max_idle_conn", DEFAULT_DATABASE_MAX_IDLE_CONN) + dbConfig.MaxOpenConnection = getConfigItemIntValue(configFile, sectionName, "max_open_conn", DEFAULT_DATABASE_MAX_OPEN_CONN) + dbConfig.ConnectionMaxLifeTime = getConfigItemIntValue(configFile, sectionName, "conn_max_lifetime", DEFAULT_DATABASE_CONN_MAX_LIFETIME) + + config.DatabaseConfig = dbConfig + config.EnableQueryLog = getConfigItemBoolValue(configFile, sectionName, "log_query", false) + + return nil +} + +func loadLogConfiguration(config *Config, configFile *ini.File, sectionName string) error { + config.LogModes = strings.Split(getConfigItemStringValue(configFile, sectionName, "mode", DEFAULT_LOG_MODE), " ") + + for i := 0; i < len(config.LogModes); i++ { + logMode := config.LogModes[i] + + if logMode == "console" { + config.EnableConsoleLog = true + } else if logMode == "file" { + config.EnableFileLog = true + } else { + return errs.ErrInvalidLogMode + } + } + + config.LogLevel = getLogLevel(getConfigItemStringValue(configFile, sectionName, "level"), DEFAULT_LOG_LEVEL) + + if config.EnableFileLog { + config.FileLogPath = getConfigItemStringValue(configFile, sectionName, "log_path") + } + + return nil +} + +func loadUuidConfiguration(config *Config, configFile *ini.File, sectionName string) error { + if getConfigItemStringValue(configFile, sectionName, "generator_type") == UUID_GENERATOR_TYPE_INTERNAL { + config.UuidGeneratorType = UUID_GENERATOR_TYPE_INTERNAL + } else { + return errs.ErrInvalidUuidMode + } + + config.UuidServerId = uint8(getConfigItemIntValue(configFile, sectionName, "server_id", 0)) + + return nil +} + +func loadSecurityConfiguration(config *Config, configFile *ini.File, sectionName string) error { + config.SecretKey = getConfigItemStringValue(configFile, sectionName, "secret_key", DEFAULT_SECRET_KEY) + config.EnableTwoFactor = getConfigItemBoolValue(configFile, sectionName, "enable_two_factor", true) + + config.TokenExpiredTime = getConfigItemIntValue(configFile, sectionName, "token_expired_time", DEFAULT_TOKEN_EXPIRED_TIME) + config.TokenExpiredTimeDuration = time.Duration(config.TokenExpiredTime) * time.Second + + config.TemporaryTokenExpiredTime = getConfigItemIntValue(configFile, sectionName, "temporary_token_expired_time", DEFAULT_TEMPORARY_TOKEN_EXPIRED_TIME) + config.TemporaryTokenExpiredTimeDuration = time.Duration(config.TemporaryTokenExpiredTime) * time.Second + + config.EnableRequestIdHeader = getConfigItemBoolValue(configFile, sectionName, "request_id_header", true) + + return nil +} + +func loadUserConfiguration(config *Config, configFile *ini.File, sectionName string) error { + config.EnableUserRegister = getConfigItemBoolValue(configFile, sectionName, "enable_register", false) + + return nil +} + +func getWorkingPath() (string, error) { + workingPath := os.Getenv(LAB_WORK_DIR) + + if workingPath != "" { + return workingPath, nil + } + + execFilePath, err := os.Getwd() + + if err != nil { + return "", err + } + + return execFilePath, nil +} + +func getFinalPath(workingPath, p string) (string, error) { + var err error + + if !filepath.IsAbs(p) { + p = filepath.Join(workingPath, p) + } + + if _, err = os.Stat(p); err == nil { + return p, nil + } + + return "", err +} + +func getConfigItemStringValue(configFile *ini.File, sectionName string, itemName string, defaultValue ...string) string { + environmentKey := getEnvironmentKey(sectionName, itemName) + environmentValue := os.Getenv(environmentKey) + + if len(environmentValue) > 0 { + return environmentValue + } + + section := configFile.Section(sectionName) + + if len(defaultValue) > 0 { + return section.Key(itemName).MustString(defaultValue[0]) + } else { + return section.Key(itemName).String() + } +} + +func getConfigItemIntValue(configFile *ini.File, sectionName string, itemName string, defaultValue ...int) int { + environmentKey := getEnvironmentKey(sectionName, itemName) + environmentValue := os.Getenv(environmentKey) + + if len(environmentValue) > 0 { + value, err := strconv.ParseInt(environmentValue, 0, 64) + + if err == nil { + return int(value) + } + } + + section := configFile.Section(sectionName) + return section.Key(itemName).MustInt(defaultValue...) +} + +func getConfigItemBoolValue(configFile *ini.File, sectionName string, itemName string, defaultValue ...bool) bool { + environmentKey := getEnvironmentKey(sectionName, itemName) + environmentValue := os.Getenv(environmentKey) + + if len(environmentValue) > 0 { + value, err := strconv.ParseBool(environmentValue) + + if err == nil { + return value + } + } + + section := configFile.Section(sectionName) + return section.Key(itemName).MustBool(defaultValue...) +} + +func getEnvironmentKey(sectionName string, itemName string) string { + return fmt.Sprintf("%s_%s_%s", LAB_ENVIRONMENT_KEY_PREFIX, strings.ToUpper(sectionName), strings.ToUpper(itemName)) +} + +func getLogLevel(logLevelStr string, defaultLogLevel Level) Level { + if logLevelStr == "debug" { + return LOGLEVEL_DEBUG + } else if logLevelStr == "warn" { + return LOGLEVEL_WARN + } else if logLevelStr == "error" { + return LOGLEVEL_ERROR + } + + return defaultLogLevel +} diff --git a/pkg/settings/setting_container.go b/pkg/settings/setting_container.go new file mode 100644 index 00000000..e6004284 --- /dev/null +++ b/pkg/settings/setting_container.go @@ -0,0 +1,13 @@ +package settings + +type ConfigContainer struct { + Current *Config +} + +var ( + Container = &ConfigContainer{} +) + +func SetCurrentConfig(config *Config) { + Container.Current = config +}