diff --git a/lib/gat/app.go b/lib/gat/app.go index 17867557dea45c094fde5efd49b1bd25a52a4976..f0793687128748e43021bd29b4edbf4e20505684 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 dac46a9f9b8e884a61a17a421c507ce7aeb6e717..4a2141f8dd7c9acc6b39ec238d4f22f2304272be 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 38eea92f1f93291289f7205dedfcd5edcbe4a5e8..3b96dc9362e13baf888968a69beb34f65710671a 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 0000000000000000000000000000000000000000..a85e141e4e1e9ff489e192582ae4f61dfb0ac1c4 --- /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 9a3a9db956b8d4b0904b6c8630ef10788978f323..dc8e97fb7497300b57673f1f38a030435b126121 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 0cdc7bf88e5d694991221eb22b3e5cdbb52fd98c..0bcdda4e4fee8822e39b824ba7c3cba36bb0675f 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) {