Files
x/config/loader/loader.go
T
ginuerzh 7723119d80 fix(loader): set logger level before registering services so -D/-DD take effect
Service registration (register) calls ParseService, which captures
logger.Default() into each service/handler/listener. Since
logger.SetDefault was called after register, all components captured
the initial Info-level logger, making -D/-DD ineffective for service
logging.
2026-05-29 00:26:00 +08:00

322 lines
9.2 KiB
Go

// Package loader converts a parsed [config.Config] into running components
// by parsing each config section and registering the results into the
// global registries. Components are registered in dependency order so that
// when a component reads its dependencies from registries during parsing,
// those dependencies are already available.
package loader
import (
"github.com/go-gost/core/admission"
"github.com/go-gost/core/auth"
"github.com/go-gost/core/bypass"
"github.com/go-gost/core/chain"
"github.com/go-gost/core/hop"
"github.com/go-gost/core/hosts"
"github.com/go-gost/core/ingress"
"github.com/go-gost/core/limiter/conn"
"github.com/go-gost/core/limiter/rate"
"github.com/go-gost/core/limiter/traffic"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/observer"
"github.com/go-gost/core/recorder"
reg "github.com/go-gost/core/registry"
"github.com/go-gost/core/resolver"
"github.com/go-gost/core/router"
"github.com/go-gost/core/sd"
"github.com/go-gost/core/service"
"github.com/go-gost/x/config"
"github.com/go-gost/x/config/parsing"
admission_parser "github.com/go-gost/x/config/parsing/admission"
auth_parser "github.com/go-gost/x/config/parsing/auth"
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
chain_parser "github.com/go-gost/x/config/parsing/chain"
hop_parser "github.com/go-gost/x/config/parsing/hop"
hosts_parser "github.com/go-gost/x/config/parsing/hosts"
ingress_parser "github.com/go-gost/x/config/parsing/ingress"
limiter_parser "github.com/go-gost/x/config/parsing/limiter"
logger_parser "github.com/go-gost/x/config/parsing/logger"
observer_parser "github.com/go-gost/x/config/parsing/observer"
recorder_parser "github.com/go-gost/x/config/parsing/recorder"
resolver_parser "github.com/go-gost/x/config/parsing/resolver"
router_parser "github.com/go-gost/x/config/parsing/router"
sd_parser "github.com/go-gost/x/config/parsing/sd"
service_parser "github.com/go-gost/x/config/parsing/service"
"github.com/go-gost/x/registry"
)
// defaultLoader is a singleton loader used by the top-level Load function.
var (
defaultLoader *loader = &loader{}
)
// Load parses all config sections from cfg and registers the resulting
// components into the global registries, then sets up the default logger
// and TLS config.
func Load(cfg *config.Config) error {
return defaultLoader.Load(cfg)
}
// loader holds no state; its Load method is the entry point for converting
// a config into running components.
type loader struct{}
// Load builds the default TLS config, registers all named components from
// cfg into the global registries, and sets the default logger and TLS config.
func (l *loader) Load(cfg *config.Config) error {
if cfg == nil {
return nil
}
tlsCfg, err := parsing.BuildDefaultTLSConfig(cfg.TLS)
if err != nil {
return err
}
logCfg := cfg.Log
if logCfg == nil {
logCfg = &config.LogConfig{}
}
logger.SetDefault(logger_parser.ParseLogger(&config.LoggerConfig{Log: logCfg}))
if err := register(cfg); err != nil {
return err
}
parsing.SetDefaultTLSConfig(tlsCfg)
return nil
}
// named is a generic name+value pair used to buffer parsed components
// before registering them.
type named[T any] struct {
name string
v T
}
// registerGroup replaces all entries in r with the given entries.
// Old entries are unregistered first; if any new entry fails to register,
// the group is left partially updated (matching the historical reload
// behavior for intra-group failures).
func registerGroup[T any](entries []named[T], r reg.Registry[T]) error {
for name := range r.GetAll() {
r.Unregister(name)
}
for _, e := range entries {
if err := r.Register(e.name, e.v); err != nil {
return err
}
}
return nil
}
// register parses config sections and registers them into the global
// registries. Groups are processed in dependency order: leaf components
// first, then hops, chains, and finally services. This ensures that
// when a component reads its dependencies from registries during
// parsing, those dependencies are already registered.
func register(cfg *config.Config) error {
if cfg == nil {
return nil
}
// --- leaf components (no inter-group registry dependencies) ---
{
var entries []named[logger.Logger]
for _, c := range cfg.Loggers {
entries = append(entries, named[logger.Logger]{c.Name, logger_parser.ParseLogger(c)})
}
if err := registerGroup(entries, registry.LoggerRegistry()); err != nil {
return err
}
}
{
var entries []named[auth.Authenticator]
for _, c := range cfg.Authers {
entries = append(entries, named[auth.Authenticator]{c.Name, auth_parser.ParseAuther(c)})
}
if err := registerGroup(entries, registry.AutherRegistry()); err != nil {
return err
}
}
{
var entries []named[admission.Admission]
for _, c := range cfg.Admissions {
entries = append(entries, named[admission.Admission]{c.Name, admission_parser.ParseAdmission(c)})
}
if err := registerGroup(entries, registry.AdmissionRegistry()); err != nil {
return err
}
}
{
var entries []named[bypass.Bypass]
for _, c := range cfg.Bypasses {
entries = append(entries, named[bypass.Bypass]{c.Name, bypass_parser.ParseBypass(c)})
}
if err := registerGroup(entries, registry.BypassRegistry()); err != nil {
return err
}
}
{
var entries []named[resolver.Resolver]
for _, c := range cfg.Resolvers {
r, err := resolver_parser.ParseResolver(c)
if err != nil {
return err
}
entries = append(entries, named[resolver.Resolver]{c.Name, r})
}
if err := registerGroup(entries, registry.ResolverRegistry()); err != nil {
return err
}
}
{
var entries []named[hosts.HostMapper]
for _, c := range cfg.Hosts {
entries = append(entries, named[hosts.HostMapper]{c.Name, hosts_parser.ParseHostMapper(c)})
}
if err := registerGroup(entries, registry.HostsRegistry()); err != nil {
return err
}
}
{
var entries []named[ingress.Ingress]
for _, c := range cfg.Ingresses {
entries = append(entries, named[ingress.Ingress]{c.Name, ingress_parser.ParseIngress(c)})
}
if err := registerGroup(entries, registry.IngressRegistry()); err != nil {
return err
}
}
{
var entries []named[router.Router]
for _, c := range cfg.Routers {
entries = append(entries, named[router.Router]{c.Name, router_parser.ParseRouter(c)})
}
if err := registerGroup(entries, registry.RouterRegistry()); err != nil {
return err
}
}
{
var entries []named[sd.SD]
for _, c := range cfg.SDs {
entries = append(entries, named[sd.SD]{c.Name, sd_parser.ParseSD(c)})
}
if err := registerGroup(entries, registry.SDRegistry()); err != nil {
return err
}
}
{
var entries []named[observer.Observer]
for _, c := range cfg.Observers {
entries = append(entries, named[observer.Observer]{c.Name, observer_parser.ParseObserver(c)})
}
if err := registerGroup(entries, registry.ObserverRegistry()); err != nil {
return err
}
}
{
var entries []named[recorder.Recorder]
for _, c := range cfg.Recorders {
entries = append(entries, named[recorder.Recorder]{c.Name, recorder_parser.ParseRecorder(c)})
}
if err := registerGroup(entries, registry.RecorderRegistry()); err != nil {
return err
}
}
{
var entries []named[traffic.TrafficLimiter]
for _, c := range cfg.Limiters {
entries = append(entries, named[traffic.TrafficLimiter]{c.Name, limiter_parser.ParseTrafficLimiter(c)})
}
if err := registerGroup(entries, registry.TrafficLimiterRegistry()); err != nil {
return err
}
}
{
var entries []named[conn.ConnLimiter]
for _, c := range cfg.CLimiters {
entries = append(entries, named[conn.ConnLimiter]{c.Name, limiter_parser.ParseConnLimiter(c)})
}
if err := registerGroup(entries, registry.ConnLimiterRegistry()); err != nil {
return err
}
}
{
var entries []named[rate.RateLimiter]
for _, c := range cfg.RLimiters {
entries = append(entries, named[rate.RateLimiter]{c.Name, limiter_parser.ParseRateLimiter(c)})
}
if err := registerGroup(entries, registry.RateLimiterRegistry()); err != nil {
return err
}
}
// --- hops (references bypasses, resolvers, hosts from registries) ---
{
var entries []named[hop.Hop]
for _, c := range cfg.Hops {
h, err := hop_parser.ParseHop(c, logger.Default())
if err != nil {
return err
}
entries = append(entries, named[hop.Hop]{c.Name, h})
}
if err := registerGroup(entries, registry.HopRegistry()); err != nil {
return err
}
}
// --- chains (references hops from registries) ---
{
var entries []named[chain.Chainer]
for _, c := range cfg.Chains {
ch, err := chain_parser.ParseChain(c, logger.Default())
if err != nil {
return err
}
entries = append(entries, named[chain.Chainer]{c.Name, ch})
}
if err := registerGroup(entries, registry.ChainRegistry()); err != nil {
return err
}
}
// --- services (references chains, resolvers, hosts, recorders,
// limiters, observers, hops from registries) ---
{
var entries []named[service.Service]
for _, c := range cfg.Services {
svc, err := service_parser.ParseService(c)
if err != nil {
return err
}
if svc != nil {
entries = append(entries, named[service.Service]{c.Name, svc})
}
}
if err := registerGroup(entries, registry.ServiceRegistry()); err != nil {
return err
}
}
return nil
}