fix(registry): log Unregister Close errors, add doc comments and 59 unit tests

Log close errors in Unregister instead of silently discarding them.
Add doc comments to all exported symbols across 20 registry files.
Add comprehensive tests covering base registry, all wrapper types,
hot-reload delegation, nil-fallback semantics, and global accessors.
This commit is contained in:
ginuerzh
2026-05-25 20:23:06 +08:00
parent b1b7500c2f
commit acce86c0e4
21 changed files with 1150 additions and 1 deletions
+5
View File
@@ -6,14 +6,19 @@ import (
"github.com/go-gost/core/admission" "github.com/go-gost/core/admission"
) )
// admissionRegistry implements a hot-reload-safe registry for admission.Admission.
// The Get method returns a wrapper that looks up the current value on every call.
type admissionRegistry struct { type admissionRegistry struct {
registry[admission.Admission] registry[admission.Admission]
} }
// Register stores an Admission under the given name.
func (r *admissionRegistry) Register(name string, v admission.Admission) error { func (r *admissionRegistry) Register(name string, v admission.Admission) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Admission.
// Returns nil if name is empty.
func (r *admissionRegistry) Get(name string) admission.Admission { func (r *admissionRegistry) Get(name string) admission.Admission {
if name != "" { if name != "" {
return &admissionWrapper{name: name, r: r} return &admissionWrapper{name: name, r: r}
+4
View File
@@ -6,14 +6,18 @@ import (
"github.com/go-gost/core/auth" "github.com/go-gost/core/auth"
) )
// autherRegistry implements a hot-reload-safe registry for auth.Authenticator.
type autherRegistry struct { type autherRegistry struct {
registry[auth.Authenticator] registry[auth.Authenticator]
} }
// Register stores an Authenticator under the given name.
func (r *autherRegistry) Register(name string, v auth.Authenticator) error { func (r *autherRegistry) Register(name string, v auth.Authenticator) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Authenticator.
// Returns nil if name is empty.
func (r *autherRegistry) Get(name string) auth.Authenticator { func (r *autherRegistry) Get(name string) auth.Authenticator {
if name != "" { if name != "" {
return &autherWrapper{name: name, r: r} return &autherWrapper{name: name, r: r}
+4
View File
@@ -6,14 +6,18 @@ import (
"github.com/go-gost/core/bypass" "github.com/go-gost/core/bypass"
) )
// bypassRegistry implements a hot-reload-safe registry for bypass.Bypass.
type bypassRegistry struct { type bypassRegistry struct {
registry[bypass.Bypass] registry[bypass.Bypass]
} }
// Register stores a Bypass under the given name.
func (r *bypassRegistry) Register(name string, v bypass.Bypass) error { func (r *bypassRegistry) Register(name string, v bypass.Bypass) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Bypass.
// Returns nil if name is empty.
func (r *bypassRegistry) Get(name string) bypass.Bypass { func (r *bypassRegistry) Get(name string) bypass.Bypass {
if name != "" { if name != "" {
return &bypassWrapper{name: name, r: r} return &bypassWrapper{name: name, r: r}
+4
View File
@@ -8,14 +8,18 @@ import (
"github.com/go-gost/core/selector" "github.com/go-gost/core/selector"
) )
// chainRegistry implements a hot-reload-safe registry for chain.Chainer.
type chainRegistry struct { type chainRegistry struct {
registry[chain.Chainer] registry[chain.Chainer]
} }
// Register stores a Chainer under the given name.
func (r *chainRegistry) Register(name string, v chain.Chainer) error { func (r *chainRegistry) Register(name string, v chain.Chainer) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Chainer.
// Returns nil if name is empty.
func (r *chainRegistry) Get(name string) chain.Chainer { func (r *chainRegistry) Get(name string) chain.Chainer {
if name != "" { if name != "" {
return &chainWrapper{name: name, r: r} return &chainWrapper{name: name, r: r}
+6
View File
@@ -5,12 +5,18 @@ import (
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
// NewConnector is a factory function that creates a new connector.Connector
// from the given options.
type NewConnector func(opts ...connector.Option) connector.Connector type NewConnector func(opts ...connector.Option) connector.Connector
// connectorRegistry stores connector factory functions. Duplicate registrations
// are treated as fatal errors (logger.Default().Fatal).
type connectorRegistry struct { type connectorRegistry struct {
registry[NewConnector] registry[NewConnector]
} }
// Register stores a connector factory under the given name. Calls Fatal on
// duplicate registration since connector names must be unique at init time.
func (r *connectorRegistry) Register(name string, v NewConnector) error { func (r *connectorRegistry) Register(name string, v NewConnector) error {
if err := r.registry.Register(name, v); err != nil { if err := r.registry.Register(name, v); err != nil {
logger.Default().Fatal(err) logger.Default().Fatal(err)
+6
View File
@@ -5,12 +5,18 @@ import (
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
// NewDialer is a factory function that creates a new dialer.Dialer
// from the given options.
type NewDialer func(opts ...dialer.Option) dialer.Dialer type NewDialer func(opts ...dialer.Option) dialer.Dialer
// dialerRegistry stores dialer factory functions. Duplicate registrations
// are treated as fatal errors (logger.Default().Fatal).
type dialerRegistry struct { type dialerRegistry struct {
registry[NewDialer] registry[NewDialer]
} }
// Register stores a dialer factory under the given name. Calls Fatal on
// duplicate registration since dialer names must be unique at init time.
func (r *dialerRegistry) Register(name string, v NewDialer) error { func (r *dialerRegistry) Register(name string, v NewDialer) error {
if err := r.registry.Register(name, v); err != nil { if err := r.registry.Register(name, v); err != nil {
logger.Default().Fatal(err) logger.Default().Fatal(err)
+6
View File
@@ -5,12 +5,18 @@ import (
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
// NewHandler is a factory function that creates a new handler.Handler
// from the given options.
type NewHandler func(opts ...handler.Option) handler.Handler type NewHandler func(opts ...handler.Option) handler.Handler
// handlerRegistry stores handler factory functions. Duplicate registrations
// are treated as fatal errors (logger.Default().Fatal).
type handlerRegistry struct { type handlerRegistry struct {
registry[NewHandler] registry[NewHandler]
} }
// Register stores a handler factory under the given name. Calls Fatal on
// duplicate registration since handler names must be unique at init time.
func (r *handlerRegistry) Register(name string, v NewHandler) error { func (r *handlerRegistry) Register(name string, v NewHandler) error {
if err := r.registry.Register(name, v); err != nil { if err := r.registry.Register(name, v); err != nil {
logger.Default().Fatal(err) logger.Default().Fatal(err)
+4
View File
@@ -7,14 +7,18 @@ import (
"github.com/go-gost/core/hop" "github.com/go-gost/core/hop"
) )
// hopRegistry implements a hot-reload-safe registry for hop.Hop.
type hopRegistry struct { type hopRegistry struct {
registry[hop.Hop] registry[hop.Hop]
} }
// Register stores a Hop under the given name.
func (r *hopRegistry) Register(name string, v hop.Hop) error { func (r *hopRegistry) Register(name string, v hop.Hop) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Hop.
// Returns nil if name is empty.
func (r *hopRegistry) Get(name string) hop.Hop { func (r *hopRegistry) Get(name string) hop.Hop {
if name != "" { if name != "" {
return &hopWrapper{name: name, r: r} return &hopWrapper{name: name, r: r}
+4
View File
@@ -7,14 +7,18 @@ import (
"github.com/go-gost/core/hosts" "github.com/go-gost/core/hosts"
) )
// hostsRegistry implements a hot-reload-safe registry for hosts.HostMapper.
type hostsRegistry struct { type hostsRegistry struct {
registry[hosts.HostMapper] registry[hosts.HostMapper]
} }
// Register stores a HostMapper under the given name.
func (r *hostsRegistry) Register(name string, v hosts.HostMapper) error { func (r *hostsRegistry) Register(name string, v hosts.HostMapper) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered HostMapper.
// Returns nil if name is empty.
func (r *hostsRegistry) Get(name string) hosts.HostMapper { func (r *hostsRegistry) Get(name string) hosts.HostMapper {
if name != "" { if name != "" {
return &hostsWrapper{name: name, r: r} return &hostsWrapper{name: name, r: r}
+4
View File
@@ -6,14 +6,18 @@ import (
"github.com/go-gost/core/ingress" "github.com/go-gost/core/ingress"
) )
// ingressRegistry implements a hot-reload-safe registry for ingress.Ingress.
type ingressRegistry struct { type ingressRegistry struct {
registry[ingress.Ingress] registry[ingress.Ingress]
} }
// Register stores an Ingress under the given name.
func (r *ingressRegistry) Register(name string, v ingress.Ingress) error { func (r *ingressRegistry) Register(name string, v ingress.Ingress) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Ingress.
// Returns nil if name is empty.
func (r *ingressRegistry) Get(name string) ingress.Ingress { func (r *ingressRegistry) Get(name string) ingress.Ingress {
if name != "" { if name != "" {
return &ingressWrapper{name: name, r: r} return &ingressWrapper{name: name, r: r}
+12
View File
@@ -9,14 +9,18 @@ import (
"github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/limiter/traffic"
) )
// trafficLimiterRegistry implements a hot-reload-safe registry for traffic.TrafficLimiter.
type trafficLimiterRegistry struct { type trafficLimiterRegistry struct {
registry[traffic.TrafficLimiter] registry[traffic.TrafficLimiter]
} }
// Register stores a TrafficLimiter under the given name.
func (r *trafficLimiterRegistry) Register(name string, v traffic.TrafficLimiter) error { func (r *trafficLimiterRegistry) Register(name string, v traffic.TrafficLimiter) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered TrafficLimiter.
// Returns nil if name is empty.
func (r *trafficLimiterRegistry) Get(name string) traffic.TrafficLimiter { func (r *trafficLimiterRegistry) Get(name string) traffic.TrafficLimiter {
if name != "" { if name != "" {
return &trafficLimiterWrapper{name: name, r: r} return &trafficLimiterWrapper{name: name, r: r}
@@ -49,14 +53,18 @@ func (w *trafficLimiterWrapper) Out(ctx context.Context, key string, opts ...lim
return v.Out(ctx, key, opts...) return v.Out(ctx, key, opts...)
} }
// connLimiterRegistry implements a hot-reload-safe registry for conn.ConnLimiter.
type connLimiterRegistry struct { type connLimiterRegistry struct {
registry[conn.ConnLimiter] registry[conn.ConnLimiter]
} }
// Register stores a ConnLimiter under the given name.
func (r *connLimiterRegistry) Register(name string, v conn.ConnLimiter) error { func (r *connLimiterRegistry) Register(name string, v conn.ConnLimiter) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered ConnLimiter.
// Returns nil if name is empty.
func (r *connLimiterRegistry) Get(name string) conn.ConnLimiter { func (r *connLimiterRegistry) Get(name string) conn.ConnLimiter {
if name != "" { if name != "" {
return &connLimiterWrapper{name: name, r: r} return &connLimiterWrapper{name: name, r: r}
@@ -81,14 +89,18 @@ func (w *connLimiterWrapper) Limiter(key string) conn.Limiter {
return v.Limiter(key) return v.Limiter(key)
} }
// rateLimiterRegistry implements a hot-reload-safe registry for rate.RateLimiter.
type rateLimiterRegistry struct { type rateLimiterRegistry struct {
registry[rate.RateLimiter] registry[rate.RateLimiter]
} }
// Register stores a RateLimiter under the given name.
func (r *rateLimiterRegistry) Register(name string, v rate.RateLimiter) error { func (r *rateLimiterRegistry) Register(name string, v rate.RateLimiter) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered RateLimiter.
// Returns nil if name is empty.
func (r *rateLimiterRegistry) Get(name string) rate.RateLimiter { func (r *rateLimiterRegistry) Get(name string) rate.RateLimiter {
if name != "" { if name != "" {
return &rateLimiterWrapper{name: name, r: r} return &rateLimiterWrapper{name: name, r: r}
+6
View File
@@ -5,12 +5,18 @@ import (
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
// NewListener is a factory function that creates a new listener.Listener
// from the given options.
type NewListener func(opts ...listener.Option) listener.Listener type NewListener func(opts ...listener.Option) listener.Listener
// listenerRegistry stores listener factory functions. Duplicate registrations
// are treated as fatal errors (logger.Default().Fatal).
type listenerRegistry struct { type listenerRegistry struct {
registry[NewListener] registry[NewListener]
} }
// Register stores a listener factory under the given name. Calls Fatal on
// duplicate registration since listener names must be unique at init time.
func (r *listenerRegistry) Register(name string, v NewListener) error { func (r *listenerRegistry) Register(name string, v NewListener) error {
if err := r.registry.Register(name, v); err != nil { if err := r.registry.Register(name, v); err != nil {
logger.Default().Fatal(err) logger.Default().Fatal(err)
+4
View File
@@ -4,10 +4,14 @@ import (
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
// loggerRegistry stores logger.Logger instances.
// It uses the base registry methods without a wrapper since loggers
// are looked up directly and do not need hot-reload proxying.
type loggerRegistry struct { type loggerRegistry struct {
registry[logger.Logger] registry[logger.Logger]
} }
// Register stores a Logger under the given name.
func (r *loggerRegistry) Register(name string, v logger.Logger) error { func (r *loggerRegistry) Register(name string, v logger.Logger) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
+4
View File
@@ -7,14 +7,18 @@ import (
"github.com/go-gost/core/observer" "github.com/go-gost/core/observer"
) )
// observerRegistry implements a hot-reload-safe registry for observer.Observer.
type observerRegistry struct { type observerRegistry struct {
registry[observer.Observer] registry[observer.Observer]
} }
// Register stores an Observer under the given name.
func (r *observerRegistry) Register(name string, v observer.Observer) error { func (r *observerRegistry) Register(name string, v observer.Observer) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Observer.
// Returns nil if name is empty.
func (r *observerRegistry) Get(name string) observer.Observer { func (r *observerRegistry) Get(name string) observer.Observer {
if name != "" { if name != "" {
return &observerWrapper{name: name, r: r} return &observerWrapper{name: name, r: r}
+4
View File
@@ -6,14 +6,18 @@ import (
"github.com/go-gost/core/recorder" "github.com/go-gost/core/recorder"
) )
// recorderRegistry implements a hot-reload-safe registry for recorder.Recorder.
type recorderRegistry struct { type recorderRegistry struct {
registry[recorder.Recorder] registry[recorder.Recorder]
} }
// Register stores a Recorder under the given name.
func (r *recorderRegistry) Register(name string, v recorder.Recorder) error { func (r *recorderRegistry) Register(name string, v recorder.Recorder) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Recorder.
// Returns nil if name is empty.
func (r *recorderRegistry) Get(name string) recorder.Recorder { func (r *recorderRegistry) Get(name string) recorder.Recorder {
if name != "" { if name != "" {
return &recorderWrapper{name: name, r: r} return &recorderWrapper{name: name, r: r}
+37 -1
View File
@@ -26,6 +26,8 @@ import (
) )
var ( var (
// ErrDup is returned by Register when a value is already registered
// under the given name.
ErrDup = errors.New("registry: duplicate object") ErrDup = errors.New("registry: duplicate object")
) )
@@ -56,10 +58,14 @@ var (
loggerReg reg.Registry[logger.Logger] = new(loggerRegistry) loggerReg reg.Registry[logger.Logger] = new(loggerRegistry)
) )
// registry is a sync.Map-backed generic named registry. It implements the
// core Registry[T] interface and is embedded by every typed registry struct.
type registry[T any] struct { type registry[T any] struct {
m sync.Map m sync.Map
} }
// Register stores v under name. It returns ErrDup if name is already
// registered. Empty names are silently ignored.
func (r *registry[T]) Register(name string, v T) error { func (r *registry[T]) Register(name string, v T) error {
if name == "" { if name == "" {
return nil return nil
@@ -71,20 +77,28 @@ func (r *registry[T]) Register(name string, v T) error {
return nil return nil
} }
// Unregister removes the value registered under name. If the value
// implements io.Closer, Close is called before removal; close errors
// are logged but do not prevent deletion.
func (r *registry[T]) Unregister(name string) { func (r *registry[T]) Unregister(name string) {
if v, ok := r.m.Load(name); ok { if v, ok := r.m.Load(name); ok {
if closer, ok := v.(io.Closer); ok { if closer, ok := v.(io.Closer); ok {
closer.Close() if err := closer.Close(); err != nil {
logger.Default().Errorf("registry: close %s: %v", name, err)
}
} }
r.m.Delete(name) r.m.Delete(name)
} }
} }
// IsRegistered reports whether a value is registered under name.
func (r *registry[T]) IsRegistered(name string) bool { func (r *registry[T]) IsRegistered(name string) bool {
_, ok := r.m.Load(name) _, ok := r.m.Load(name)
return ok return ok
} }
// Get returns the value registered under name, or the zero value of T
// if name is empty or not registered.
func (r *registry[T]) Get(name string) (t T) { func (r *registry[T]) Get(name string) (t T) {
if name == "" { if name == "" {
return return
@@ -94,6 +108,7 @@ func (r *registry[T]) Get(name string) (t T) {
return return
} }
// GetAll returns a snapshot of all registered name-to-value mappings.
func (r *registry[T]) GetAll() (m map[string]T) { func (r *registry[T]) GetAll() (m map[string]T) {
m = make(map[string]T) m = make(map[string]T)
r.m.Range(func(key, value any) bool { r.m.Range(func(key, value any) bool {
@@ -105,86 +120,107 @@ func (r *registry[T]) GetAll() (m map[string]T) {
return return
} }
// ListenerRegistry returns the global registry of listener factory functions.
func ListenerRegistry() reg.Registry[NewListener] { func ListenerRegistry() reg.Registry[NewListener] {
return listenerReg return listenerReg
} }
// HandlerRegistry returns the global registry of handler factory functions.
func HandlerRegistry() reg.Registry[NewHandler] { func HandlerRegistry() reg.Registry[NewHandler] {
return handlerReg return handlerReg
} }
// DialerRegistry returns the global registry of dialer factory functions.
func DialerRegistry() reg.Registry[NewDialer] { func DialerRegistry() reg.Registry[NewDialer] {
return dialerReg return dialerReg
} }
// ConnectorRegistry returns the global registry of connector factory functions.
func ConnectorRegistry() reg.Registry[NewConnector] { func ConnectorRegistry() reg.Registry[NewConnector] {
return connectorReg return connectorReg
} }
// ServiceRegistry returns the global registry of service instances.
func ServiceRegistry() reg.Registry[service.Service] { func ServiceRegistry() reg.Registry[service.Service] {
return serviceReg return serviceReg
} }
// ChainRegistry returns the global registry of chain instances.
func ChainRegistry() reg.Registry[chain.Chainer] { func ChainRegistry() reg.Registry[chain.Chainer] {
return chainReg return chainReg
} }
// HopRegistry returns the global registry of hop instances.
func HopRegistry() reg.Registry[hop.Hop] { func HopRegistry() reg.Registry[hop.Hop] {
return hopReg return hopReg
} }
// AutherRegistry returns the global registry of authenticator instances.
func AutherRegistry() reg.Registry[auth.Authenticator] { func AutherRegistry() reg.Registry[auth.Authenticator] {
return autherReg return autherReg
} }
// AdmissionRegistry returns the global registry of admission instances.
func AdmissionRegistry() reg.Registry[admission.Admission] { func AdmissionRegistry() reg.Registry[admission.Admission] {
return admissionReg return admissionReg
} }
// BypassRegistry returns the global registry of bypass instances.
func BypassRegistry() reg.Registry[bypass.Bypass] { func BypassRegistry() reg.Registry[bypass.Bypass] {
return bypassReg return bypassReg
} }
// ResolverRegistry returns the global registry of resolver instances.
func ResolverRegistry() reg.Registry[resolver.Resolver] { func ResolverRegistry() reg.Registry[resolver.Resolver] {
return resolverReg return resolverReg
} }
// HostsRegistry returns the global registry of host mapper instances.
func HostsRegistry() reg.Registry[hosts.HostMapper] { func HostsRegistry() reg.Registry[hosts.HostMapper] {
return hostsReg return hostsReg
} }
// RecorderRegistry returns the global registry of recorder instances.
func RecorderRegistry() reg.Registry[recorder.Recorder] { func RecorderRegistry() reg.Registry[recorder.Recorder] {
return recorderReg return recorderReg
} }
// TrafficLimiterRegistry returns the global registry of traffic limiter instances.
func TrafficLimiterRegistry() reg.Registry[traffic.TrafficLimiter] { func TrafficLimiterRegistry() reg.Registry[traffic.TrafficLimiter] {
return trafficLimiterReg return trafficLimiterReg
} }
// ConnLimiterRegistry returns the global registry of connection limiter instances.
func ConnLimiterRegistry() reg.Registry[conn.ConnLimiter] { func ConnLimiterRegistry() reg.Registry[conn.ConnLimiter] {
return connLimiterReg return connLimiterReg
} }
// RateLimiterRegistry returns the global registry of rate limiter instances.
func RateLimiterRegistry() reg.Registry[rate.RateLimiter] { func RateLimiterRegistry() reg.Registry[rate.RateLimiter] {
return rateLimiterReg return rateLimiterReg
} }
// IngressRegistry returns the global registry of ingress instances.
func IngressRegistry() reg.Registry[ingress.Ingress] { func IngressRegistry() reg.Registry[ingress.Ingress] {
return ingressReg return ingressReg
} }
// RouterRegistry returns the global registry of router instances.
func RouterRegistry() reg.Registry[router.Router] { func RouterRegistry() reg.Registry[router.Router] {
return routerReg return routerReg
} }
// SDRegistry returns the global registry of service discovery instances.
func SDRegistry() reg.Registry[sd.SD] { func SDRegistry() reg.Registry[sd.SD] {
return sdReg return sdReg
} }
// ObserverRegistry returns the global registry of observer instances.
func ObserverRegistry() reg.Registry[observer.Observer] { func ObserverRegistry() reg.Registry[observer.Observer] {
return observerReg return observerReg
} }
// LoggerRegistry returns the global registry of logger instances.
func LoggerRegistry() reg.Registry[logger.Logger] { func LoggerRegistry() reg.Registry[logger.Logger] {
return loggerReg return loggerReg
} }
File diff suppressed because it is too large Load Diff
+4
View File
@@ -7,14 +7,18 @@ import (
"github.com/go-gost/core/resolver" "github.com/go-gost/core/resolver"
) )
// resolverRegistry implements a hot-reload-safe registry for resolver.Resolver.
type resolverRegistry struct { type resolverRegistry struct {
registry[resolver.Resolver] registry[resolver.Resolver]
} }
// Register stores a Resolver under the given name.
func (r *resolverRegistry) Register(name string, v resolver.Resolver) error { func (r *resolverRegistry) Register(name string, v resolver.Resolver) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Resolver.
// Returns nil if name is empty.
func (r *resolverRegistry) Get(name string) resolver.Resolver { func (r *resolverRegistry) Get(name string) resolver.Resolver {
if name != "" { if name != "" {
return &resolverWrapper{name: name, r: r} return &resolverWrapper{name: name, r: r}
+4
View File
@@ -6,14 +6,18 @@ import (
"github.com/go-gost/core/router" "github.com/go-gost/core/router"
) )
// routerRegistry implements a hot-reload-safe registry for router.Router.
type routerRegistry struct { type routerRegistry struct {
registry[router.Router] registry[router.Router]
} }
// Register stores a Router under the given name.
func (r *routerRegistry) Register(name string, v router.Router) error { func (r *routerRegistry) Register(name string, v router.Router) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered Router.
// Returns nil if name is empty.
func (r *routerRegistry) Get(name string) router.Router { func (r *routerRegistry) Get(name string) router.Router {
if name != "" { if name != "" {
return &routerWrapper{name: name, r: r} return &routerWrapper{name: name, r: r}
+4
View File
@@ -6,14 +6,18 @@ import (
"github.com/go-gost/core/sd" "github.com/go-gost/core/sd"
) )
// sdRegistry implements a hot-reload-safe registry for sd.SD.
type sdRegistry struct { type sdRegistry struct {
registry[sd.SD] registry[sd.SD]
} }
// Register stores an SD under the given name.
func (r *sdRegistry) Register(name string, v sd.SD) error { func (r *sdRegistry) Register(name string, v sd.SD) error {
return r.registry.Register(name, v) return r.registry.Register(name, v)
} }
// Get returns a wrapper that delegates to the currently registered SD.
// Returns nil if name is empty.
func (r *sdRegistry) Get(name string) sd.SD { func (r *sdRegistry) Get(name string) sd.SD {
if name != "" { if name != "" {
return &sdWrapper{name: name, r: r} return &sdWrapper{name: name, r: r}
+3
View File
@@ -4,6 +4,9 @@ import (
"github.com/go-gost/core/service" "github.com/go-gost/core/service"
) )
// serviceRegistry stores service.Service instances.
// It uses the base registry methods without a wrapper since services
// are looked up directly by name during startup.
type serviceRegistry struct { type serviceRegistry struct {
registry[service.Service] registry[service.Service]
} }