GoDoxy/internal/route/provider/event_handler.go
yusing 53557e38b6 Fixed a few issues:
- Incorrect name being shown on dashboard "Proxies page"
- Apps being shown when homepage.show is false
- Load balanced routes are shown on homepage instead of the load balancer
- Route with idlewatcher will now be removed on container destroy
- Idlewatcher panic
- Performance improvement
- Idlewatcher infinitely loading
- Reload stucked / not working properly
- Streams stuck on shutdown / reload
- etc...
Added:
- support idlewatcher for loadbalanced routes
- partial implementation for stream type idlewatcher
Issues:
- graceful shutdown
2024-10-18 16:47:01 +08:00

109 lines
2.6 KiB
Go

package provider
import (
E "github.com/yusing/go-proxy/internal/error"
"github.com/yusing/go-proxy/internal/route"
"github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/watcher"
)
type EventHandler struct {
provider *Provider
added []string
removed []string
paused []string
updated []string
errs E.Builder
}
func (provider *Provider) newEventHandler() *EventHandler {
return &EventHandler{
provider: provider,
errs: E.NewBuilder("event errors"),
}
}
func (handler *EventHandler) Handle(parent task.Task, events []watcher.Event) {
oldRoutes := handler.provider.routes
newRoutes, err := handler.provider.LoadRoutesImpl()
if err != nil {
handler.errs.Add(err.Subject("load routes"))
return
}
oldRoutes.RangeAll(func(k string, v *route.Route) {
if !newRoutes.Has(k) {
handler.Remove(v)
}
})
newRoutes.RangeAll(func(k string, newr *route.Route) {
if oldRoutes.Has(k) {
for _, ev := range events {
if handler.match(ev, newr) {
old, ok := oldRoutes.Load(k)
if !ok { // should not happen
panic("race condition")
}
handler.Update(parent, old, newr)
return
}
}
} else {
handler.Add(parent, newr)
}
})
}
func (handler *EventHandler) match(event watcher.Event, route *route.Route) bool {
switch handler.provider.t {
case ProviderTypeDocker:
return route.Entry.Container.ContainerID == event.ActorID ||
route.Entry.Container.ContainerName == event.ActorName
case ProviderTypeFile:
return true
}
// should never happen
return false
}
func (handler *EventHandler) Add(parent task.Task, route *route.Route) {
err := handler.provider.startRoute(parent, route)
if err != nil {
handler.errs.Add(err)
} else {
handler.added = append(handler.added, route.Entry.Alias)
}
}
func (handler *EventHandler) Remove(route *route.Route) {
route.Finish("route removal")
handler.removed = append(handler.removed, route.Entry.Alias)
}
func (handler *EventHandler) Update(parent task.Task, oldRoute *route.Route, newRoute *route.Route) {
oldRoute.Finish("route update")
err := handler.provider.startRoute(parent, newRoute)
if err != nil {
handler.errs.Add(err)
} else {
handler.updated = append(handler.updated, newRoute.Entry.Alias)
}
}
func (handler *EventHandler) Log() {
results := E.NewBuilder("event occured")
for _, alias := range handler.added {
results.Addf("added %s", alias)
}
for _, alias := range handler.removed {
results.Addf("removed %s", alias)
}
for _, alias := range handler.updated {
results.Addf("updated %s", alias)
}
results.Add(handler.errs.Build())
if result := results.Build(); result != nil {
handler.provider.l.Info(result)
}
}