refactor: minor styling fixes; deadcode cleanup and correct log level

This commit is contained in:
yusing
2026-02-15 20:01:36 +08:00
parent 35b8a60edb
commit 154149b06d
29 changed files with 88 additions and 67 deletions

View File

@@ -135,6 +135,9 @@ func (c *Config) Valid() bool {
} }
func (c *Config) Start(parent task.Parent) error { func (c *Config) Start(parent task.Parent) error {
if c.valErr != nil {
return c.valErr
}
if c.Log != nil { if c.Log != nil {
logger, err := accesslog.NewAccessLogger(parent, c.Log) logger, err := accesslog.NewAccessLogger(parent, c.Log)
if err != nil { if err != nil {
@@ -142,9 +145,6 @@ func (c *Config) Start(parent task.Parent) error {
} }
c.logger = logger c.logger = logger
} }
if c.valErr != nil {
return c.valErr
}
if c.needLogOrNotify() { if c.needLogOrNotify() {
c.logNotifyCh = make(chan ipLog, 100) c.logNotifyCh = make(chan ipLog, 100)
@@ -308,9 +308,9 @@ func (c *Config) IPAllowed(ip net.IP) bool {
return true return true
} }
reason := "deny by default" reason := "denied by default"
if c.defaultAllow { if c.defaultAllow {
reason = "allow by default" reason = "allowed by default"
} }
c.logAndNotify(ipAndStr, c.defaultAllow, reason) c.logAndNotify(ipAndStr, c.defaultAllow, reason)
c.cacheRecord(ipAndStr, c.defaultAllow, reason) c.cacheRecord(ipAndStr, c.defaultAllow, reason)

View File

@@ -55,6 +55,7 @@ func (s *UDPListener) WriteTo(p []byte, addr net.Addr) (int, error) {
} }
udpAddr, ok := addr.(*net.UDPAddr) udpAddr, ok := addr.(*net.UDPAddr)
if !ok { if !ok {
log.Error().Msgf("unexpected remote address type: %T, addr: %s", addr, addr.String())
// Not a UDPAddr, drop // Not a UDPAddr, drop
continue continue
} }

View File

@@ -246,7 +246,7 @@ func (p *Provider) ObtainCertAll() error {
for _, provider := range p.allProviders() { for _, provider := range p.allProviders() {
errs.Go(func() error { errs.Go(func() error {
if err := provider.obtainCertIfNotExists(); err != nil { if err := provider.obtainCertIfNotExists(); err != nil {
return fmt.Errorf("failed to obtain cert for %s: %w", provider.GetName(), err) return gperr.PrependSubject(err, provider.GetName())
} }
return nil return nil
}) })

View File

@@ -5,11 +5,13 @@ import (
"github.com/yusing/godoxy/internal/route/rules" "github.com/yusing/godoxy/internal/route/rules"
) )
// Config defines the entrypoint configuration for proxy handling,
// including proxy protocol support, routing rules, middlewares, and access logging.
type Config struct { type Config struct {
SupportProxyProtocol bool `json:"support_proxy_protocol"` SupportProxyProtocol bool `json:"support_proxy_protocol"`
Rules struct { Rules struct {
NotFound rules.Rules `json:"not_found"` NotFound rules.Rules `json:"not_found"`
} `json:"rules"` } `json:"rules"`
Middlewares []map[string]any `json:"middlewares"` Middlewares []map[string]any `json:"middlewares"`
AccessLog *accesslog.RequestLoggerConfig `json:"access_log" validate:"omitempty"` AccessLog *accesslog.RequestLoggerConfig `json:"access_log"`
} }

View File

@@ -145,18 +145,20 @@ func (ep *Entrypoint) SetNotFoundRules(rules rules.Rules) {
ep.notFoundHandler = rules.BuildHandler(serveNotFound) ep.notFoundHandler = rules.BuildHandler(serveNotFound)
} }
func (ep *Entrypoint) SetAccessLogger(parent task.Parent, cfg *accesslog.RequestLoggerConfig) (err error) { func (ep *Entrypoint) SetAccessLogger(parent task.Parent, cfg *accesslog.RequestLoggerConfig) error {
if cfg == nil { if cfg == nil {
ep.accessLogger = nil ep.accessLogger = nil
return err return nil
} }
ep.accessLogger, err = accesslog.NewAccessLogger(parent, cfg) accessLogger, err := accesslog.NewAccessLogger(parent, cfg)
if err != nil { if err != nil {
return err return err
} }
ep.accessLogger = accessLogger
log.Debug().Msg("entrypoint access logger created") log.Debug().Msg("entrypoint access logger created")
return err return nil
} }
func findRouteAnyDomain(routes HTTPRoutes, host string) types.HTTPRoute { func findRouteAnyDomain(routes HTTPRoutes, host string) types.HTTPRoute {

View File

@@ -95,15 +95,17 @@ func BenchmarkEntrypointReal(b *testing.B) {
b.Fatal("server not found") b.Fatal("server not found")
} }
server.ServeHTTP(&w, &req)
if w.statusCode != http.StatusOK {
b.Fatalf("status code is not 200: %d", w.statusCode)
}
if string(w.written) != "1" {
b.Fatalf("written is not 1: %s", string(w.written))
}
b.ResetTimer() b.ResetTimer()
for b.Loop() { for b.Loop() {
server.ServeHTTP(&w, &req) server.ServeHTTP(&w, &req)
if w.statusCode != http.StatusOK {
b.Fatalf("status code is not 200: %d", w.statusCode)
}
if string(w.written) != "1" {
b.Fatalf("written is not 1: %s", string(w.written))
}
} }
} }

View File

@@ -156,7 +156,7 @@ func serveNotFound(w http.ResponseWriter, r *http.Request) {
// Then scraper / scanners will know the subdomain is invalid. // Then scraper / scanners will know the subdomain is invalid.
// With StatusNotFound, they won't know whether it's the path, or the subdomain that is invalid. // With StatusNotFound, they won't know whether it's the path, or the subdomain that is invalid.
if served := middleware.ServeStaticErrorPageFile(w, r); !served { if served := middleware.ServeStaticErrorPageFile(w, r); !served {
log.Error(). log.Warn().
Str("method", r.Method). Str("method", r.Method).
Str("url", r.URL.String()). Str("url", r.URL.String()).
Str("remote", r.RemoteAddr). Str("remote", r.RemoteAddr).

View File

@@ -43,7 +43,8 @@ func (ep *Entrypoint) GetHealthInfoSimple() map[string]types.HealthStatus {
func (ep *Entrypoint) RoutesByProvider() map[string][]types.Route { func (ep *Entrypoint) RoutesByProvider() map[string][]types.Route {
rts := make(map[string][]types.Route) rts := make(map[string][]types.Route)
for r := range ep.IterRoutes { for r := range ep.IterRoutes {
rts[r.ProviderName()] = append(rts[r.ProviderName()], r) providerName := r.ProviderName()
rts[providerName] = append(rts[providerName], r)
} }
return rts return rts
} }

View File

@@ -142,4 +142,5 @@ func (ep *Entrypoint) delHTTPRoute(route types.HTTPRoute) {
srv.DelRoute(route) srv.DelRoute(route)
} }
} }
// TODO: close server if no routes are left
} }

View File

@@ -45,12 +45,7 @@ func (w *Watcher) newWakeEvent(message string, err error) *WakeEvent {
} }
func (e *WakeEvent) WriteSSE(w io.Writer) error { func (e *WakeEvent) WriteSSE(w io.Writer) error {
data, err := sonic.Marshal(e) return writeSSE(w, e)
if err != nil {
return err
}
_, err = fmt.Fprintf(w, "data: %s\n\n", data)
return err
} }
func (w *Watcher) clearEventHistory() { func (w *Watcher) clearEventHistory() {

View File

@@ -33,7 +33,7 @@ func DebugHandler(rw http.ResponseWriter, r *http.Request) {
go w.handleWakeEventsSSE(rw, r) go w.handleWakeEventsSSE(rw, r)
ticker := time.NewTicker(1 * time.Second) ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop() defer ticker.Stop()
events := []WakeEventType{ eventTypes := []WakeEventType{
WakeEventStarting, WakeEventStarting,
WakeEventWakingDep, WakeEventWakingDep,
WakeEventDepReady, WakeEventDepReady,
@@ -57,8 +57,8 @@ func DebugHandler(rw http.ResponseWriter, r *http.Request) {
case <-r.Context().Done(): case <-r.Context().Done():
return return
case <-ticker.C: case <-ticker.C:
idx := rand.IntN(len(events)) idx := rand.IntN(len(eventTypes))
w.sendEvent(events[idx], messages[idx], nil) w.sendEvent(eventTypes[idx], messages[idx], nil)
} }
} }
default: default:

View File

@@ -250,14 +250,13 @@ func (m *Middleware) LogError(req *http.Request) *zerolog.Event {
Str("path", req.URL.Path) Str("path", req.URL.Path)
} }
func PatchReverseProxy(rp *ReverseProxy, middlewaresMap map[string]OptionsRaw) (err error) { func PatchReverseProxy(rp *ReverseProxy, middlewaresMap map[string]OptionsRaw) error {
var middlewares []*Middleware middlewares, err := compileMiddlewares(middlewaresMap)
middlewares, err = compileMiddlewares(middlewaresMap)
if err != nil { if err != nil {
return err return err
} }
patchReverseProxy(rp, middlewares) patchReverseProxy(rp, middlewares)
return err return nil
} }
func patchReverseProxy(rp *ReverseProxy, middlewares []*Middleware) { func patchReverseProxy(rp *ReverseProxy, middlewares []*Middleware) {

View File

@@ -2,6 +2,7 @@ package notif
import ( import (
"errors" "errors"
"fmt"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@@ -49,7 +50,7 @@ func (base *ProviderBase) Validate() error {
} }
u, err := url.Parse(base.URL) u, err := url.Parse(base.URL)
if err != nil { if err != nil {
return err return fmt.Errorf("invalid url: %w", err)
} }
base.URL = u.String() base.URL = u.String()
return nil return nil

View File

@@ -44,14 +44,13 @@ func (webhook *Webhook) Validate() error {
switch webhook.Template { switch webhook.Template {
case "": case "":
if webhook.MIMEType == MimeTypeJSON { if webhook.Payload == "" {
errs.Adds("invalid payload, expect non-empty")
} else if webhook.MIMEType == MimeTypeJSON {
if !validateJSONPayload(webhook.Payload) { if !validateJSONPayload(webhook.Payload) {
errs.Adds("invalid payload, expect valid JSON") errs.Adds("invalid payload, expect valid JSON")
} }
} }
if webhook.Payload == "" {
errs.Adds("invalid payload, expect non-empty")
}
case "discord": case "discord":
webhook.ColorMode = "dec" webhook.ColorMode = "dec"
webhook.Method = http.MethodPost webhook.Method = http.MethodPost

View File

@@ -31,8 +31,10 @@ type Config struct {
client *Client client *Client
} }
const ResourcePollInterval = 3 * time.Second const (
const SessionRefreshInterval = 1 * time.Minute ResourcePollInterval = 3 * time.Second
SessionRefreshInterval = 1 * time.Minute
)
// NodeStatsPollInterval controls how often node stats are streamed when streaming is enabled. // NodeStatsPollInterval controls how often node stats are streamed when streaming is enabled.
const NodeStatsPollInterval = time.Second const NodeStatsPollInterval = time.Second
@@ -158,6 +160,7 @@ func (c *Config) refreshSessionLoop(ctx context.Context) {
backoff := time.Duration(min(math.Pow(2, float64(numRetries)), 10)) * time.Second backoff := time.Duration(min(math.Pow(2, float64(numRetries)), 10)) * time.Second
ticker.Reset(backoff) ticker.Reset(backoff)
} else { } else {
numRetries = 0
ticker.Reset(SessionRefreshInterval) ticker.Reset(SessionRefreshInterval)
} }
} }

View File

@@ -140,9 +140,6 @@ func formatIECBytes(b uint64) string {
// One decimal, trimming trailing ".0" to keep output compact (e.g. "10GiB"). // One decimal, trimming trailing ".0" to keep output compact (e.g. "10GiB").
s := fmt.Sprintf("%.1f", val) s := fmt.Sprintf("%.1f", val)
s = strings.TrimSuffix(s, ".0") s = strings.TrimSuffix(s, ".0")
if exp == 0 {
return s + "B"
}
return s + prefixes[exp] + "B" return s + prefixes[exp] + "B"
} }

View File

@@ -15,6 +15,10 @@ func checkExists(ctx context.Context, r types.Route) error {
if r.UseLoadBalance() { // skip checking for load balanced routes if r.UseLoadBalance() { // skip checking for load balanced routes
return nil return nil
} }
ep := entrypoint.FromCtx(ctx)
if ep == nil {
return fmt.Errorf("entrypoint not found in context")
}
var ( var (
existing types.Route existing types.Route
ok bool ok bool

View File

@@ -55,7 +55,7 @@ func NewFileServer(base *Route) (*FileServer, error) {
s := &FileServer{Route: base} s := &FileServer{Route: base}
s.Root = filepath.Clean(s.Root) s.Root = filepath.Clean(s.Root)
if !path.IsAbs(s.Root) { if !filepath.IsAbs(s.Root) {
return nil, errors.New("`root` must be an absolute path") return nil, errors.New("`root` must be an absolute path")
} }

View File

@@ -108,4 +108,4 @@ example: # matching `example.y.z`
no_loading_page: false no_loading_page: false
docker: docker:
container_id: abc123 container_id: abc123
container_name: example-app container_name: example-app

View File

@@ -99,6 +99,6 @@ func (handler *EventHandler) Update(parent task.Parent, oldRoute *route.Route, n
func (handler *EventHandler) Log() { func (handler *EventHandler) Log() {
if err := handler.errs.Error(); err != nil { if err := handler.errs.Error(); err != nil {
handler.provider.Logger().Info().Msg(err.Error()) handler.provider.Logger().Error().Msg(err.Error())
} }
} }

View File

@@ -23,7 +23,7 @@ import (
"github.com/yusing/goutils/version" "github.com/yusing/goutils/version"
) )
type ReveseProxyRoute struct { type ReverseProxyRoute struct {
*Route *Route
loadBalancer *loadbalancer.LoadBalancer loadBalancer *loadbalancer.LoadBalancer
@@ -31,11 +31,11 @@ type ReveseProxyRoute struct {
rp *reverseproxy.ReverseProxy rp *reverseproxy.ReverseProxy
} }
var _ types.ReverseProxyRoute = (*ReveseProxyRoute)(nil) var _ types.ReverseProxyRoute = (*ReverseProxyRoute)(nil)
// var globalMux = http.NewServeMux() // TODO: support regex subdomain matching. // var globalMux = http.NewServeMux() // TODO: support regex subdomain matching.
func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, error) { func NewReverseProxyRoute(base *Route) (*ReverseProxyRoute, error) {
httpConfig := base.HTTPConfig httpConfig := base.HTTPConfig
proxyURL := base.ProxyURL proxyURL := base.ProxyURL
@@ -111,7 +111,7 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, error) {
} }
} }
r := &ReveseProxyRoute{ r := &ReverseProxyRoute{
Route: base, Route: base,
rp: rp, rp: rp,
} }
@@ -119,12 +119,12 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, error) {
} }
// ReverseProxy implements routes.ReverseProxyRoute. // ReverseProxy implements routes.ReverseProxyRoute.
func (r *ReveseProxyRoute) ReverseProxy() *reverseproxy.ReverseProxy { func (r *ReverseProxyRoute) ReverseProxy() *reverseproxy.ReverseProxy {
return r.rp return r.rp
} }
// Start implements task.TaskStarter. // Start implements task.TaskStarter.
func (r *ReveseProxyRoute) Start(parent task.Parent) error { func (r *ReverseProxyRoute) Start(parent task.Parent) error {
r.task = parent.Subtask("http."+r.Name(), false) r.task = parent.Subtask("http."+r.Name(), false)
r.task.SetValue(monitor.DisplayNameKey{}, r.DisplayName()) r.task.SetValue(monitor.DisplayNameKey{}, r.DisplayName())
@@ -160,6 +160,7 @@ func (r *ReveseProxyRoute) Start(parent task.Parent) error {
if r.HealthMon != nil { if r.HealthMon != nil {
if err := r.HealthMon.Start(r.task); err != nil { if err := r.HealthMon.Start(r.task); err != nil {
// TODO: add to event history
log.Warn().Err(err).Msg("health monitor error") log.Warn().Err(err).Msg("health monitor error")
r.HealthMon = nil r.HealthMon = nil
} }
@@ -186,23 +187,23 @@ func (r *ReveseProxyRoute) Start(parent task.Parent) error {
return nil return nil
} }
func (r *ReveseProxyRoute) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (r *ReverseProxyRoute) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// req.Header.Set("Accept-Encoding", "identity") // req.Header.Set("Accept-Encoding", "identity")
r.handler.ServeHTTP(w, req) r.handler.ServeHTTP(w, req)
} }
var lbLock sync.Mutex var lbLock sync.Mutex
func (r *ReveseProxyRoute) addToLoadBalancer(parent task.Parent, ep entrypoint.Entrypoint) error { func (r *ReverseProxyRoute) addToLoadBalancer(parent task.Parent, ep entrypoint.Entrypoint) error {
var lb *loadbalancer.LoadBalancer var lb *loadbalancer.LoadBalancer
cfg := r.LoadBalance cfg := r.LoadBalance
lbLock.Lock() lbLock.Lock()
defer lbLock.Unlock() defer lbLock.Unlock()
l, ok := ep.HTTPRoutes().Get(cfg.Link) l, ok := ep.HTTPRoutes().Get(cfg.Link)
var linked *ReveseProxyRoute var linked *ReverseProxyRoute
if ok { if ok {
linked = l.(*ReveseProxyRoute) // it must be a reverse proxy route linked = l.(*ReverseProxyRoute) // it must be a reverse proxy route
lb = linked.loadBalancer lb = linked.loadBalancer
lb.UpdateConfigIfNeeded(cfg) lb.UpdateConfigIfNeeded(cfg)
if linked.Homepage.Name == "" { if linked.Homepage.Name == "" {
@@ -211,7 +212,7 @@ func (r *ReveseProxyRoute) addToLoadBalancer(parent task.Parent, ep entrypoint.E
} else { } else {
lb = loadbalancer.New(cfg) lb = loadbalancer.New(cfg)
_ = lb.Start(parent) // always return nil _ = lb.Start(parent) // always return nil
linked = &ReveseProxyRoute{ linked = &ReverseProxyRoute{
Route: &Route{ Route: &Route{
Alias: cfg.Link, Alias: cfg.Link,
Homepage: r.Homepage, Homepage: r.Homepage,

View File

@@ -682,7 +682,7 @@ func (r *Route) DisplayName() string {
func (r *Route) MarshalZerologObject(e *zerolog.Event) { func (r *Route) MarshalZerologObject(e *zerolog.Event) {
e.Str("alias", r.Alias) e.Str("alias", r.Alias)
switch r := r.impl.(type) { switch r := r.impl.(type) {
case *ReveseProxyRoute: case *ReverseProxyRoute:
e.Str("type", "reverse_proxy"). e.Str("type", "reverse_proxy").
Str("scheme", r.Scheme.String()). Str("scheme", r.Scheme.String()).
Str("bind", r.LisURL.Host). Str("bind", r.LisURL.Host).
@@ -728,7 +728,7 @@ func (r *Route) PreferOver(other any) bool {
switch v := other.(type) { switch v := other.(type) {
case *Route: case *Route:
or = v or = v
case *ReveseProxyRoute: case *ReverseProxyRoute:
or = v.Route or = v.Route
case *FileServer: case *FileServer:
or = v.Route or = v.Route

View File

@@ -52,13 +52,14 @@ func (s *TCPTCPStream) ListenAndServe(ctx context.Context, preDial, onRead netty
if ep := entrypoint.FromCtx(ctx); ep != nil { if ep := entrypoint.FromCtx(ctx); ep != nil {
if proxyProto := ep.SupportProxyProtocol(); proxyProto { if proxyProto := ep.SupportProxyProtocol(); proxyProto {
log.Debug().EmbedObject(s).Msg("wrapping listener with proxy protocol")
s.listener = &proxyproto.Listener{Listener: s.listener} s.listener = &proxyproto.Listener{Listener: s.listener}
} }
} }
if acl := acl.FromCtx(ctx); acl != nil { if aclCfg := acl.FromCtx(ctx); aclCfg != nil {
log.Debug().EmbedObject(s).Msg("wrapping listener with ACL") log.Debug().EmbedObject(s).Msg("wrapping listener with ACL")
s.listener = acl.WrapTCP(s.listener) s.listener = aclCfg.WrapTCP(s.listener)
} }
s.preDial = preDial s.preDial = preDial

View File

@@ -81,9 +81,9 @@ func (s *UDPUDPStream) ListenAndServe(ctx context.Context, preDial, onRead netty
return err return err
} }
s.listener = l s.listener = l
if acl := acl.FromCtx(ctx); acl != nil { if aclCfg := acl.FromCtx(ctx); aclCfg != nil {
log.Debug().EmbedObject(s).Msg("wrapping listener with ACL") log.Debug().EmbedObject(s).Msg("wrapping listener with ACL")
s.listener = acl.WrapUDP(s.listener) s.listener = aclCfg.WrapUDP(l)
} }
s.preDial = preDial s.preDial = preDial
s.onRead = onRead s.onRead = onRead

View File

@@ -105,12 +105,14 @@ func ValidateWithFieldTags(s any) error {
detail = "require " + strconv.Quote(detail) detail = "require " + strconv.Quote(detail)
} }
errs.Add(gperr.PrependSubject(ErrValidationError, e.Namespace()). errs.Add(gperr.PrependSubject(ErrValidationError, e.Namespace()).
Withf(detail)) Withf("%s", detail))
} }
} }
return errs.Error() return errs.Error()
} }
// dive recursively dives into the nested pointers of the dst.
// dst value pointer must be valid (satisfies reflect.Value.IsValid()).
func dive(dst reflect.Value) (v reflect.Value, t reflect.Type) { func dive(dst reflect.Value) (v reflect.Value, t reflect.Type) {
dstT := dst.Type() dstT := dst.Type()
for { for {
@@ -445,7 +447,7 @@ func Convert(src reflect.Value, dst reflect.Value, checkValidateTag bool) error
} }
obj, ok := src.Interface().(SerializedObject) obj, ok := src.Interface().(SerializedObject)
if !ok { if !ok {
return fmt.Errorf("convert: %w for %s to %s", ErrUnsupportedConversion, dstT, srcT) return fmt.Errorf("convert: %w from %s to %s", ErrUnsupportedConversion, srcT, dstT)
} }
return mapUnmarshalValidate(obj, dst.Addr(), checkValidateTag) return mapUnmarshalValidate(obj, dst.Addr(), checkValidateTag)
case srcKind == reflect.Slice: // slice to slice case srcKind == reflect.Slice: // slice to slice

View File

@@ -17,7 +17,7 @@ func initConfigDirWatcher() {
configDirWatcher = NewDirectoryWatcher(t, common.ConfigBasePath) configDirWatcher = NewDirectoryWatcher(t, common.ConfigBasePath)
} }
// NewConfigFileWatcher creates a new file watcher for file under common.ConfigBasePath. // NewConfigFileWatcher creates a new file watcher for a file under common.ConfigBasePath.
func NewConfigFileWatcher(filename string) Watcher { func NewConfigFileWatcher(filename string) Watcher {
configDirWatcherInitOnce.Do(initConfigDirWatcher) configDirWatcherInitOnce.Do(initConfigDirWatcher)
return configDirWatcher.Add(filename) return configDirWatcher.Add(filename)

View File

@@ -61,6 +61,9 @@ func NewDirectoryWatcher(parent task.Parent, dirPath string) *DirWatcher {
return helper return helper
} }
var _ Watcher = (*DirWatcher)(nil)
// Events implements the Watcher interface.
func (h *DirWatcher) Events(_ context.Context) (<-chan Event, <-chan error) { func (h *DirWatcher) Events(_ context.Context) (<-chan Event, <-chan error) {
return h.eventCh, h.errCh return h.eventCh, h.errCh
} }
@@ -112,7 +115,7 @@ func (h *DirWatcher) start() {
relPath := strings.TrimPrefix(fsEvent.Name, h.dir) relPath := strings.TrimPrefix(fsEvent.Name, h.dir)
relPath = strings.TrimPrefix(relPath, "/") relPath = strings.TrimPrefix(relPath, "/")
if len(relPath) > 0 && relPath[0] == '.' { // hideden file if len(relPath) > 0 && relPath[0] == '.' { // hidden file
continue continue
} }

View File

@@ -82,6 +82,9 @@ func NewDockerWatcher(dockerCfg types.DockerProviderConfig) DockerWatcher {
} }
} }
var _ Watcher = (*DockerWatcher)(nil)
// Events implements the Watcher interface.
func (w DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan error) { func (w DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan error) {
return w.EventsWithOptions(ctx, optionsDefault) return w.EventsWithOptions(ctx, optionsDefault)
} }
@@ -123,11 +126,11 @@ func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerList
eventCh <- reloadTrigger eventCh <- reloadTrigger
retry := time.NewTicker(dockerWatcherRetryInterval) retry := time.NewTicker(dockerWatcherRetryInterval)
defer retry.Stop()
outer: outer:
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
retry.Stop()
return return
case <-retry.C: case <-retry.C:
if checkConnection(ctx, client) { if checkConnection(ctx, client) {
@@ -135,6 +138,7 @@ func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerList
} }
} }
} }
retry.Stop()
// connection successful, trigger reload (reload routes) // connection successful, trigger reload (reload routes)
eventCh <- reloadTrigger eventCh <- reloadTrigger
// reopen event channel // reopen event channel

View File

@@ -10,6 +10,9 @@ type fileWatcher struct {
errCh chan error errCh chan error
} }
var _ Watcher = (*fileWatcher)(nil)
// Events implements the Watcher interface.
func (fw *fileWatcher) Events(ctx context.Context) (<-chan Event, <-chan error) { func (fw *fileWatcher) Events(ctx context.Context) (<-chan Event, <-chan error) {
return fw.eventCh, fw.errCh return fw.eventCh, fw.errCh
} }