91 lines
1.9 KiB
Go
91 lines
1.9 KiB
Go
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)
|
|
}
|