From c35eceb9dbc4a86cbaece7f7606ce366134e294f Mon Sep 17 00:00:00 2001 From: Zeev Diukman Date: Sat, 8 Mar 2025 17:51:28 +0000 Subject: [PATCH] 4 --- pkg/config/config.go | 106 ++++++++++++++++----- zgate.go | 216 +++++++++++++++++++++++++++---------------- 2 files changed, 218 insertions(+), 104 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index d1ecee5..7369d72 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -4,6 +4,7 @@ import ( "regexp" "strings" + "github.com/spf13/viper" "github.com/zeevdiukman/go-config" ) @@ -16,6 +17,7 @@ const ENTRYPOINTS_KEY string = "entrypoints" const TLS_KEY string = "tls.certproviders" type Config struct { + Viper *viper.Viper HTTP *HTTP TLS *TLS EntryPoints EntryPoints @@ -71,6 +73,7 @@ func New() *Config { c.Load() appConfig := &Config{ + Viper: c.Viper, HTTP: &HTTP{ Routers: Routers{}, Services: Services{}, @@ -88,17 +91,28 @@ func New() *Config { return appConfig } + +func (r Rules) Get(ruleName string) string { + if _, ok := r.Map[ruleName]; !ok { + return "" + } + return r.Map[ruleName].Value +} + func (r Routers) ForEach(fn func(routerName string, routerConfig *Router)) { for k, v := range r { fn(k, v) } } + func (ep EntryPoints) ForEach(fn func(entryPointName string, entryPointConfig *EntryPoint)) { forEach(ep, fn) } + func (s Services) ForEach(fn func(serviceName string, serviceConfig *Service)) { forEach(s, fn) } + func (c *Config) InitRouters(vConfig *config.Config) { c.HTTP.Routers = make(Routers) for k, v := range vConfig.Sub(ROUTERS_KEY).AllSettings() { @@ -132,22 +146,61 @@ func (c *Config) InitRouters(vConfig *config.Config) { EntryPoint: entryPoint, TLS: &RouterTLS{CertProvider: tls}, } - r.ForRuleFunc("Domain", func(domain string) { - r.Rules.Map["Domain"] = &Rule{ - Name: "Domain", - Value: domain, - } - }) - r.ForRuleFunc("Path", func(path string) { - r.Rules.Map["Path"] = &Rule{ - Name: "Path", - Value: path, - } - }) + r.RuleInit("Domain") + r.RuleInit("Path") + r.RuleInit("PathPrefix") + // r.RuleInit("Path") + // r.ForRuleFunc("Domain", func(domain string) { + // r.Rules.Map["Domain"] = &Rule{ + // Name: "Domain", + // Value: domain, + // } + // }) + // r.ForRuleFunc("Path", func(path string) { + // r.Rules.Map["Path"] = &Rule{ + // Name: "Path", + // Value: path, + // } + // }) + // r.ForRuleFunc("PathPrefix", func(path string) { + // r.Rules.Map["PathPrefix"] = &Rule{ + // Name: "PathPrefix", + // Value: path, + // } + // }) c.HTTP.Routers[k] = r } } + +func (r *Router) RuleInit(ruleName string) { + r.ForRuleFunc(ruleName, func(ruleValue string) { + // _, ok := isOK(r.Rules.Map, ruleName) + // if ok { + r.Rules.Map[ruleName] = &Rule{ + Name: ruleName, + Value: ruleValue, + } + // } + + }) +} + +func (r *Router) ForRuleFunc(ruleName string, fn func(rValue string)) { + rules := r.Rules.Raw + rulesSlice := splitStatementByRegex(rules, "\\(`(.*?)`\\)") + for idx, rule := range rulesSlice { + rule, _ = strings.CutPrefix(rule, ".") + if rule == ruleName { + valueIdx := idx + 1 + // if len(rulesSlice) < valueIdx { + v := rulesSlice[valueIdx] + fn(v) + // } + } + } +} + func (c *Config) InitServices(vConfig *config.Config) { c.HTTP.Services = make(map[string]*Service) for k, v := range vConfig.Sub(SERVICES_KEY).AllSettings() { @@ -156,6 +209,7 @@ func (c *Config) InitServices(vConfig *config.Config) { } } } + func (c *Config) InitEntryPoints(vConfig *config.Config) { c.EntryPoints = make(EntryPoints) for k, v := range vConfig.Sub(ENTRYPOINTS_KEY).AllSettings() { @@ -192,23 +246,13 @@ func (c *Config) InitTLS(vConfig *config.Config) { } } } + func forEach[K comparable, V comparable](mp map[K]V, fn func(key K, value V)) { for k, v := range mp { fn(k, v) } } -func (r *Router) ForRuleFunc(ruleName string, fn func(string)) { - rules := r.Rules.Raw - rulesSlice := splitStatementByRegex(rules, "\\(`(.*?)`\\)") - for idx, rule := range rulesSlice { - rule, _ = strings.CutPrefix(rule, ".") - if rule == ruleName { - fn(rulesSlice[idx+1]) - } - } -} - func splitStatementByRegex(str string, regx string) []string { input := str @@ -239,3 +283,19 @@ func splitStatementByRegex(str string, regx string) []string { return result } + +func isOK[K comparable, V comparable](mp map[K]V, key K) (V, bool) { + if v, ok := mp[key]; ok { + return v, true + } else { + return v, false + } +} + +func OK[K comparable, V comparable](mp map[K]V, key K) bool { + if _, ok := mp[key]; ok { + return true + } else { + return false + } +} diff --git a/zgate.go b/zgate.go index 49819f0..4e44c7d 100644 --- a/zgate.go +++ b/zgate.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + "github.com/gorilla/mux" "github.com/zeevdiukman/go-reverseproxy" "github.com/zeevdiukman/go-router" "github.com/zeevdiukman/go-server" @@ -17,37 +18,45 @@ const CERTS_PATH string = "./assets/certs/" type Zgate struct { Context context.Context - // Routers struct { - // Maps map[string]*router.HostRouter - // } - // map[string]*router.HostRouter - // Rules map[string]map[string]string - // Services map[string]string - Config *config.Config - DomainRouters DomainRouters + Config *config.Config + // DomainRouters DomainRouters EntryPoints EntryPoints ActiveEntryPoints ActiveEntryPoints } type ActiveEntryPoints map[string]bool -type DomainRouters map[string]*router.DomainRouter + +// type DomainRouters map[string]*mux.Router type EntryPoints map[string]*EntryPoint type EntryPoint struct { - *server.Server - *router.Router + IsTLS bool + Server *server.Server + Router *mux.Router + // Router *router.Router + HostRouters HostRouters + Name string } type HostRouters map[string]*router.DomainRouter func New() *Zgate { - zGate := &Zgate{} - zGate.Context = context.Background() - zGate.Config = config.New() + zGate := &Zgate{ + Context: context.Background(), + Config: config.New(), + // DomainRouters: DomainRouters{}, + EntryPoints: EntryPoints{}, + ActiveEntryPoints: ActiveEntryPoints{}, + } zGate.initActiveEntryPoints() - zGate.DomainRouters = make(DomainRouters) - zGate.EntryPoints = make(EntryPoints) + zGate.Config.Viper.WatchConfig() return zGate } +func (zGate *Zgate) NewReverseProxy(serviceName string) *reverseproxy.ReverseProxy { + serviceURL := zGate.Config.HTTP.Services[serviceName].URL + newReverseProxy := reverseproxy.New(zGate.Context, serviceURL) + return newReverseProxy +} + func (ep EntryPoints) ForEach(f func(string, *EntryPoint)) { forEach(ep, f) } @@ -59,58 +68,109 @@ func forEach[K comparable, V any](mp map[K]V, f func(K, V)) { } func (zGate *Zgate) initActiveEntryPoints() { - activeEntryPoints := make(ActiveEntryPoints) - zGate.Config.EntryPoints.ForEach(func(entryPointName string, entryPointConfig *config.EntryPoint) { + zGate.Config.EntryPoints.ForEach(func(epName string, epConfig *config.EntryPoint) { zGate.Config.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) { - if rConfig.EntryPoint == entryPointName { - activeEntryPoints[entryPointName] = true + if rConfig.EntryPoint == epName { + zGate.ActiveEntryPoints[epName] = true } }) }) - zGate.ActiveEntryPoints = activeEntryPoints -} -func (zGate *Zgate) BuildActiveEntryPoints() { - zGate.Config.EntryPoints.ForEach(func(entryPointName string, entryPointConfig *config.EntryPoint) { - if isUsed, ok := zGate.ActiveEntryPoints[entryPointName]; ok && isUsed { - if !isOK(zGate.ActiveEntryPoints, entryPointName) { - zGate.EntryPoints = make(map[string]*EntryPoint) - } - r := router.NewRouter() - _, portStr, _ := strings.Cut(entryPointConfig.Address, ":") - port, _ := strconv.Atoi(portStr) - s := server.New().Name(entryPointName).Port(port) - s.Router(r) - zGate.EntryPoints[entryPointName] = &EntryPoint{ - Server: s, - Router: r, - HostRouters: make(map[string]*router.DomainRouter), - } - } - }) } -func (zGate *Zgate) BuildRouters() { - zGate.Config.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) { - if isUsed, ok := zGate.ActiveEntryPoints[rConfig.EntryPoint]; ok && isUsed { - domain := rConfig.Rules.Map["Domain"].Value - serviceURL := zGate.Config.HTTP.Services[rConfig.Service].URL - if _, ok := zGate.EntryPoints[rConfig.EntryPoint]; ok { - entryPoint := zGate.EntryPoints[rConfig.EntryPoint] - if _, ok := entryPoint.HostRouters[domain]; !ok { - entryPoint.HostRouters = make(map[string]*router.DomainRouter) - } - rp := reverseproxy.New(zGate.Context, serviceURL) - rp.DirectorFunc(func(jup reverseproxy.JoinURLPathFunc) reverseproxy.DirectorFunc { - return defaultDirector(rp, jup) - }) - r := zGate.EntryPoints[rConfig.EntryPoint].Router - hostRouter := r.NewDomainRouter(domain) - hostRouter.Handler(rp) - zGate.EntryPoints[rConfig.EntryPoint].HostRouters[domain] = hostRouter - } - } - }) +// func (zGate *Zgate) BuildActiveEntryPoints() { +// zGate.Config.EntryPoints.ForEach(func(entryPointName string, entryPointConfig *config.EntryPoint) { +// v, ok := isOK(zGate.ActiveEntryPoints, entryPointName) +// if ok && v { +// port := strAddressPortToInt(entryPointConfig.Address) +// newEntryPoint := zGate.EntryPoints.NewEntryPoint(entryPointName) +// newEntryPoint.Server.Port(port).Name(entryPointName) +// newEntryPoint.Server.Router(newEntryPoint.Router) +// } +// }) +// } + +func (entryPoints EntryPoints) GetEntryPoint(name string) *EntryPoint { + return entryPoints[name] } + +func (entryPoints EntryPoints) NewEntryPoint(name string) *EntryPoint { + entryPoints[name] = &EntryPoint{ + Server: server.New(), + Router: mux.NewRouter(), + HostRouters: HostRouters{}, + Name: name, + IsTLS: false, + } + + return entryPoints[name] +} + +func (entryPoint *EntryPoint) SetName(name string) *EntryPoint { + entryPoint.Name = name + return entryPoint +} + +func (entryPoint *EntryPoint) NewServer() *EntryPoint { + entryPoint.Server = server.New() + entryPoint.Server.Name(entryPoint.Name) + return entryPoint +} +func (entryPoint *EntryPoint) Port(port int) *EntryPoint { + entryPoint.Server.Port(port) + return entryPoint +} +func (entryPoint *EntryPoint) SetServer(s *server.Server) *EntryPoint { + entryPoint.Server = s + return entryPoint +} +func (entryPoints EntryPoints) GetServer(name string) *server.Server { + return entryPoints[name].Server +} +func (entryPoints EntryPoints) GetRouter(name string) *mux.Router { + return entryPoints[name].Router +} +func (entryPoint *EntryPoint) NewRouter() *EntryPoint { + r := mux.NewRouter() + entryPoint.SetRouter(r) + entryPoint.Router.Name(entryPoint.Name) + return entryPoint +} +func (entryPoint *EntryPoint) SetRouter(r *mux.Router) *EntryPoint { + entryPoint.Server.Handler = r + entryPoint.Router = r + return entryPoint +} + +// func (entryPoint *EntryPoint) IsEntryPointTLS() bool { + +// name := entryPoint.IsTLS +// z +// return entryPoint +// } + +// func (zGate *Zgate) BuildRouters() { +// zGate.Config.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) { +// v, ok := isOK(zGate.ActiveEntryPoints, rConfig.EntryPoint) +// if ok && v { +// domain := rConfig.Rules.Map["Domain"].Value +// serviceURL := zGate.Config.HTTP.Services[rConfig.Service].URL +// if isOK(zGate.EntryPoints, rConfig.EntryPoint); ok { +// entryPoint := zGate.EntryPoints[rConfig.EntryPoint] +// if _, ok := entryPoint.HostRouters[domain]; !ok { +// entryPoint.HostRouters = make(map[string]*router.DomainRouter) +// } +// rp := reverseproxy.New(zGate.Context, serviceURL) +// rp.DirectorFunc(func(jup reverseproxy.JoinURLPathFunc) reverseproxy.DirectorFunc { +// return DefaultDirector(rp, jup) +// }) +// r := zGate.EntryPoints[rConfig.EntryPoint].Router +// hostRouter := r.NewDomainRouter(domain) +// hostRouter.Handler(rp) +// zGate.EntryPoints[rConfig.EntryPoint].HostRouters[domain] = hostRouter +// } +// } +// }) +// } func (zGate *Zgate) ListenAndServe() { zGate.EntryPoints.ForEach(func(s string, zGateEntryPoint *EntryPoint) { //TODO: TLS per domain @@ -119,32 +179,20 @@ func (zGate *Zgate) ListenAndServe() { } }) - zGateEntryPoint.CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem") - go zGateEntryPoint.ListenAndServeTLS() + zGateEntryPoint.Server.CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem") + go zGateEntryPoint.Server.ListenAndServeTLS() }) } -// func (activeEntryPoints ActiveEntryPoints) BuildActiveEntryPoint(entryPointName string, port int) { -// r := router.NewRouter() -// _, portStr, _ := strings.Cut(port, ":") -// port, _ := strconv.Atoi(portStr) -// s := server.New().Name(entryPointName).Port(port) -// s.Router(r) -// entryPoint = &EntryPoint{ -// Server: s, -// Router: r, -// HostRouters: make(map[string]*router.DomainRouter), -// } -// } - -func isOK[K comparable, V comparable](mp map[K]V, key K) bool { - if _, ok := mp[key]; !ok { - return false +func isOK[K comparable, V comparable](mp map[K]V, key K) (V, bool) { + if v, ok := mp[key]; ok { + return v, true + } else { + return v, false } - return true } -func defaultDirector(rpHandler *reverseproxy.ReverseProxy, jup reverseproxy.JoinURLPathFunc) func(*http.Request) { +func DefaultDirector(rpHandler *reverseproxy.ReverseProxy, jup reverseproxy.JoinURLPathFunc) func(*http.Request) { return func(r *http.Request) { r = r.WithContext(rpHandler.Context) ctxKey := reverseproxy.CtxKey("host") @@ -161,3 +209,9 @@ func defaultDirector(rpHandler *reverseproxy.ReverseProxy, jup reverseproxy.Join } } } + +func StrAddressPortToInt(addr string) int { + _, portStr, _ := strings.Cut(addr, ":") + port, _ := strconv.Atoi(portStr) + return port +}