172 lines
3.9 KiB
Go
172 lines
3.9 KiB
Go
package configs
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/iwind/TeaGo/Tea"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
const ConfigFileName = "api_httpdns.yaml"
|
|
const oldConfigFileName = "api.yaml"
|
|
|
|
var sharedAPIConfig *APIConfig
|
|
|
|
type APIConfig struct {
|
|
OldRPC struct {
|
|
Endpoints []string `yaml:"endpoints"`
|
|
DisableUpdate bool `yaml:"disableUpdate"`
|
|
} `yaml:"rpc,omitempty"`
|
|
|
|
RPCEndpoints []string `yaml:"rpc.endpoints,flow" json:"rpc.endpoints"`
|
|
RPCDisableUpdate bool `yaml:"rpc.disableUpdate" json:"rpc.disableUpdate"`
|
|
|
|
NodeId string `yaml:"nodeId"`
|
|
Secret string `yaml:"secret"`
|
|
|
|
ListenAddr string `yaml:"listenAddr"`
|
|
|
|
HTTPSListenAddr string `yaml:"https.listenAddr" json:"https.listenAddr"`
|
|
HTTPSCert string `yaml:"https.cert" json:"https.cert"`
|
|
HTTPSKey string `yaml:"https.key" json:"https.key"`
|
|
|
|
LogDir string `yaml:"logDir" json:"logDir"`
|
|
}
|
|
|
|
func SharedAPIConfig() (*APIConfig, error) {
|
|
if sharedAPIConfig != nil {
|
|
return sharedAPIConfig, nil
|
|
}
|
|
|
|
config, err := LoadAPIConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sharedAPIConfig = config
|
|
return config, nil
|
|
}
|
|
|
|
func LoadAPIConfig() (*APIConfig, error) {
|
|
for _, filename := range []string{ConfigFileName, oldConfigFileName} {
|
|
var loadedData []byte
|
|
var loadedPath string
|
|
for _, candidate := range findConfigCandidates(filename) {
|
|
data, err := os.ReadFile(candidate)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
continue
|
|
}
|
|
return nil, err
|
|
}
|
|
loadedData = data
|
|
loadedPath = candidate
|
|
break
|
|
}
|
|
|
|
if len(loadedData) == 0 {
|
|
if filename == oldConfigFileName {
|
|
continue
|
|
}
|
|
return nil, errors.New("no config file '" + ConfigFileName + "' found")
|
|
}
|
|
|
|
config := &APIConfig{}
|
|
err := yaml.Unmarshal(loadedData, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = config.Init()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if filename == oldConfigFileName {
|
|
config.OldRPC.Endpoints = nil
|
|
// 优先写回当前旧配置所在目录,避免依赖启动时工作目录
|
|
_ = config.WriteFile(filepath.Join(filepath.Dir(loadedPath), ConfigFileName))
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
return nil, errors.New("no config file '" + ConfigFileName + "' found")
|
|
}
|
|
|
|
func (c *APIConfig) Init() error {
|
|
if len(c.RPCEndpoints) == 0 && len(c.OldRPC.Endpoints) > 0 {
|
|
c.RPCEndpoints = c.OldRPC.Endpoints
|
|
c.RPCDisableUpdate = c.OldRPC.DisableUpdate
|
|
}
|
|
|
|
if len(c.RPCEndpoints) == 0 {
|
|
return errors.New("no valid 'rpc.endpoints'")
|
|
}
|
|
|
|
if len(c.NodeId) == 0 {
|
|
return errors.New("'nodeId' required")
|
|
}
|
|
if len(c.Secret) == 0 {
|
|
return errors.New("'secret' required")
|
|
}
|
|
|
|
// 兼容旧配置中的 listenAddr
|
|
if len(c.HTTPSListenAddr) == 0 {
|
|
if len(c.ListenAddr) > 0 {
|
|
c.HTTPSListenAddr = c.ListenAddr
|
|
} else {
|
|
c.HTTPSListenAddr = ":8443"
|
|
}
|
|
}
|
|
|
|
if len(c.HTTPSCert) == 0 {
|
|
// return errors.New("'https.cert' required")
|
|
}
|
|
if len(c.HTTPSKey) == 0 {
|
|
// return errors.New("'https.key' required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *APIConfig) WriteFile(path string) error {
|
|
data, err := yaml.Marshal(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(path, data, 0666)
|
|
}
|
|
|
|
func findConfigCandidates(filename string) []string {
|
|
candidates := []string{
|
|
Tea.ConfigFile(filename),
|
|
Tea.ConfigFile(filepath.Join("configs", filename)),
|
|
filename,
|
|
filepath.Join("configs", filename),
|
|
}
|
|
|
|
if exePath, err := os.Executable(); err == nil {
|
|
exeDir := filepath.Dir(exePath)
|
|
candidates = append(candidates,
|
|
filepath.Join(exeDir, filename),
|
|
filepath.Join(exeDir, "configs", filename),
|
|
filepath.Join(exeDir, "..", "configs", filename),
|
|
)
|
|
}
|
|
|
|
uniq := map[string]struct{}{}
|
|
result := make([]string, 0, len(candidates))
|
|
for _, candidate := range candidates {
|
|
candidate = filepath.Clean(candidate)
|
|
if len(candidate) == 0 {
|
|
continue
|
|
}
|
|
if _, ok := uniq[candidate]; ok {
|
|
continue
|
|
}
|
|
uniq[candidate] = struct{}{}
|
|
result = append(result, candidate)
|
|
}
|
|
return result
|
|
}
|