217 lines
6 KiB
Go
217 lines
6 KiB
Go
package zgate
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/zeevdiukman/go-reverseproxy"
|
|
"github.com/zeevdiukman/go-router"
|
|
"github.com/zeevdiukman/go-server"
|
|
"github.com/zeevdiukman/go-zgate/pkg/config"
|
|
)
|
|
|
|
const CERTS_PATH string = "./assets/certs/"
|
|
|
|
type Zgate struct {
|
|
Context context.Context
|
|
Config *config.Config
|
|
// DomainRouters DomainRouters
|
|
EntryPoints EntryPoints
|
|
ActiveEntryPoints ActiveEntryPoints
|
|
}
|
|
type ActiveEntryPoints map[string]bool
|
|
|
|
// type DomainRouters map[string]*mux.Router
|
|
type EntryPoints map[string]*EntryPoint
|
|
type EntryPoint struct {
|
|
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{
|
|
Context: context.Background(),
|
|
Config: config.New(),
|
|
// DomainRouters: DomainRouters{},
|
|
EntryPoints: EntryPoints{},
|
|
ActiveEntryPoints: ActiveEntryPoints{},
|
|
}
|
|
zGate.initActiveEntryPoints()
|
|
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)
|
|
}
|
|
|
|
func forEach[K comparable, V any](mp map[K]V, f func(K, V)) {
|
|
for k, v := range mp {
|
|
f(k, v)
|
|
}
|
|
}
|
|
|
|
func (zGate *Zgate) initActiveEntryPoints() {
|
|
zGate.Config.EntryPoints.ForEach(func(epName string, epConfig *config.EntryPoint) {
|
|
zGate.Config.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) {
|
|
if rConfig.EntryPoint == epName {
|
|
zGate.ActiveEntryPoints[epName] = true
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// 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
|
|
zGate.Config.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) {
|
|
if s == rConfig.EntryPoint {
|
|
|
|
}
|
|
})
|
|
zGateEntryPoint.Server.CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem")
|
|
go zGateEntryPoint.Server.ListenAndServeTLS()
|
|
})
|
|
}
|
|
|
|
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 DefaultDirector(rpHandler *reverseproxy.ReverseProxy, jup reverseproxy.JoinURLPathFunc) func(*http.Request) {
|
|
return func(r *http.Request) {
|
|
r = r.WithContext(rpHandler.Context)
|
|
ctxKey := reverseproxy.CtxKey("host")
|
|
hostFromCtx := rpHandler.Context.Value(ctxKey).(string)
|
|
target, _ := url.Parse(hostFromCtx)
|
|
targetQuery := target.RawQuery
|
|
r.URL.Scheme = target.Scheme
|
|
r.URL.Host = target.Host
|
|
r.URL.Path, r.URL.RawPath = jup(target, r.URL)
|
|
if targetQuery == "" || r.URL.RawQuery == "" {
|
|
r.URL.RawQuery = targetQuery + r.URL.RawQuery
|
|
} else {
|
|
r.URL.RawQuery = targetQuery + "&" + r.URL.RawQuery
|
|
}
|
|
}
|
|
}
|
|
|
|
func StrAddressPortToInt(addr string) int {
|
|
_, portStr, _ := strings.Cut(addr, ":")
|
|
port, _ := strconv.Atoi(portStr)
|
|
return port
|
|
}
|