From ddc358d09bbb72f906387668ea449fee6841809e Mon Sep 17 00:00:00 2001 From: d34dscene Date: Sat, 28 Jun 2025 00:39:03 +0200 Subject: [PATCH] fixed middlewares, better types --- agent/cmd/main.go | 1 + agent/internal/client/client.go | 1 + agent/internal/collector/docker.go | 1 + go.mod | 12 +- go.sum | 27 +- internal/api/handler/oidc.go | 5 +- internal/api/handler/upload.go | 50 +- internal/api/middlewares/auth.go | 1 + internal/api/server/server.go | 14 +- internal/api/service/agent.go | 10 +- internal/api/service/backup.go | 7 +- internal/api/service/middleware.go | 7 +- internal/api/service/service.go | 1 + internal/backup/backup.go | 1 + internal/config/flags.go | 7 + internal/config/setup.go | 1 + internal/config/zod.go | 55 + internal/convert/middleware.go | 7 + internal/dns/client.go | 1 + internal/dns/technitium.go | 30 +- internal/mail/mail.go | 1 + internal/settings/settings.go | 1 + internal/settings/settings_test.go | 149 ++ internal/storage/local.go | 1 + internal/store/connection.go | 1 + internal/store/db/http_middlewares.sql.go | 13 +- internal/store/db/tcp_middlewares.sql.go | 13 +- internal/store/queries/http_middlewares.sql | 11 +- internal/store/queries/tcp_middlewares.sql | 11 +- internal/store/squash.go | 12 +- internal/traefik/client.go | 26 +- pkg/build/build.go | 1 + pkg/build/update.go | 25 +- pkg/logger/logger.go | 1 + pkg/meta/claims.go | 1 + pkg/util/ip.go | 7 +- pkg/util/tools.go | 1 + proto/gen/mantrae/v1/middleware.pb.go | 392 ++--- proto/gen/openapi/openapi.yaml | 3 + proto/mantrae/v1/middleware.proto | 7 +- tygo.yaml | 11 - web/src/app.html | 12 +- .../lib/components/forms/DynamicForm.svelte | 277 ++- web/src/lib/components/forms/FormField.svelte | 289 ---- .../lib/components/forms/PluginForm.svelte | 127 -- .../components/forms/httpMiddleware.svelte | 38 +- .../lib/components/forms/httpRouter.svelte | 8 +- .../lib/components/forms/httpService.svelte | 10 +- .../lib/components/forms/tcpMiddleware.svelte | 51 + web/src/lib/components/forms/tcpRouter.svelte | 2 +- .../lib/components/forms/tcpService.svelte | 2 +- web/src/lib/components/forms/udpRouter.svelte | 2 +- .../lib/components/forms/udpService.svelte | 2 +- .../lib/components/modals/middleware.svelte | 13 +- web/src/lib/components/modals/router.svelte | 84 +- .../lib/components/tables/ColumnBadge.svelte | 2 +- web/src/lib/formGenerator.ts | 149 ++ web/src/lib/gen/mantrae/v1/middleware_pb.ts | 13 +- web/src/lib/gen/tygo/dynamic/index.ts | 1489 ----------------- web/src/lib/gen/tygo/tls/index.ts | 112 -- web/src/lib/gen/tygo/types/index.ts | 264 --- web/src/lib/gen/zen/traefik-schemas.ts | 588 +++++++ web/src/lib/types.ts | 76 +- web/src/routes/middlewares/+page.svelte | 20 +- web/src/routes/router/+page.svelte | 2 +- 65 files changed, 1782 insertions(+), 2777 deletions(-) create mode 100644 internal/config/zod.go create mode 100644 internal/settings/settings_test.go delete mode 100644 tygo.yaml delete mode 100644 web/src/lib/components/forms/FormField.svelte delete mode 100644 web/src/lib/components/forms/PluginForm.svelte create mode 100644 web/src/lib/components/forms/tcpMiddleware.svelte create mode 100644 web/src/lib/formGenerator.ts delete mode 100644 web/src/lib/gen/tygo/dynamic/index.ts delete mode 100644 web/src/lib/gen/tygo/tls/index.ts delete mode 100644 web/src/lib/gen/tygo/types/index.ts create mode 100644 web/src/lib/gen/zen/traefik-schemas.ts diff --git a/agent/cmd/main.go b/agent/cmd/main.go index 2eae834..67e9fdd 100644 --- a/agent/cmd/main.go +++ b/agent/cmd/main.go @@ -1,3 +1,4 @@ +// Package main is the entrypoint for the mantrae agent. package main import ( diff --git a/agent/internal/client/client.go b/agent/internal/client/client.go index ac479f0..170090e 100644 --- a/agent/internal/client/client.go +++ b/agent/internal/client/client.go @@ -1,3 +1,4 @@ +// Package client provides the agent's main gRPC client logic. package client import ( diff --git a/agent/internal/collector/docker.go b/agent/internal/collector/docker.go index a5ef19f..71e2ab5 100644 --- a/agent/internal/collector/docker.go +++ b/agent/internal/collector/docker.go @@ -1,3 +1,4 @@ +// Package collector provides functions for collecting data from the host system. package collector import ( diff --git a/go.mod b/go.mod index 07cc22f..8579dec 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/mizuchilabs/mantrae go 1.24.4 require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250613105001-9f2d3c737feb.1 + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250625184727-c923a0c2a132.1 connectrpc.com/connect v1.18.1 connectrpc.com/cors v0.1.0 connectrpc.com/grpchealth v1.4.0 @@ -12,7 +12,7 @@ require ( github.com/aws/aws-sdk-go-v2 v1.36.5 github.com/aws/aws-sdk-go-v2/config v1.29.17 github.com/aws/aws-sdk-go-v2/credentials v1.17.70 - github.com/aws/aws-sdk-go-v2/service/s3 v1.81.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0 github.com/caarlos0/env/v11 v11.3.1 github.com/cloudflare/cloudflare-go v0.115.0 github.com/coreos/go-oidc/v3 v3.14.1 @@ -20,18 +20,19 @@ require ( github.com/domodwyer/mailyak/v3 v3.6.2 github.com/golang-jwt/jwt/v5 v5.2.2 github.com/google/uuid v1.6.0 + github.com/hypersequent/zen v0.0.0-20250317110808-f521ea1d4fc3 github.com/joeig/go-powerdns/v3 v3.16.0 github.com/pressly/goose/v3 v3.24.3 github.com/rs/cors v1.11.1 github.com/stretchr/testify v1.10.0 github.com/traefik/paerser v0.2.2 - github.com/traefik/traefik/v3 v3.4.1 + github.com/traefik/traefik/v3 v3.4.3 golang.org/x/crypto v0.39.0 golang.org/x/net v0.41.0 golang.org/x/oauth2 v0.30.0 google.golang.org/protobuf v1.36.6 modernc.org/sqlite v1.38.0 - sigs.k8s.io/yaml v1.4.0 + sigs.k8s.io/yaml v1.5.0 ) require ( @@ -63,7 +64,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-acme/lego/v4 v4.23.1 // indirect - github.com/go-jose/go-jose/v4 v4.1.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.1 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -108,6 +109,7 @@ require ( go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect golang.org/x/mod v0.25.0 // indirect golang.org/x/sync v0.15.0 // indirect diff --git a/go.sum b/go.sum index d7425bb..4074672 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250613105001-9f2d3c737feb.1 h1:AUL6VF5YWL01j/1H/DQbPUSDkEwYqwVCNw7yhbpOxSQ= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250613105001-9f2d3c737feb.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250625184727-c923a0c2a132.1 h1:6tCo3lsKNLqUjRPhyc8JuYWYUiQkulufxSDOfG1zgWQ= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250625184727-c923a0c2a132.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U= buf.build/go/protovalidate v0.13.1 h1:6loHDTWdY/1qmqmt1MijBIKeN4T9Eajrqb9isT1W1s8= buf.build/go/protovalidate v0.13.1/go.mod h1:C/QcOn/CjXRn5udUwYBiLs8y1TGy7RS+GOSKqjS77aU= cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= @@ -48,8 +48,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzRE github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= -github.com/aws/aws-sdk-go-v2/service/s3 v1.81.0 h1:1GmCadhKR3J2sMVKs2bAYq9VnwYeCqfRyZzD4RASGlA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.81.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= +github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0 h1:JubM8CGDDFaAOmBrd8CRYNr49ZNgEAiLwGwgNMdS0nw= +github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= @@ -93,8 +93,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV4= github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI= -github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY= -github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw= +github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= +github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= @@ -117,7 +117,6 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY= github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo= @@ -137,6 +136,8 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/http-wasm/http-wasm-host-go v0.7.0 h1:+1KrRyOO6tWiDB24QrtSYyDmzFLBBs3jioKaUT0mq1c= github.com/http-wasm/http-wasm-host-go v0.7.0/go.mod h1:adXKcLmL7yuavH/e0kBAp7b3TgAHTo/enCduyN5bXGM= +github.com/hypersequent/zen v0.0.0-20250317110808-f521ea1d4fc3 h1:hql4suSs7RG3+t5UyjdPXIzBmXg6AyFoqRRF+TPR3yY= +github.com/hypersequent/zen v0.0.0-20250317110808-f521ea1d4fc3/go.mod h1:uJ9mqUok1RHIAoVlkWxPHJqXNLwhLzh7jCUbp2V9Rws= github.com/jarcoal/httpmock v1.4.0 h1:BvhqnH0JAYbNudL2GMJKgOHe2CtKlzJ/5rWKyp+hc2k= github.com/jarcoal/httpmock v1.4.0/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0= github.com/joeig/go-powerdns/v3 v3.16.0 h1:d6k0dVlBYr+B9P5U+74rVY1VmQxUG6Qdtlb3F33cBLQ= @@ -210,8 +211,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ= github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24= -github.com/traefik/traefik/v3 v3.4.1 h1:QBO/C9ILViPVBhsmY8nEnoobTULxg6oW1jUTX8FFh8w= -github.com/traefik/traefik/v3 v3.4.1/go.mod h1:8FHoFbX5P+zMQ3UUjjfrDH87BDSbHllcUQyiI2wCP3o= +github.com/traefik/traefik/v3 v3.4.3 h1:4bFwOd+kd+c+XQevhHbZ4V4Ui5jMXI5aHh6YdHj0mqM= +github.com/traefik/traefik/v3 v3.4.3/go.mod h1:uXB3uTO0wFWHFdliHvsHXvG52n3anUYHed89yRDcZmc= github.com/unrolled/render v1.7.0 h1:1yke01/tZiZpiXfUG+zqB+6fq3G4I+KDmnh0EhPq7So= github.com/unrolled/render v1.7.0/go.mod h1:LwQSeDhjml8NLjIO9GJO1/1qpFJxtfVIpzxXKjfVkoI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -254,6 +255,10 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -348,5 +353,5 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= +sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/internal/api/handler/oidc.go b/internal/api/handler/oidc.go index 35507f2..a903da1 100644 --- a/internal/api/handler/oidc.go +++ b/internal/api/handler/oidc.go @@ -1,3 +1,4 @@ +// Package handler provides HTTP handlers for the API. package handler import ( @@ -172,7 +173,7 @@ func OIDCCallback(a *config.App) http.HandlerFunc { // Extract user info from verified token var userInfo OIDCUserInfo - if err := verifiedToken.Claims(&userInfo); err != nil { + if err = verifiedToken.Claims(&userInfo); err != nil { http.Error( w, fmt.Sprintf("Failed to parse claims: %v", err), @@ -180,7 +181,7 @@ func OIDCCallback(a *config.App) http.HandlerFunc { ) return } - if err := userInfo.Validate(); err != nil { + if err = userInfo.Validate(); err != nil { http.Error( w, fmt.Sprintf("Invalid user info: %v", err), diff --git a/internal/api/handler/upload.go b/internal/api/handler/upload.go index 03c2f9f..5950142 100644 --- a/internal/api/handler/upload.go +++ b/internal/api/handler/upload.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net/http" "path/filepath" "slices" @@ -27,7 +28,11 @@ func UploadAvatar(a *config.App) http.HandlerFunc { http.Error(w, "File too large or invalid form data", http.StatusBadRequest) return } - defer r.MultipartForm.RemoveAll() + defer func() { + if err := r.MultipartForm.RemoveAll(); err != nil { + slog.Error("failed to close request body", "error", err) + } + }() userID := r.URL.Query().Get("user_id") if userID == "" { @@ -40,7 +45,11 @@ func UploadAvatar(a *config.App) http.HandlerFunc { http.Error(w, "Failed to get uploaded file", http.StatusBadRequest) return } - defer file.Close() + defer func() { + if err = file.Close(); err != nil { + slog.Error("failed to close uploaded file", "error", err) + } + }() extension := filepath.Ext(header.Filename) allowedExtensions := []string{".png", ".jpg", ".jpeg"} @@ -79,14 +88,22 @@ func UploadBackup(a *config.App) http.HandlerFunc { http.Error(w, "File too large or invalid form data", http.StatusBadRequest) return } - defer r.MultipartForm.RemoveAll() + defer func() { + if err := r.MultipartForm.RemoveAll(); err != nil { + slog.Error("failed to close request body", "error", err) + } + }() file, header, err := r.FormFile("file") if err != nil { http.Error(w, "Failed to get uploaded file", http.StatusBadRequest) return } - defer file.Close() + defer func() { + if err = file.Close(); err != nil { + slog.Error("failed to close uploaded file", "error", err) + } + }() extension := filepath.Ext(header.Filename) allowedExtensions := []string{".db", ".json", ".yaml", ".yml"} @@ -136,25 +153,22 @@ func UploadBackup(a *config.App) http.HandlerFunc { return } - if extension == ".yaml" || extension == ".yml" { - if err = yaml.Unmarshal(content, &dynamic); err != nil { - http.Error( - w, - fmt.Sprintf("Failed to decode YAML file: %v", err), - http.StatusInternalServerError, - ) + switch extension { + case ".yaml", ".yml": + if err = yaml.Unmarshal(content, dynamic); err != nil { + http.Error(w, fmt.Sprintf("Failed to decode YAML file: %v", err), http.StatusInternalServerError) return } - } else if extension == ".json" { - if err = json.Unmarshal(content, &dynamic); err != nil { - http.Error( - w, - fmt.Sprintf("Failed to decode JSON file: %v", err), - http.StatusInternalServerError, - ) + case ".json": + if err = json.Unmarshal(content, dynamic); err != nil { + http.Error(w, fmt.Sprintf("Failed to decode JSON file: %v", err), http.StatusInternalServerError) return } + default: + http.Error(w, "Invalid file type", http.StatusBadRequest) + return } + if err = convert.DynamicToDB(r.Context(), *a.Conn.GetQuery(), profileIDValue, dynamic); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/internal/api/middlewares/auth.go b/internal/api/middlewares/auth.go index 6d69093..e784335 100644 --- a/internal/api/middlewares/auth.go +++ b/internal/api/middlewares/auth.go @@ -1,3 +1,4 @@ +// Package middlewares provides authentication and logging middleware. package middlewares import ( diff --git a/internal/api/server/server.go b/internal/api/server/server.go index 96ba1b1..cbe9048 100644 --- a/internal/api/server/server.go +++ b/internal/api/server/server.go @@ -67,7 +67,11 @@ func NewServer(app *config.App) *Server { func (s *Server) Start(ctx context.Context) error { s.registerServices() - defer s.app.Conn.Close() + defer func() { + if err := s.app.Conn.Close(); err != nil { + slog.Error("failed to close database connection", "error", err) + } + }() server := &http.Server{ Addr: s.Host + ":" + s.Port, @@ -83,12 +87,12 @@ func (s *Server) Start(ctx context.Context) error { // Start server in a goroutine go func() { - serverUrl, _ := s.app.SM.Get("server_url") - if serverUrl == "" { - serverUrl = s.Host + ":" + s.Port + serverURL, ok := s.app.SM.Get("server_url") + if ok && serverURL == "" { + serverURL = s.Host + ":" + s.Port } slog.Info("Server listening on", "address", "127.0.0.1:"+s.Port) - slog.Info("Agents can connect to", "address", serverUrl) + slog.Info("Agents can connect to", "address", serverURL) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { serverErr <- err } diff --git a/internal/api/service/agent.go b/internal/api/service/agent.go index 33e6f9a..cdb12e1 100644 --- a/internal/api/service/agent.go +++ b/internal/api/service/agent.go @@ -48,11 +48,11 @@ func (s *AgentService) CreateAgent( return nil, connect.NewError(connect.CodeInternal, err) } - serverUrl, err := s.app.Conn.GetQuery().GetSetting(ctx, settings.KeyServerURL) + serverURL, err := s.app.Conn.GetQuery().GetSetting(ctx, settings.KeyServerURL) if err != nil { return nil, connect.NewError(connect.CodeInternal, err) } - if serverUrl.Value == "" { + if serverURL.Value == "" { return nil, connect.NewError( connect.CodeInvalidArgument, errors.New("server url is required, check your settings"), @@ -157,7 +157,7 @@ func (s *AgentService) HealthCheck( } // Rotate Token if it's close to expiring - if _, err := s.updateToken(ctx, &agent); err != nil { + if _, err = s.updateToken(ctx, &agent); err != nil { return nil, connect.NewError(connect.CodeInternal, err) } @@ -235,7 +235,7 @@ func (s *AgentService) updateToken(ctx context.Context, agent *db.Agent) (*strin } func (s *AgentService) createToken(agentID string, profileID int64) (*string, error) { - serverUrl, ok := s.app.SM.Get(settings.KeyServerURL) + serverURL, ok := s.app.SM.Get(settings.KeyServerURL) if !ok { return nil, errors.New("failed to get server url setting") } @@ -248,7 +248,7 @@ func (s *AgentService) createToken(agentID string, profileID int64) (*string, er token, err := meta.EncodeAgentToken( profileID, agentID, - serverUrl, + serverURL, s.app.Secret, time.Now().Add(settings.AsDuration(agentInterval)), ) diff --git a/internal/api/service/backup.go b/internal/api/service/backup.go index 26844a8..e03bee4 100644 --- a/internal/api/service/backup.go +++ b/internal/api/service/backup.go @@ -4,6 +4,7 @@ import ( "context" "errors" "io" + "log/slog" "connectrpc.com/connect" "github.com/mizuchilabs/mantrae/internal/config" @@ -95,7 +96,11 @@ func (s *BackupService) DownloadBackup( if err != nil { return connect.NewError(connect.CodeInternal, err) } - defer reader.Close() + defer func() { + if err = reader.Close(); err != nil { + slog.Error("failed to close backup reader", "error", err) + } + }() buf := make([]byte, 32*1024) for { diff --git a/internal/api/service/middleware.go b/internal/api/service/middleware.go index 92bedd2..4cddf54 100644 --- a/internal/api/service/middleware.go +++ b/internal/api/service/middleware.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "log/slog" "net/http" "slices" @@ -320,7 +321,11 @@ func (s *MiddlewareService) GetMiddlewarePlugins( if err != nil { return nil, connect.NewError(connect.CodeInternal, err) } - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() var allPlugins []schema.Plugin if err := json.NewDecoder(resp.Body).Decode(&allPlugins); err != nil { diff --git a/internal/api/service/service.go b/internal/api/service/service.go index 96438ba..f373b93 100644 --- a/internal/api/service/service.go +++ b/internal/api/service/service.go @@ -1,3 +1,4 @@ +// Package service provides the gRPC service implementations. package service import ( diff --git a/internal/backup/backup.go b/internal/backup/backup.go index 2325cce..c67f391 100644 --- a/internal/backup/backup.go +++ b/internal/backup/backup.go @@ -1,3 +1,4 @@ +// Package backup provides functionality for creating and restoring backups. package backup import ( diff --git a/internal/config/flags.go b/internal/config/flags.go index 42565bc..87a41d0 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -15,6 +15,7 @@ type Flags struct { Version bool Update bool Squash bool + Zod bool } func ParseFlags() { @@ -22,6 +23,7 @@ func ParseFlags() { flag.BoolVar(&f.Version, "version", false, "Print version and exit") flag.BoolVar(&f.Update, "update", false, "Update the application") flag.BoolVar(&f.Squash, "squash", false, "Squash the database") + flag.BoolVar(&f.Zod, "zod", false, "Generate zod schemas (only for dev)") flag.Parse() flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) @@ -35,5 +37,10 @@ func ParseFlags() { store.Squash() os.Exit(1) } + + if f.Zod { + StructToZodSchema() + os.Exit(1) + } build.Update(f.Update) } diff --git a/internal/config/setup.go b/internal/config/setup.go index 51bce5c..d23f52b 100644 --- a/internal/config/setup.go +++ b/internal/config/setup.go @@ -1,3 +1,4 @@ +// Package config provides application configuration and setup. package config import ( diff --git a/internal/config/zod.go b/internal/config/zod.go new file mode 100644 index 0000000..216dcaa --- /dev/null +++ b/internal/config/zod.go @@ -0,0 +1,55 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/hypersequent/zen" + "github.com/traefik/traefik/v3/pkg/config/dynamic" +) + +// StructToZodSchema converts a struct to a zod schema (for use in the frontend) +func StructToZodSchema() { + types := map[string]any{ + // Routers + "httpRouter": dynamic.Router{}, + "tcpRouter": dynamic.TCPRouter{}, + "udpRouter": dynamic.UDPRouter{}, + + // Services + "httpService": dynamic.Service{}, + "tcpService": dynamic.TCPService{}, + "udpService": dynamic.UDPService{}, + + // HTTP Middlewares + "httpMiddleware": dynamic.Middleware{}, + + // TCP Middlewares + "tcpMiddleware": dynamic.TCPMiddleware{}, + } + + var builder strings.Builder + + // Add a header + builder.WriteString("// This file is auto-generated via `zen.StructToZodSchema`.\n") + builder.WriteString("// Do not edit manually.\n\n") + builder.WriteString("import { z } from 'zod';\n\n") + + for _, strct := range types { + schema := zen.StructToZodSchema(strct) + builder.WriteString(fmt.Sprintf("%s\n", schema)) + } + + out := "./web/src/lib/gen/zen/traefik-schemas.ts" + + if err := os.MkdirAll(filepath.Dir(out), 0755); err != nil { + panic(err) + } + if err := os.WriteFile(out, []byte(builder.String()), 0644); err != nil { + panic(err) + } + + fmt.Printf("✅ Zod schemas written to %s\n", out) +} diff --git a/internal/convert/middleware.go b/internal/convert/middleware.go index 03ca9ca..899c4c8 100644 --- a/internal/convert/middleware.go +++ b/internal/convert/middleware.go @@ -18,6 +18,7 @@ func HTTPMiddlewareToProto(m *db.HttpMiddleware) *mantraev1.Middleware { Name: m.Name, Config: config, Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_HTTP, + Enabled: m.Enabled, CreatedAt: SafeTimestamp(m.CreatedAt), UpdatedAt: SafeTimestamp(m.UpdatedAt), } @@ -36,6 +37,7 @@ func TCPMiddlewareToProto(m *db.TcpMiddleware) *mantraev1.Middleware { Name: m.Name, Config: config, Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_TCP, + Enabled: m.Enabled, CreatedAt: SafeTimestamp(m.CreatedAt), UpdatedAt: SafeTimestamp(m.UpdatedAt), } @@ -58,6 +60,7 @@ func TCPMiddlewaresToProto(middlewares []db.TcpMiddleware) []*mantraev1.Middlewa } // Specialized batch conversion functions + func MiddlewaresByProfileToProto( middlewares []db.ListMiddlewaresByProfileRow, ) []*mantraev1.Middleware { @@ -76,6 +79,7 @@ func MiddlewaresByProfileToProto( Name: m.Name, Config: config, Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_HTTP, + Enabled: m.Enabled, CreatedAt: SafeTimestamp(m.CreatedAt), UpdatedAt: SafeTimestamp(m.UpdatedAt), }) @@ -91,6 +95,7 @@ func MiddlewaresByProfileToProto( Name: m.Name, Config: config, Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_TCP, + Enabled: m.Enabled, CreatedAt: SafeTimestamp(m.CreatedAt), UpdatedAt: SafeTimestamp(m.UpdatedAt), }) @@ -117,6 +122,7 @@ func MiddlewaresByAgentToProto(middlewares []db.ListMiddlewaresByAgentRow) []*ma Name: m.Name, Config: config, Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_HTTP, + Enabled: m.Enabled, CreatedAt: SafeTimestamp(m.CreatedAt), UpdatedAt: SafeTimestamp(m.UpdatedAt), }) @@ -132,6 +138,7 @@ func MiddlewaresByAgentToProto(middlewares []db.ListMiddlewaresByAgentRow) []*ma Name: m.Name, Config: config, Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_TCP, + Enabled: m.Enabled, CreatedAt: SafeTimestamp(m.CreatedAt), UpdatedAt: SafeTimestamp(m.UpdatedAt), }) diff --git a/internal/dns/client.go b/internal/dns/client.go index c9a719d..f7f9179 100644 --- a/internal/dns/client.go +++ b/internal/dns/client.go @@ -1,3 +1,4 @@ +// Package dns provides functionality for managing DNS records. package dns import ( diff --git a/internal/dns/technitium.go b/internal/dns/technitium.go index 8a00f7a..baecf9f 100644 --- a/internal/dns/technitium.go +++ b/internal/dns/technitium.go @@ -147,7 +147,11 @@ func (t *TechnitiumProvider) DeleteRecord(subdomain string) error { if err != nil { return err } - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() if resp.StatusCode != http.StatusOK { bodyBytes, _ := io.ReadAll(resp.Body) @@ -202,7 +206,11 @@ func (t *TechnitiumProvider) createRecord(subdomain, recordType string) error { if err != nil { return err } - defer resp.Body.Close() + defer func() { + if err = resp.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() if resp.StatusCode != http.StatusOK { bodyBytes, _ := io.ReadAll(resp.Body) @@ -224,7 +232,11 @@ func (t *TechnitiumProvider) createRecord(subdomain, recordType string) error { if err != nil { return err } - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() if resp.StatusCode != http.StatusOK { bodyBytes, _ := io.ReadAll(resp.Body) @@ -259,7 +271,11 @@ func (t *TechnitiumProvider) updateRecord(subdomain, recordType string) error { if err != nil { return err } - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() if resp.StatusCode != http.StatusOK { bodyBytes, _ := io.ReadAll(resp.Body) @@ -290,7 +306,11 @@ func (t *TechnitiumProvider) ListRecords(subdomain string) ([]DNSRecord, error) if err != nil { return nil, err } - defer resp.Body.Close() + defer func() { + if err = resp.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() var tRecords struct { Status string `json:"status"` diff --git a/internal/mail/mail.go b/internal/mail/mail.go index 357f3c2..8855688 100644 --- a/internal/mail/mail.go +++ b/internal/mail/mail.go @@ -1,3 +1,4 @@ +// Package mail provides functionality for sending emails. package mail import ( diff --git a/internal/settings/settings.go b/internal/settings/settings.go index 9c50925..3753946 100644 --- a/internal/settings/settings.go +++ b/internal/settings/settings.go @@ -1,3 +1,4 @@ +// Package settings provides functionality for managing application settings. package settings import ( diff --git a/internal/settings/settings_test.go b/internal/settings/settings_test.go new file mode 100644 index 0000000..dc97a11 --- /dev/null +++ b/internal/settings/settings_test.go @@ -0,0 +1,149 @@ +package settings + +import ( + "context" + "os" + "testing" + "time" + + "github.com/mizuchilabs/mantrae/internal/store" + "github.com/mizuchilabs/mantrae/internal/store/db" + "github.com/stretchr/testify/assert" +) + +func setupTest() (*SettingsManager, func()) { + conn := store.NewConnection(":memory:") + sm := NewManager(conn) + + return sm, func() { conn.Close() } +} + +func TestNewManager(t *testing.T) { + conn := store.NewConnection(":memory:") + defer conn.Close() + + sm := NewManager(conn) + assert.NotNil(t, sm) + assert.NotNil(t, sm.conn) + assert.NotNil(t, sm.cache) +} + +func TestGetAndSet(t *testing.T) { + sm, teardown := setupTest() + defer teardown() + + ctx := context.Background() + + // Test setting and getting a value + err := sm.Set(ctx, KeyServerURL, "http://localhost:8080") + assert.NoError(t, err) + + val, ok := sm.Get(KeyServerURL) + assert.True(t, ok) + assert.Equal(t, "http://localhost:8080", val) + + // Test setting an invalid key + err = sm.Set(ctx, "invalid_key", "some_value") + assert.Error(t, err) +} + +func TestGetAll(t *testing.T) { + sm, teardown := setupTest() + defer teardown() + + ctx := context.Background() + sm.Start(ctx) + + // Test getting all values + allSettings := sm.GetAll() + assert.NotEmpty(t, allSettings) + assert.Equal(t, "local", allSettings[KeyStorage]) +} + +func TestGetMany(t *testing.T) { + sm, teardown := setupTest() + defer teardown() + + ctx := context.Background() + sm.Start(ctx) + + // Test getting many values + keys := []string{KeyServerURL, KeyStorage} + manySettings := sm.GetMany(keys) + assert.Len(t, manySettings, 2) + assert.Equal(t, "", manySettings[KeyServerURL]) + assert.Equal(t, "local", manySettings[KeyStorage]) +} + +func TestStart(t *testing.T) { + sm, teardown := setupTest() + defer teardown() + + ctx := context.Background() + + // Set an environment variable + os.Setenv("SERVER_URL", "http://env.test") + defer os.Unsetenv("SERVER_URL") + + // Add a value to the database + err := sm.conn.GetQuery().UpsertSetting(ctx, db.UpsertSettingParams{ + Key: KeyStorage, + Value: "db_value", + }) + assert.NoError(t, err) + + sm.Start(ctx) + + // Check that the environment variable is used + val, ok := sm.Get(KeyServerURL) + assert.True(t, ok) + assert.Equal(t, "http://env.test", val) + + // Check that the database value is used + val, ok = sm.Get(KeyStorage) + assert.True(t, ok) + assert.Equal(t, "db_value", val) + + // Check that the default value is used + val, ok = sm.Get(KeyBackupEnabled) + assert.True(t, ok) + assert.Equal(t, "true", val) +} + +func TestValidation(t *testing.T) { + sm, teardown := setupTest() + defer teardown() + + ctx := context.Background() + + // Test validation for server url + err := sm.Set(ctx, KeyServerURL, " ") + assert.Error(t, err) + + // Test validation for email port + err = sm.Set(ctx, KeyEmailPort, "abc") + assert.Error(t, err) + + err = sm.Set(ctx, KeyEmailPort, "70000") + assert.Error(t, err) + + // Test validation for backup keep + err = sm.Set(ctx, KeyBackupKeep, "0") + assert.Error(t, err) +} + +func TestAsHelpers(t *testing.T) { + testString := "test" + testStringEmpty := "" + assert.Equal(t, "test", AsString(&testString)) + assert.Equal(t, "", AsString(&testStringEmpty)) + assert.True(t, AsBool("true")) + assert.False(t, AsBool("false")) + assert.False(t, AsBool("invalid")) + assert.Equal(t, 123, AsInt("123")) + assert.Equal(t, 0, AsInt("invalid")) + assert.Equal(t, 123.45, AsFloat64("123.45")) + assert.Equal(t, 0.0, AsFloat64("invalid")) + assert.Equal(t, time.Hour, AsDuration("1h")) + assert.Equal(t, time.Duration(0), AsDuration("invalid")) +} diff --git a/internal/storage/local.go b/internal/storage/local.go index 568bc29..0328443 100644 --- a/internal/storage/local.go +++ b/internal/storage/local.go @@ -1,3 +1,4 @@ +// Package storage provides a generic interface for storage backends. package storage import ( diff --git a/internal/store/connection.go b/internal/store/connection.go index f09b39a..b4e8ca6 100644 --- a/internal/store/connection.go +++ b/internal/store/connection.go @@ -1,3 +1,4 @@ +// Package store provides functionality for interacting with the database. package store import ( diff --git a/internal/store/db/http_middlewares.sql.go b/internal/store/db/http_middlewares.sql.go index 4ca9421..f529ed4 100644 --- a/internal/store/db/http_middlewares.sql.go +++ b/internal/store/db/http_middlewares.sql.go @@ -64,20 +64,11 @@ INSERT INTO agent_id, name, config, - enabled, created_at, updated_at ) VALUES - ( - ?, - ?, - ?, - ?, - ?, - CURRENT_TIMESTAMP, - CURRENT_TIMESTAMP - ) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at + (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at ` type CreateHttpMiddlewareParams struct { @@ -85,7 +76,6 @@ type CreateHttpMiddlewareParams struct { AgentID *string `json:"agentId"` Name string `json:"name"` Config *schema.Middleware `json:"config"` - Enabled bool `json:"enabled"` } func (q *Queries) CreateHttpMiddleware(ctx context.Context, arg CreateHttpMiddlewareParams) (HttpMiddleware, error) { @@ -94,7 +84,6 @@ func (q *Queries) CreateHttpMiddleware(ctx context.Context, arg CreateHttpMiddle arg.AgentID, arg.Name, arg.Config, - arg.Enabled, ) var i HttpMiddleware err := row.Scan( diff --git a/internal/store/db/tcp_middlewares.sql.go b/internal/store/db/tcp_middlewares.sql.go index c875820..ac7efeb 100644 --- a/internal/store/db/tcp_middlewares.sql.go +++ b/internal/store/db/tcp_middlewares.sql.go @@ -64,20 +64,11 @@ INSERT INTO agent_id, name, config, - enabled, created_at, updated_at ) VALUES - ( - ?, - ?, - ?, - ?, - ?, - CURRENT_TIMESTAMP, - CURRENT_TIMESTAMP - ) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at + (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at ` type CreateTcpMiddlewareParams struct { @@ -85,7 +76,6 @@ type CreateTcpMiddlewareParams struct { AgentID *string `json:"agentId"` Name string `json:"name"` Config *schema.TCPMiddleware `json:"config"` - Enabled bool `json:"enabled"` } func (q *Queries) CreateTcpMiddleware(ctx context.Context, arg CreateTcpMiddlewareParams) (TcpMiddleware, error) { @@ -94,7 +84,6 @@ func (q *Queries) CreateTcpMiddleware(ctx context.Context, arg CreateTcpMiddlewa arg.AgentID, arg.Name, arg.Config, - arg.Enabled, ) var i TcpMiddleware err := row.Scan( diff --git a/internal/store/queries/http_middlewares.sql b/internal/store/queries/http_middlewares.sql index 5348bb8..d56a717 100644 --- a/internal/store/queries/http_middlewares.sql +++ b/internal/store/queries/http_middlewares.sql @@ -5,20 +5,11 @@ INSERT INTO agent_id, name, config, - enabled, created_at, updated_at ) VALUES - ( - ?, - ?, - ?, - ?, - ?, - CURRENT_TIMESTAMP, - CURRENT_TIMESTAMP - ) RETURNING *; + (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING *; -- name: GetHttpMiddleware :one SELECT diff --git a/internal/store/queries/tcp_middlewares.sql b/internal/store/queries/tcp_middlewares.sql index 2b5dbd2..7248b65 100644 --- a/internal/store/queries/tcp_middlewares.sql +++ b/internal/store/queries/tcp_middlewares.sql @@ -5,20 +5,11 @@ INSERT INTO agent_id, name, config, - enabled, created_at, updated_at ) VALUES - ( - ?, - ?, - ?, - ?, - ?, - CURRENT_TIMESTAMP, - CURRENT_TIMESTAMP - ) RETURNING *; + (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING *; -- name: GetTcpMiddleware :one SELECT diff --git a/internal/store/squash.go b/internal/store/squash.go index 80ed111..7afe5a8 100644 --- a/internal/store/squash.go +++ b/internal/store/squash.go @@ -11,7 +11,11 @@ func Squash() { conn.Migrate() db := conn.db - defer db.Close() + defer func() { + if err := db.Close(); err != nil { + slog.Error("failed to close database", "error", err) + } + }() var currentVersion int64 err := db.QueryRow("SELECT version_id FROM goose_db_version ORDER BY id DESC LIMIT 1"). @@ -31,7 +35,11 @@ func Squash() { if err != nil { panic(err) } - defer rows.Close() + defer func() { + if err = rows.Close(); err != nil { + slog.Error("failed to close rows", "error", err) + } + }() // Create new base migration baseFile := "-- +goose Up\n" diff --git a/internal/traefik/client.go b/internal/traefik/client.go index 9bdad49..e19b8e0 100644 --- a/internal/traefik/client.go +++ b/internal/traefik/client.go @@ -1,3 +1,4 @@ +// Package traefik provides functionality for interacting with the Traefik API. package traefik import ( @@ -7,6 +8,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net/http" "time" @@ -32,7 +34,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error { if err != nil { return fmt.Errorf("failed to fetch %s: %w", instance.Url+RawAPI, err) } - defer rawResp.Close() + defer func() { + if err = rawResp.Close(); err != nil { + slog.Error("failed to close raw response", "error", err) + } + }() var config schema.Configuration if err = json.NewDecoder(rawResp).Decode(&config); err != nil { @@ -43,7 +49,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error { if err != nil { return fmt.Errorf("failed to fetch %s: %w", instance.Url+EntrypointsAPI, err) } - defer entrypointsResp.Close() + defer func() { + if err = entrypointsResp.Close(); err != nil { + slog.Error("failed to close entrypoints response", "error", err) + } + }() var entrypoints schema.EntryPoints if err = json.NewDecoder(entrypointsResp).Decode(&entrypoints); err != nil { @@ -54,7 +64,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error { if err != nil { return fmt.Errorf("failed to fetch %s: %w", instance.Url+OverviewAPI, err) } - defer overviewResp.Close() + defer func() { + if err = overviewResp.Close(); err != nil { + slog.Error("failed to close overview response", "error", err) + } + }() var overview schema.Overview if err = json.NewDecoder(overviewResp).Decode(&overview); err != nil { @@ -65,7 +79,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error { if err != nil { return fmt.Errorf("failed to fetch %s: %w", instance.Url+VersionAPI, err) } - defer versionResp.Close() + defer func() { + if err = versionResp.Close(); err != nil { + slog.Error("failed to close version response", "error", err) + } + }() var version schema.Version if err := json.NewDecoder(versionResp).Decode(&version); err != nil { diff --git a/pkg/build/build.go b/pkg/build/build.go index ed3bbfe..3b04587 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -1,3 +1,4 @@ +// Package build provides build information. package build var ( diff --git a/pkg/build/update.go b/pkg/build/update.go index 909ef50..e0b43f1 100644 --- a/pkg/build/update.go +++ b/pkg/build/update.go @@ -107,7 +107,11 @@ func fetchLatestRelease() (*release, error) { if err != nil { return nil, err } - defer res.Body.Close() + defer func() { + if err = res.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("(%d) failed to send latest release request", res.StatusCode) @@ -139,7 +143,11 @@ func downloadFile(url string, dest string) error { if err != nil { return err } - defer res.Body.Close() + defer func() { + if err = res.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() if res.StatusCode != http.StatusOK { return fmt.Errorf("(%d) failed to send download file request", res.StatusCode) @@ -149,7 +157,11 @@ func downloadFile(url string, dest string) error { if err != nil { return err } - defer out.Close() + defer func() { + if err = out.Close(); err != nil { + slog.Error("failed to close output file", "error", err) + } + }() if _, err := io.Copy(out, res.Body); err != nil { return err @@ -207,12 +219,9 @@ func compareVersions(a, b string) int { bSplit := strings.Split(b, ".") bTotal := len(bSplit) - limit := aTotal - if bTotal > aTotal { - limit = bTotal - } + limit := max(aTotal, bTotal) - for i := 0; i < limit; i++ { + for i := range limit { var x, y int if i < aTotal { diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 00bb898..86d96a0 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -1,3 +1,4 @@ +// Package logger provides logging setup and configuration for the application. package logger import ( diff --git a/pkg/meta/claims.go b/pkg/meta/claims.go index cdd6db3..b15fa31 100644 --- a/pkg/meta/claims.go +++ b/pkg/meta/claims.go @@ -1,3 +1,4 @@ +// Package meta provides functionality for handling JWT claims. package meta import ( diff --git a/pkg/util/ip.go b/pkg/util/ip.go index c985903..7cc2700 100644 --- a/pkg/util/ip.go +++ b/pkg/util/ip.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "log/slog" "net" "net/http" "strings" @@ -123,7 +124,11 @@ func getIP(services []string, validationFunc func(string) bool) (string, error) if err != nil { continue } - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + slog.Error("failed to close response body", "error", err) + } + }() if resp.StatusCode != http.StatusOK { continue diff --git a/pkg/util/tools.go b/pkg/util/tools.go index 8333ab2..49931dc 100644 --- a/pkg/util/tools.go +++ b/pkg/util/tools.go @@ -1,3 +1,4 @@ +// Package util provides utility functions. package util import ( diff --git a/proto/gen/mantrae/v1/middleware.pb.go b/proto/gen/mantrae/v1/middleware.pb.go index b37811c..3409d53 100644 --- a/proto/gen/mantrae/v1/middleware.pb.go +++ b/proto/gen/mantrae/v1/middleware.pb.go @@ -80,9 +80,10 @@ type Middleware struct { AgentId string `protobuf:"bytes,3,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` Config *structpb.Struct `protobuf:"bytes,5,opt,name=config,proto3" json:"config,omitempty"` - Type MiddlewareType `protobuf:"varint,6,opt,name=type,proto3,enum=mantrae.v1.MiddlewareType" json:"type,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + Enabled bool `protobuf:"varint,6,opt,name=enabled,proto3" json:"enabled,omitempty"` + Type MiddlewareType `protobuf:"varint,7,opt,name=type,proto3,enum=mantrae.v1.MiddlewareType" json:"type,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -152,6 +153,13 @@ func (x *Middleware) GetConfig() *structpb.Struct { return nil } +func (x *Middleware) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + func (x *Middleware) GetType() MiddlewareType { if x != nil { return x.Type @@ -1032,7 +1040,7 @@ var file_mantrae_v1_middleware_proto_rawDesc = string([]byte{ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc1, 0x02, 0x0a, 0x0a, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdb, 0x02, 0x0a, 0x0a, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, @@ -1042,202 +1050,204 @@ var file_mantrae_v1_middleware_proto_rawDesc = string([]byte{ 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, - 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, - 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xac, 0x03, 0x0a, 0x06, 0x50, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72, - 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, - 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, - 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, - 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x75, - 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, - 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6c, - 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x72, 0x73, 0x12, 0x33, 0x0a, 0x07, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, - 0x52, 0x07, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x49, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x38, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x38, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x79, - 0x61, 0x6d, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x6f, 0x6d, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x6f, 0x6d, 0x6c, 0x22, 0x6f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, - 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, - 0x02, 0x20, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x4f, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, - 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, - 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, - 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, - 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0xed, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, - 0x00, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, - 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x52, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, - 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, - 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, 0x17, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, + 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2e, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, + 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, + 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x22, 0xac, 0x03, 0x0a, 0x06, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1d, + 0x0a, 0x0a, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, + 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x73, 0x12, 0x33, + 0x0a, 0x07, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x52, 0x07, 0x73, 0x6e, 0x69, 0x70, + 0x70, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x22, 0x49, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70, + 0x70, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x38, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x38, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x6f, 0x6d, + 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x6f, 0x6d, 0x6c, 0x22, 0x6f, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, + 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, + 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4f, + 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, + 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, + 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, + 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, + 0xed, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, + 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, + 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2f, - 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x52, 0x0a, 0x18, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, - 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, - 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, - 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0x72, 0x0a, - 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, - 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, - 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xef, 0x02, - 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, - 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, - 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, - 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, - 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xba, 0x48, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, - 0x48, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x71, 0x0a, 0x05, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x56, 0xba, 0x48, 0x53, 0xba, - 0x01, 0x50, 0x0a, 0x0b, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, - 0x29, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, - 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x2d, 0x31, 0x20, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x30, 0x1a, 0x16, 0x74, 0x68, 0x69, 0x73, - 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, - 0x20, 0x30, 0x48, 0x02, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x24, - 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, - 0xba, 0x48, 0x04, 0x22, 0x02, 0x28, 0x00, 0x48, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, - 0x64, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, - 0x74, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x6d, 0x69, - 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, + 0x52, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, + 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d, + 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, - 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0b, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, - 0x61, 0x72, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x1d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, - 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x4c, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, - 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x73, 0x2a, 0x64, 0x0a, 0x0e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41, - 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, - 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x12, - 0x17, 0x0a, 0x13, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x54, 0x43, 0x50, 0x10, 0x02, 0x32, 0xdc, 0x04, 0x0a, 0x11, 0x4d, 0x69, 0x64, - 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, - 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, - 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x5d, 0x0a, 0x10, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, - 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, + 0x61, 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, + 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, + 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, + 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, + 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x22, 0x52, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, + 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, + 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0x72, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, - 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, - 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, - 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, - 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x74, - 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, - 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, - 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, - 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x6e, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4d, 0x69, - 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, - 0x27, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, - 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, - 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x42, 0xa9, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, - 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0f, 0x4d, 0x69, 0x64, 0x64, - 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x7a, 0x75, 0x63, 0x68, - 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f, - 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d, - 0x58, 0x58, 0xaa, 0x02, 0x0a, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x56, 0x31, 0xca, - 0x02, 0x0a, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x16, 0x4d, - 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0b, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, + 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, + 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, + 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, + 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xef, 0x02, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, + 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, + 0x20, 0x00, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, + 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x42, 0x08, 0xba, 0x48, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x48, 0x01, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x71, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x42, 0x56, 0xba, 0x48, 0x53, 0xba, 0x01, 0x50, 0x0a, 0x0b, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x29, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x2d, 0x31, 0x20, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x6e, 0x20, 0x30, 0x1a, 0x16, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, + 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x48, 0x02, 0x52, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xba, 0x48, 0x04, 0x22, 0x02, 0x28, + 0x00, 0x48, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0b, + 0x0a, 0x09, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x74, 0x0a, 0x17, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, + 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, + 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, + 0x65, 0x52, 0x0b, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x12, 0x1f, + 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, + 0x1d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4c, + 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, + 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x2a, 0x64, 0x0a, 0x0e, + 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, + 0x0a, 0x1b, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x18, 0x0a, 0x14, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x49, 0x44, + 0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x43, 0x50, + 0x10, 0x02, 0x32, 0xdc, 0x04, 0x0a, 0x11, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4d, + 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x74, + 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, + 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, + 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, + 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, + 0x90, 0x02, 0x01, 0x12, 0x5d, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, + 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, + 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, + 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, + 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, + 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, + 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, + 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, + 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, + 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, + 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, + 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5f, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, + 0x72, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, + 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, + 0x01, 0x12, 0x6e, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, + 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x27, 0x2e, 0x6d, 0x61, 0x6e, 0x74, + 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, + 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, + 0x01, 0x42, 0xa9, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, + 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0f, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x7a, 0x75, 0x63, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2f, + 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, + 0x6e, 0x2f, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x6e, + 0x74, 0x72, 0x61, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d, 0x58, 0x58, 0xaa, 0x02, 0x0a, 0x4d, + 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0a, 0x4d, 0x61, 0x6e, 0x74, + 0x72, 0x61, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x16, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, + 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x0b, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( diff --git a/proto/gen/openapi/openapi.yaml b/proto/gen/openapi/openapi.yaml index 15afb4f..3d16f5a 100644 --- a/proto/gen/openapi/openapi.yaml +++ b/proto/gen/openapi/openapi.yaml @@ -1219,6 +1219,9 @@ components: config: title: config $ref: '#/components/schemas/google.protobuf.Struct' + enabled: + type: boolean + title: enabled type: title: type $ref: '#/components/schemas/mantrae.v1.MiddlewareType' diff --git a/proto/mantrae/v1/middleware.proto b/proto/mantrae/v1/middleware.proto index cf82580..4f5803d 100644 --- a/proto/mantrae/v1/middleware.proto +++ b/proto/mantrae/v1/middleware.proto @@ -33,9 +33,10 @@ message Middleware { string agent_id = 3; string name = 4; google.protobuf.Struct config = 5; - MiddlewareType type = 6; - google.protobuf.Timestamp created_at = 7; - google.protobuf.Timestamp updated_at = 8; + bool enabled = 6; + MiddlewareType type = 7; + google.protobuf.Timestamp created_at = 8; + google.protobuf.Timestamp updated_at = 9; } message Plugin { diff --git a/tygo.yaml b/tygo.yaml deleted file mode 100644 index d599726..0000000 --- a/tygo.yaml +++ /dev/null @@ -1,11 +0,0 @@ -packages: - - path: "github.com/traefik/traefik/v3/pkg/config/dynamic" - output_path: "web/src/lib/gen/tygo/dynamic" - type_mappings: - ptypes.Duration: string - - - path: "github.com/traefik/traefik/v3/pkg/tls" - output_path: "web/src/lib/gen/tygo/tls" - - - path: "github.com/traefik/traefik/v3/pkg/types" - output_path: "web/src/lib/gen/tygo/types" diff --git a/web/src/app.html b/web/src/app.html index 8319e67..1b8a340 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -2,12 +2,12 @@ - - - - - - + + + + + + %sveltekit.head% diff --git a/web/src/lib/components/forms/DynamicForm.svelte b/web/src/lib/components/forms/DynamicForm.svelte index 5fbc049..97e4e79 100644 --- a/web/src/lib/components/forms/DynamicForm.svelte +++ b/web/src/lib/components/forms/DynamicForm.svelte @@ -1,69 +1,244 @@ -
-
- {#each fields as field (field.key)} - - {/each} -
+
+ {#each Object.entries(fields) as [key, field] (key)} +
+ - - - + {#if field.type === 'string'} + updateField(key, data[key])} + /> + {:else if field.type === 'number'} + updateField(key, data[key])} + /> + {:else if field.type === 'boolean'} + updateField(key, checked)} + /> + {:else if field.type === 'plugin'} +
+