From b056e997a7c67ce5db47d25566035ffe8074b071 Mon Sep 17 00:00:00 2001 From: Garet Halliday <me@garet.holiday> Date: Thu, 28 Sep 2023 18:27:00 -0500 Subject: [PATCH] matchers to json --- lib/gat/app.go | 6 +- lib/gat/gatcaddyfile/README.md | 13 +--- lib/gat/gatcaddyfile/gattype.go | 22 +++++- lib/gat/gatcaddyfile/matchers.go | 130 +++++++++++++++++++++++++++++++ lib/gat/route.go | 4 +- lib/gat/server.go | 7 +- 6 files changed, 162 insertions(+), 20 deletions(-) create mode 100644 lib/gat/gatcaddyfile/matchers.go diff --git a/lib/gat/app.go b/lib/gat/app.go index 17867557..f0793687 100644 --- a/lib/gat/app.go +++ b/lib/gat/app.go @@ -18,9 +18,9 @@ import ( ) type Config struct { - StatLogPeriod dur.Duration `json:"stat_log_period"` - Listen []ListenerConfig `json:"listen"` - Servers []ServerConfig `json:"servers"` + StatLogPeriod dur.Duration `json:"stat_log_period,omitempty"` + Listen []ListenerConfig `json:"listen,omitempty"` + Servers []ServerConfig `json:"servers,omitempty"` } func init() { diff --git a/lib/gat/gatcaddyfile/README.md b/lib/gat/gatcaddyfile/README.md index dac46a9f..4a2141f8 100644 --- a/lib/gat/gatcaddyfile/README.md +++ b/lib/gat/gatcaddyfile/README.md @@ -3,12 +3,7 @@ Server blocks will be matched in order by their keys. Different SSL configuratio (due to technical limitations). ## Directives -| Directive | Description | -|------------------|--------------------------------------------------------------------------| -| ssl | ssl configuration for this server | -| allow_parameters | set which initial parameters are allowed | -| user | rewrite username | -| password | use global password instead of password provided by pool | -| database | rewrite database | -| parameters | rewrite parameters | -| {provider} | a pool provider. if pool is not found, the next provider will be checked | +| Directive | Description | +|-----------|-----------------------------------| +| ssl | ssl configuration for this server | +| {handler} | each handler will be run in order | diff --git a/lib/gat/gatcaddyfile/gattype.go b/lib/gat/gatcaddyfile/gattype.go index 38eea92f..3b96dc93 100644 --- a/lib/gat/gatcaddyfile/gattype.go +++ b/lib/gat/gatcaddyfile/gattype.go @@ -1,11 +1,11 @@ package gatcaddyfile import ( - "log" - "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + + "gfx.cafe/gfx/pggat/lib/gat" ) func init() { @@ -15,9 +15,23 @@ func init() { type ServerType struct{} func (ServerType) Setup(blocks []caddyfile.ServerBlock, m map[string]any) (*caddy.Config, []caddyconfig.Warning, error) { + var config caddy.Config + var warnings []caddyconfig.Warning + + var app gat.App + for _, block := range blocks { - log.Printf("%#v", block) + var server gat.ServerConfig + + server.Match = MatcherFromConnectionStrings(block.Keys, &warnings) + + app.Servers = append(app.Servers, server) + } + + if config.AppsRaw == nil { + config.AppsRaw = make(caddy.ModuleMap) } + config.AppsRaw[string(app.CaddyModule().ID)] = caddyconfig.JSON(app, &warnings) - return nil, nil, nil + return &config, warnings, nil } diff --git a/lib/gat/gatcaddyfile/matchers.go b/lib/gat/gatcaddyfile/matchers.go new file mode 100644 index 00000000..a85e141e --- /dev/null +++ b/lib/gat/gatcaddyfile/matchers.go @@ -0,0 +1,130 @@ +package gatcaddyfile + +import ( + "encoding/json" + "strings" + + "github.com/caddyserver/caddy/v2/caddyconfig" + + "gfx.cafe/gfx/pggat/lib/gat/matchers" +) + +func MatcherFromConnectionStrings(strs []string, warnings *[]caddyconfig.Warning) json.RawMessage { + var or matchers.Or + + for _, str := range strs { + val := MatcherFromConnectionString(str, warnings) + if val != nil { + or.Or = append(or.Or, val) + } + } + + if len(or.Or) == 0 { + return nil + } + if len(or.Or) == 1 { + return or.Or[0] + } + + return caddyconfig.JSONModuleObject( + or, + "matcher", + "and", + warnings, + ) +} + +// MatcherFromConnectionString converts from the postgres connection string format to a bunch of matchers. +// Example: postgres://user@address:port/database?parameter_key=parameter_value +func MatcherFromConnectionString(str string, warnings *[]caddyconfig.Warning) json.RawMessage { + // strip optional postgres:// + str = strings.TrimPrefix(str, "postgres://") + + if str == "" { + return nil + } + + var and matchers.And + + var parametersString string + str, parametersString, _ = strings.Cut(str, "?") + + if parametersString != "" { + var parameters matchers.StartupParameters + parameters.Parameters = make(map[string]string) + kvs := strings.Split(parametersString, "&") + for _, kv := range kvs { + k, v, _ := strings.Cut(kv, "=") + parameters.Parameters[k] = v + } + and.And = append( + and.And, + caddyconfig.JSONModuleObject( + parameters, + "matcher", + "startup_parameters", + warnings, + ), + ) + } + + var database matchers.Database + str, database.Database, _ = strings.Cut(str, "/") + if database.Database != "" { + and.And = append( + and.And, + caddyconfig.JSONModuleObject( + database, + "matcher", + "database", + warnings, + ), + ) + } + + var address = matchers.LocalAddress{ + Network: "tcp", + } + var user matchers.User + var ok bool + user.User, address.Address, ok = strings.Cut(str, "@") + if !ok { + address.Address = user.User + user.User = "" + } else if user.User != "" { + and.And = append( + and.And, + caddyconfig.JSONModuleObject( + user, + "matcher", + "user", + warnings, + ), + ) + } + if address.Address != "" { + and.And = append( + and.And, + caddyconfig.JSONModuleObject( + address, + "matcher", + "local_address", + warnings, + ), + ) + } + + if len(and.And) == 0 { + return nil + } + if len(and.And) == 1 { + return and.And[0] + } + + return caddyconfig.JSONModuleObject( + and, + "matcher", + "and", + warnings, + ) +} diff --git a/lib/gat/route.go b/lib/gat/route.go index 9a3a9db9..dc8e97fb 100644 --- a/lib/gat/route.go +++ b/lib/gat/route.go @@ -8,8 +8,8 @@ import ( ) type RouteConfig struct { - Match json.RawMessage `json:"match" caddy:"namespace=pggat.matchers inline_key=matcher"` - Handle json.RawMessage `json:"handle" caddy:"namespace=pggat.handlers inline_key=handler"` + Match json.RawMessage `json:"match,omitempty" caddy:"namespace=pggat.matchers inline_key=matcher"` + Handle json.RawMessage `json:"handle,omitempty" caddy:"namespace=pggat.handlers inline_key=handler"` } type Route struct { diff --git a/lib/gat/server.go b/lib/gat/server.go index 0cdc7bf8..0bcdda4e 100644 --- a/lib/gat/server.go +++ b/lib/gat/server.go @@ -16,8 +16,8 @@ import ( ) type ServerConfig struct { - Match json.RawMessage `json:"match" caddy:"namespace=pggat.matchers inline_key=matcher"` - Routes []RouteConfig `json:"routes"` + Match json.RawMessage `json:"match,omitempty" caddy:"namespace=pggat.matchers inline_key=matcher"` + Routes []RouteConfig `json:"routes,omitempty"` } type Server struct { @@ -80,6 +80,9 @@ func (T *Server) Serve(conn *fed.Conn) { continue } + if route.handle == nil { + continue + } err := route.handle.Handle(conn) if err != nil { if errors.Is(err, io.EOF) { -- GitLab