aqi/app.go
2024-06-18 18:09:39 +08:00

210 lines
4.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package aqi
import (
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/fatih/color"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"github.com/wonli/aqi/config"
"github.com/wonli/aqi/logger"
"github.com/wonli/aqi/validate"
)
type AppConfig struct {
//运行时数据存储基础路径
DataPath string
//应用日志文件配置路径
LogPathKey string
//默认语言
Language string
//开发模式
devMode bool
//服务名称support.Version
//当指定 HttpServerPortFindPath 时在配置读取之后从配置路径获取http端口
Servername []string
ServerPort string
HttpServerPortFindPath string
ConfigType string //配置文件类型
ConfigPath string //配置文件路径
ConfigName string //配置文件名称
Configs map[string]any
HttpServer http.Handler //http server
RemoteProvider *RemoteProvider //远程配置支持etcd, consul
WatchHandler func()
}
var acf *AppConfig
func Init(options ...Option) *AppConfig {
acf = &AppConfig{
Language: "zh",
ConfigType: "yaml",
ConfigName: "config",
ServerPort: "1091",
LogPathKey: "log",
DataPath: "data",
}
for _, opt := range options {
if opt != nil {
err := opt(acf)
if err != nil {
color.Red("error %s", err.Error())
os.Exit(1)
}
}
}
if acf.ConfigPath == "" {
workerDir, err := os.Getwd()
if err != nil {
color.Red("Failed to get the configuration file directory: %s", err.Error())
os.Exit(1)
}
acf.ConfigPath = workerDir
}
if CommitVersion == "" {
acf.devMode = true
acf.ConfigName = fmt.Sprintf("%s-dev", acf.ConfigName)
}
// 设置环境变量的前缀
// 自动将环境变量绑定到 Viper 配置中
viper.SetEnvPrefix("")
viper.AutomaticEnv()
//设置配置文件
viper.SetConfigName(acf.ConfigName)
viper.SetConfigType(acf.ConfigType)
viper.AddConfigPath(acf.ConfigPath)
err := viper.ReadInConfig()
if err != nil {
if acf.RemoteProvider == nil {
err = acf.WriteDefaultConfig()
if err != nil {
color.Red("Error gen default config file: %s", err.Error())
os.Exit(1)
}
color.Red("failed to read config file: %s", err.Error())
os.Exit(1)
}
color.Red("Remote configuration will be used: %s", err.Error())
} else {
acf.Configs = viper.AllSettings()
}
if acf.LogPathKey == "" {
color.Red("Please specify LogPathKey")
os.Exit(1)
}
isSetDevMode := viper.IsSet("devMode")
if isSetDevMode {
setDevModel := viper.GetBool("devMode")
acf.devMode = setDevModel
}
viper.Set("devMode", acf.devMode)
if acf.RemoteProvider != nil {
_ = viper.AddRemoteProvider(string(acf.RemoteProvider.Name), acf.RemoteProvider.Endpoint, acf.RemoteProvider.Path)
viper.SetConfigType(acf.RemoteProvider.Type)
err := viper.ReadRemoteConfig()
if err != nil {
color.Red("Failed to read remote config")
os.Exit(1)
}
go func() {
t := time.NewTicker(time.Minute * 30)
for range t.C {
err2 := viper.WatchRemoteConfig()
if err2 != nil {
logger.SugarLog.Errorf("unable to read remote config: %v", err2)
continue
}
if acf.WatchHandler != nil {
acf.WatchHandler()
}
}
}()
}
//处理http服务端口信息
if acf.HttpServerPortFindPath != "" {
port := viper.GetString(acf.HttpServerPortFindPath)
if port == "" {
port = acf.ServerPort
}
if strings.Contains(port, ":") {
s := strings.Split(port, ":")
port = s[len(s)-1]
}
acf.ServerPort = port
acf.Servername = append(acf.Servername, "is now running at http://0.0.0.0:"+port)
}
//打印系统信息
if acf.Servername != nil {
AsciiLogo(acf.Servername...)
}
if CommitVersion == "" {
color.Green("dev mode -- use config %s", acf.ConfigName+"."+acf.ConfigType)
}
var c config.Logger
err = viper.UnmarshalKey(acf.LogPathKey, &c)
if err != nil {
color.Red("failed to init app log")
os.Exit(1)
}
if !filepath.IsAbs(c.LogPath) {
c.LogPath = acf.GetDataPath(c.LogPath)
}
//初始化日志库
logger.Init(c)
//validate语言配置
validate.InitTranslator(acf.Language)
//配置文件更新回调
viper.OnConfigChange(func(e fsnotify.Event) {
logger.SugarLog.Infof("config file changed: %s", e.Name)
if acf.WatchHandler != nil {
acf.WatchHandler()
}
})
//监听配置
viper.WatchConfig()
return acf
}