Files
go-proxy/internal/router/router.go
T

91 lines
1.9 KiB
Go
Raw Normal View History

2026-09-15 01:38:15 +09:00
package router
import (
"log"
"net/http"
"net/http/httputil"
"strings"
"sync"
"github.com/user/go-proxy/internal/config"
"github.com/user/go-proxy/internal/proxy"
)
// routeEntry stores the configuration and its pre-compiled ReverseProxy
type routeEntry struct {
config config.RouterRoute
proxy *httputil.ReverseProxy
}
type Router struct {
mu sync.RWMutex
routes []routeEntry
}
func NewRouter(cfg config.HTTPConfig) *Router {
r := &Router{}
r.UpdateConfig(cfg)
return r
}
func (r *Router) UpdateConfig(cfg config.HTTPConfig) {
var newRoutes []routeEntry
for _, routeCfg := range cfg.Routers {
// Collect backends (support both Backends array and single BackendURL)
backends := routeCfg.Backends
if len(backends) == 0 && routeCfg.BackendURL != "" {
backends = []string{routeCfg.BackendURL}
}
if len(backends) == 0 {
log.Printf("Warning: Route %s has no backends configured, skipping", routeCfg.Path)
continue
}
p, err := proxy.NewLoadBalancedHTTPProxy(backends)
if err != nil {
log.Printf("Error creating proxy for route %s: %v", routeCfg.Path, err)
continue
}
newRoutes = append(newRoutes, routeEntry{
config: routeCfg,
proxy: p,
})
}
r.mu.Lock()
defer r.mu.Unlock()
r.routes = newRoutes
}
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
r.mu.RLock()
routes := r.routes
r.mu.RUnlock()
for _, route := range routes {
cfg := route.config
if cfg.Host != "" && req.Host != cfg.Host {
continue
}
if strings.HasPrefix(req.URL.Path, cfg.Path) {
if cfg.StripPrefix {
req.URL.Path = strings.TrimPrefix(req.URL.Path, cfg.Path)
if req.URL.Path == "" || req.URL.Path[0] != '/' {
req.URL.Path = "/" + req.URL.Path
}
}
// Serve using the pre-compiled proxy
route.proxy.ServeHTTP(w, req)
return
}
}
http.Error(w, "Not Found", http.StatusNotFound)
}