153 lines
3.8 KiB
Go
153 lines
3.8 KiB
Go
|
|
package config
|
||
|
|
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
"strconv"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"gopkg.in/yaml.v3"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Config holds the agent configuration
|
||
|
|
type Config struct {
|
||
|
|
MasterURL string `yaml:"master_url"`
|
||
|
|
Token string `yaml:"token"`
|
||
|
|
ConnectionMode string `yaml:"connection_mode"`
|
||
|
|
ListenPort string `yaml:"listen_port"`
|
||
|
|
XrayServers []XrayServer `yaml:"xray_servers"`
|
||
|
|
TrafficReportInterval time.Duration `yaml:"traffic_report_interval"`
|
||
|
|
SpeedReportInterval time.Duration `yaml:"speed_report_interval"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// XrayServer represents a local Xray server configuration
|
||
|
|
type XrayServer struct {
|
||
|
|
Name string `yaml:"name"`
|
||
|
|
ConfigPath string `yaml:"config_path"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// DefaultXrayConfigPaths are the default paths to search for Xray config
|
||
|
|
var DefaultXrayConfigPaths = []string{
|
||
|
|
"/usr/local/etc/xray/config.json",
|
||
|
|
"/etc/xray/config.json",
|
||
|
|
"/opt/xray/config.json",
|
||
|
|
}
|
||
|
|
|
||
|
|
// Load loads configuration from a YAML file
|
||
|
|
func Load(path string) (*Config, error) {
|
||
|
|
data, err := os.ReadFile(path)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
var config Config
|
||
|
|
if err := yaml.Unmarshal(data, &config); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
// Apply defaults
|
||
|
|
config.applyDefaults()
|
||
|
|
|
||
|
|
return &config, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// FromEnv creates configuration from environment variables
|
||
|
|
func FromEnv() *Config {
|
||
|
|
config := &Config{
|
||
|
|
MasterURL: os.Getenv("MMWX_MASTER_URL"),
|
||
|
|
Token: os.Getenv("MMWX_TOKEN"),
|
||
|
|
ConnectionMode: os.Getenv("MMWX_CONNECTION_MODE"),
|
||
|
|
ListenPort: os.Getenv("MMWX_LISTEN_PORT"),
|
||
|
|
}
|
||
|
|
|
||
|
|
// Parse Xray config path from env
|
||
|
|
if xrayConfig := os.Getenv("MMWX_XRAY_CONFIG"); xrayConfig != "" {
|
||
|
|
config.XrayServers = []XrayServer{
|
||
|
|
{Name: "primary", ConfigPath: xrayConfig},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Parse intervals
|
||
|
|
if interval := os.Getenv("MMWX_TRAFFIC_INTERVAL"); interval != "" {
|
||
|
|
if d, err := time.ParseDuration(interval); err == nil {
|
||
|
|
config.TrafficReportInterval = d
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if interval := os.Getenv("MMWX_SPEED_INTERVAL"); interval != "" {
|
||
|
|
if d, err := time.ParseDuration(interval); err == nil {
|
||
|
|
config.SpeedReportInterval = d
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
config.applyDefaults()
|
||
|
|
return config
|
||
|
|
}
|
||
|
|
|
||
|
|
// Merge merges environment config into file config (env takes precedence)
|
||
|
|
func (c *Config) Merge(env *Config) {
|
||
|
|
if env.MasterURL != "" {
|
||
|
|
c.MasterURL = env.MasterURL
|
||
|
|
}
|
||
|
|
if env.Token != "" {
|
||
|
|
c.Token = env.Token
|
||
|
|
}
|
||
|
|
if env.ConnectionMode != "" {
|
||
|
|
c.ConnectionMode = env.ConnectionMode
|
||
|
|
}
|
||
|
|
if env.ListenPort != "" {
|
||
|
|
c.ListenPort = env.ListenPort
|
||
|
|
}
|
||
|
|
if len(env.XrayServers) > 0 {
|
||
|
|
c.XrayServers = env.XrayServers
|
||
|
|
}
|
||
|
|
if env.TrafficReportInterval > 0 {
|
||
|
|
c.TrafficReportInterval = env.TrafficReportInterval
|
||
|
|
}
|
||
|
|
if env.SpeedReportInterval > 0 {
|
||
|
|
c.SpeedReportInterval = env.SpeedReportInterval
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// applyDefaults sets default values for unset fields
|
||
|
|
func (c *Config) applyDefaults() {
|
||
|
|
if c.ConnectionMode == "" {
|
||
|
|
c.ConnectionMode = "auto"
|
||
|
|
}
|
||
|
|
if c.ListenPort == "" {
|
||
|
|
c.ListenPort = "8081"
|
||
|
|
}
|
||
|
|
if c.TrafficReportInterval == 0 {
|
||
|
|
c.TrafficReportInterval = 1 * time.Minute
|
||
|
|
}
|
||
|
|
if c.SpeedReportInterval == 0 {
|
||
|
|
c.SpeedReportInterval = 3 * time.Second
|
||
|
|
}
|
||
|
|
|
||
|
|
// Auto-discover Xray servers if not configured
|
||
|
|
if len(c.XrayServers) == 0 {
|
||
|
|
c.XrayServers = c.discoverXrayServers()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// discoverXrayServers scans default paths for Xray config files
|
||
|
|
func (c *Config) discoverXrayServers() []XrayServer {
|
||
|
|
var servers []XrayServer
|
||
|
|
for i, path := range DefaultXrayConfigPaths {
|
||
|
|
if _, err := os.Stat(path); err == nil {
|
||
|
|
servers = append(servers, XrayServer{
|
||
|
|
Name: "xray-" + strconv.Itoa(i+1),
|
||
|
|
ConfigPath: path,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return servers
|
||
|
|
}
|
||
|
|
|
||
|
|
// Validate checks if the configuration is valid
|
||
|
|
func (c *Config) Validate() error {
|
||
|
|
// Token is required for non-pull modes
|
||
|
|
if c.ConnectionMode != "pull" && c.Token == "" {
|
||
|
|
// Allow empty token, will work in pull mode only
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|