diff --git a/Dockerfile.auth b/Dockerfile.auth index 95175b1..6093f68 100644 --- a/Dockerfile.auth +++ b/Dockerfile.auth @@ -6,6 +6,7 @@ WORKDIR /app COPY go.work go.work.sum ./ COPY auth/go.mod auth/go.sum ./auth/ +COPY profiles/go.mod profiles/go.sum ./profiles/ COPY gateway/go.mod gateway/go.sum ./gateway/ COPY shared/go.mod shared/go.sum ./shared/ COPY protos/go.mod protos/go.sum ./protos/ diff --git a/Dockerfile.gateway b/Dockerfile.gateway index b7bada2..454b5da 100644 --- a/Dockerfile.gateway +++ b/Dockerfile.gateway @@ -6,6 +6,7 @@ WORKDIR /app COPY go.work go.work.sum ./ COPY auth/go.mod auth/go.sum ./auth/ +COPY profiles/go.mod profiles/go.sum ./profiles/ COPY gateway/go.mod gateway/go.sum ./gateway/ COPY shared/go.mod shared/go.sum ./shared/ COPY protos/go.mod protos/go.sum ./protos/ diff --git a/Dockerfile.profiles b/Dockerfile.profiles new file mode 100644 index 0000000..6eb5bdc --- /dev/null +++ b/Dockerfile.profiles @@ -0,0 +1,33 @@ +FROM golang:1.25.0-alpine AS builder + +RUN apk add --no-cache git + +WORKDIR /app + +COPY go.work go.work.sum ./ +COPY auth/go.mod auth/go.sum ./auth/ +COPY profiles/go.mod profiles/go.sum ./profiles/ +COPY gateway/go.mod gateway/go.sum ./gateway/ +COPY shared/go.mod shared/go.sum ./shared/ +COPY protos/go.mod protos/go.sum ./protos/ + +RUN go work sync && go mod download + +COPY profiles/ ./profiles/ +COPY shared/ ./shared/ +COPY protos/ ./protos/ + +RUN go build -o ./profiles/profiles ./profiles/cmd/profiles/main.go + +FROM alpine:3.22.1 + +RUN apk add --no-cache ca-certificates + +WORKDIR /app + +COPY --from=builder /app/profiles/profiles . +COPY --from=builder /app/profiles/migrations ./migrations + +EXPOSE 50051 + +CMD ["./profiles"] diff --git a/Taskfile.yaml b/Taskfile.yaml index e23ab98..115c8d9 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -34,6 +34,13 @@ tasks: - | echo "Build Auth Image..." docker build -f Dockerfile.auth -t got-auth:latest . + build_profiles: + dir: "{{.TASKFILE_DIR}}" + desc: Build Profiles image + cmds: + - | + echo "Build Profiles Image..." + docker build -f Dockerfile.profiles -t got-profiles:latest . build_gateway: dir: "{{.TASKFILE_DIR}}" desc: Build Gateway image diff --git a/auth/cmd/auth/main.go b/auth/cmd/auth/main.go index 7e679b5..bb847f8 100644 --- a/auth/cmd/auth/main.go +++ b/auth/cmd/auth/main.go @@ -10,7 +10,7 @@ import ( "github.com/alexwatcher/gateofthings/auth/internal/app" "github.com/alexwatcher/gateofthings/auth/internal/config" "github.com/alexwatcher/gateofthings/auth/internal/consts" - "github.com/alexwatcher/gateofthings/auth/internal/migrator/postgresql" + sharedpgsql "github.com/alexwatcher/gateofthings/shared/pkg/migrator/postgresql" "github.com/alexwatcher/gateofthings/shared/pkg/telemetry" ) @@ -24,7 +24,7 @@ func main() { telemetry.MustInitMeter(context.Background(), res, cfg.Telemetry.MetricsEndpoint) slog.Info("start migration") - postgresql.Migrate(cfg.Database) + sharedpgsql.Migrate(cfg.Database) slog.Info("end migration") slog.Info("starting application") diff --git a/auth/internal/app/app.go b/auth/internal/app/app.go index 38229a2..04704ae 100644 --- a/auth/internal/app/app.go +++ b/auth/internal/app/app.go @@ -8,11 +8,12 @@ import ( "time" grpcauth "github.com/alexwatcher/gateofthings/auth/internal/grpc/auth" - "github.com/alexwatcher/gateofthings/auth/internal/grpc/interceptors/tracing" - "github.com/alexwatcher/gateofthings/auth/internal/grpc/interceptors/valid" "github.com/alexwatcher/gateofthings/auth/internal/repository/postgresql" "github.com/alexwatcher/gateofthings/auth/internal/services" "github.com/alexwatcher/gateofthings/shared/pkg/config" + "github.com/alexwatcher/gateofthings/shared/pkg/grpc/interceptors/tracing" + "github.com/alexwatcher/gateofthings/shared/pkg/grpc/interceptors/valid" + sharedpgsql "github.com/alexwatcher/gateofthings/shared/pkg/repository/postgresql" "google.golang.org/grpc" ) @@ -26,7 +27,7 @@ type App struct { // service with the server and returns the configured App instance. func New(ctx context.Context, gRPConfig config.GRPCSrvConfig, dbConfig config.DatabaseConfig, secret string, tokenTTL time.Duration) *App { - dbConn, err := postgresql.NewConnection(ctx, dbConfig) + dbConn, err := sharedpgsql.NewConnection(ctx, dbConfig) if err != nil { slog.Error("failed to connect to database", "error", err) panic(err) diff --git a/auth/internal/grpc/interceptors/valid/auth.go b/auth/internal/grpc/auth/auth.go similarity index 72% rename from auth/internal/grpc/interceptors/valid/auth.go rename to auth/internal/grpc/auth/auth.go index 366d3f0..52394f8 100644 --- a/auth/internal/grpc/interceptors/valid/auth.go +++ b/auth/internal/grpc/auth/auth.go @@ -1,25 +1,27 @@ -package valid +package auth import ( authv1 "github.com/alexwatcher/gateofthings/protos/gen/go/auth/v1" + sharedvalid "github.com/alexwatcher/gateofthings/shared/pkg/grpc/interceptors/valid" validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/go-ozzo/ozzo-validation/v4/is" ) func init() { - rulesMap[getStructId(&authv1.SignUpRequest{})] = func(s any) error { + + sharedvalid.RegisterRule(&authv1.SignUpRequest{}, func(s any) error { rr := s.(*authv1.SignUpRequest) return validation.ValidateStruct(rr, validation.Field(&rr.Email, validation.Required, is.EmailFormat), validation.Field(&rr.Password, validation.Required, validation.Length(6, 128)), ) - } + }) - rulesMap[getStructId(&authv1.SignInRequest{})] = func(s any) error { + sharedvalid.RegisterRule(&authv1.SignInRequest{}, func(s any) error { lr := s.(*authv1.SignInRequest) return validation.ValidateStruct(lr, validation.Field(&lr.Email, validation.Required, is.EmailFormat), validation.Field(&lr.Password, validation.Required, validation.Length(6, 128)), ) - } + }) } diff --git a/auth/internal/repository/postgresql/constants.go b/auth/internal/repository/postgresql/constants.go deleted file mode 100644 index 6dddb28..0000000 --- a/auth/internal/repository/postgresql/constants.go +++ /dev/null @@ -1,7 +0,0 @@ -package postgresql - -const ( - errCodeUniqueViolation = "23505" - errCodeForeignKey = "23503" - errCodeNotNull = "23502" -) diff --git a/auth/internal/repository/postgresql/users.go b/auth/internal/repository/postgresql/users.go index 42a6665..c3d2460 100644 --- a/auth/internal/repository/postgresql/users.go +++ b/auth/internal/repository/postgresql/users.go @@ -8,6 +8,7 @@ import ( "github.com/Masterminds/squirrel" "github.com/alexwatcher/gateofthings/auth/internal/models" "github.com/alexwatcher/gateofthings/auth/internal/repository" + spgsql "github.com/alexwatcher/gateofthings/shared/pkg/repository/postgresql" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" @@ -26,7 +27,7 @@ func (r *UsersRepo) Insert(ctx context.Context, email string, passhash []byte) ( id := uuid.New() - sql, args, err := sqlBuilder. + sql, args, err := spgsql.SqlBuilder. Insert("auth_users"). Columns("id", "email", "password_hash"). Values(id, email, passhash). @@ -38,7 +39,7 @@ func (r *UsersRepo) Insert(ctx context.Context, email string, passhash []byte) ( _, err = r.conn.Exec(ctx, sql, args...) if err != nil { var pgErr *pgconn.PgError - if errors.As(err, &pgErr) && pgErr.Code == errCodeUniqueViolation { + if errors.As(err, &pgErr) && pgErr.Code == spgsql.ErrCodeUniqueViolation { return "", fmt.Errorf("%s: %w", op, repository.ErrUserAlreadyExists) } return "", fmt.Errorf("%s: %w", op, err) @@ -48,10 +49,10 @@ func (r *UsersRepo) Insert(ctx context.Context, email string, passhash []byte) ( } func (r *UsersRepo) Get(ctx context.Context, email string) (models.User, error) { - op := "repository.users.Select" + op := "repository.users.Get" var user models.User - query, args, err := sqlBuilder. + query, args, err := spgsql.SqlBuilder. Select("id", "email", "password_hash"). From("auth_users"). Where(squirrel.Eq{"email": email}). diff --git a/auth/migrations/001_init.sql b/auth/migrations/001_init.sql index 5604902..a3bff57 100644 --- a/auth/migrations/001_init.sql +++ b/auth/migrations/001_init.sql @@ -8,16 +8,6 @@ CREATE TABLE IF NOT EXISTS auth_users ( ); CREATE INDEX idx_auth_users_email ON auth_users (email); -CREATE TABLE IF NOT EXISTS user_profiles ( - id UUID PRIMARY KEY REFERENCES auth_users(id) ON DELETE CASCADE, - full_name TEXT, - permissions JSONB, - settings JSONB, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); - -- +goose Down DROP INDEX IF EXISTS idx_auth_users_email; DROP TABLE IF EXISTS auth_users; -DROP TABLE IF EXISTS user_profiles; diff --git a/docker-compose.yaml b/docker-compose.yaml index 55ab704..5030f5a 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -141,6 +141,8 @@ services: METRICS_PASS: metrics_pass AUTH_USER: auth_user AUTH_PASS: auth_pass + PROFILES_USER: profiles_user + PROFILES_PASS: profiles_pass depends_on: postgres: condition: service_healthy diff --git a/frontend/utils/fetchWithCsrf.ts b/frontend/utils/postWithCsrf.ts similarity index 100% rename from frontend/utils/fetchWithCsrf.ts rename to frontend/utils/postWithCsrf.ts diff --git a/gateway/go.mod b/gateway/go.mod index a087761..73cc08b 100644 --- a/gateway/go.mod +++ b/gateway/go.mod @@ -27,6 +27,7 @@ require ( github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/spec v0.20.6 // indirect github.com/go-openapi/swag v0.19.15 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect diff --git a/gateway/go.sum b/gateway/go.sum index 6b1be83..c35d1e0 100644 --- a/gateway/go.sum +++ b/gateway/go.sum @@ -25,6 +25,8 @@ github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= diff --git a/gateway/internal/app/app.go b/gateway/internal/app/app.go index 11d5eba..e97cc42 100644 --- a/gateway/internal/app/app.go +++ b/gateway/internal/app/app.go @@ -6,8 +6,8 @@ import ( "log/slog" "net/http" - "github.com/alexwatcher/gateofthings/gateway/internal/interceptors" - "github.com/alexwatcher/gateofthings/gateway/internal/middlewares" + "github.com/alexwatcher/gateofthings/gateway/internal/grpc/interceptors" + "github.com/alexwatcher/gateofthings/gateway/internal/http/middlewares" "github.com/alexwatcher/gateofthings/gateway/internal/openapi" authv1 "github.com/alexwatcher/gateofthings/protos/gen/go/auth/v1" "github.com/alexwatcher/gateofthings/shared/pkg/config" @@ -42,15 +42,16 @@ func (a *App) MustRun(ctx context.Context) { // server can't be started, it returns an error. func (a *App) Run(ctx context.Context) error { mux := runtime.NewServeMux( - runtime.WithForwardResponseOption(interceptors.MakeSetSignInCookie()), + runtime.WithForwardResponseOption(interceptors.SetSignInCookies), runtime.WithMiddlewares( middlewares.TracingMiddleware, middlewares.MakeCSRFMiddleware([]string{"/v1/auth/signin", "/v1/auth/signup"}), + middlewares.MakeAuthTokenMiddleware([]string{"/v1/auth/signin", "/v1/auth/signup"}), ), ) opts := []grpc.DialOption{ - grpc.WithChainUnaryInterceptor(interceptors.MakeTracingClientInterceptor()), + grpc.WithChainUnaryInterceptor(interceptors.TracingClientInterceptor), grpc.WithTransportCredentials(insecure.NewCredentials()), } err := authv1.RegisterAuthHandlerFromEndpoint(ctx, mux, a.authConfig.Address, opts) diff --git a/gateway/internal/interceptors/login.go b/gateway/internal/grpc/interceptors/login.go similarity index 99% rename from gateway/internal/interceptors/login.go rename to gateway/internal/grpc/interceptors/login.go index 6c391f4..7c0fc0c 100644 --- a/gateway/internal/interceptors/login.go +++ b/gateway/internal/grpc/interceptors/login.go @@ -12,7 +12,6 @@ import ( func MakeSetSignInCookie() func(ctx context.Context, w http.ResponseWriter, resp proto.Message) error { return func(ctx context.Context, w http.ResponseWriter, resp proto.Message) error { if r, ok := resp.(*authv1.SignInResponse); ok { - http.SetCookie(w, &http.Cookie{ Name: "token", Value: r.Token, diff --git a/gateway/internal/grpc/interceptors/signincookies.go b/gateway/internal/grpc/interceptors/signincookies.go new file mode 100644 index 0000000..46e056c --- /dev/null +++ b/gateway/internal/grpc/interceptors/signincookies.go @@ -0,0 +1,33 @@ +package interceptors + +import ( + "context" + "net/http" + + authv1 "github.com/alexwatcher/gateofthings/protos/gen/go/auth/v1" + "github.com/google/uuid" + "google.golang.org/protobuf/proto" +) + +func SetSignInCookies(ctx context.Context, w http.ResponseWriter, resp proto.Message) error { + if r, ok := resp.(*authv1.SignInResponse); ok { + http.SetCookie(w, &http.Cookie{ + Name: "token", + Value: r.Token, + Path: "/", + HttpOnly: true, + Secure: true, + }) + + csrfToken := uuid.NewString() + w.Header().Set("X-CSRF-Token", csrfToken) + http.SetCookie(w, &http.Cookie{ + Name: "csrf_token", + Value: csrfToken, + Path: "/", + HttpOnly: false, + Secure: true, + }) + } + return nil +} diff --git a/gateway/internal/grpc/interceptors/tracing.go b/gateway/internal/grpc/interceptors/tracing.go new file mode 100644 index 0000000..0cf92ae --- /dev/null +++ b/gateway/internal/grpc/interceptors/tracing.go @@ -0,0 +1,22 @@ +package interceptors + +import ( + "context" + + "github.com/alexwatcher/gateofthings/shared/pkg/telemetry/propagation" + "go.opentelemetry.io/otel" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +func TracingClientInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + md, ok := metadata.FromOutgoingContext(ctx) + if ok { + md = md.Copy() + } else { + md = metadata.New(nil) + } + otel.GetTextMapPropagator().Inject(ctx, propagation.GRPCMetadataCarrier(md)) + ctx = metadata.NewOutgoingContext(ctx, md) + return invoker(ctx, method, req, reply, cc, opts...) +} diff --git a/gateway/internal/http/middlewares/auth.go b/gateway/internal/http/middlewares/auth.go new file mode 100644 index 0000000..fbf0b53 --- /dev/null +++ b/gateway/internal/http/middlewares/auth.go @@ -0,0 +1,51 @@ +package middlewares + +import ( + "net/http" + + "github.com/golang-jwt/jwt/v5" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" +) + +func MakeAuthTokenMiddleware(ignorePaths []string) func(next runtime.HandlerFunc) runtime.HandlerFunc { + return func(next runtime.HandlerFunc) runtime.HandlerFunc { + ignorePathMap := make(map[string]struct{}, len(ignorePaths)) + for _, path := range ignorePaths { + ignorePathMap[path] = struct{}{} + } + + return func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) { + if _, ok := ignorePathMap[r.URL.Path]; !ok { + userId := "" + cookies := r.CookiesNamed("token") + if len(cookies) > 0 && len(cookies[0].Value) > 0 { + token := cookies[0].Value + + jwtToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { + return nil, nil + }) + + if err != nil || !jwtToken.Valid { + // remove token + http.SetCookie(w, &http.Cookie{ + Name: "token", + MaxAge: 0, + }) + http.Error(w, "invalid token", http.StatusForbidden) + return + } + + claims, ok := jwtToken.Claims.(jwt.MapClaims) + if ok { + uid, ok := claims["uid"].(string) + if ok { + userId = uid + } + } + } + r.Header.Set("X-User-ID", userId) + } + next(w, r, pathParams) + } + } +} diff --git a/gateway/internal/middlewares/csrf.go b/gateway/internal/http/middlewares/csrf.go similarity index 100% rename from gateway/internal/middlewares/csrf.go rename to gateway/internal/http/middlewares/csrf.go diff --git a/gateway/internal/middlewares/tracing.go b/gateway/internal/http/middlewares/tracing.go similarity index 100% rename from gateway/internal/middlewares/tracing.go rename to gateway/internal/http/middlewares/tracing.go diff --git a/gateway/internal/interceptors/tracing.go b/gateway/internal/interceptors/tracing.go deleted file mode 100644 index ed695fd..0000000 --- a/gateway/internal/interceptors/tracing.go +++ /dev/null @@ -1,24 +0,0 @@ -package interceptors - -import ( - "context" - - "github.com/alexwatcher/gateofthings/shared/pkg/telemetry/propagation" - "go.opentelemetry.io/otel" - "google.golang.org/grpc" - "google.golang.org/grpc/metadata" -) - -func MakeTracingClientInterceptor() grpc.UnaryClientInterceptor { - return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - md, ok := metadata.FromOutgoingContext(ctx) - if ok { - md = md.Copy() - } else { - md = metadata.New(nil) - } - otel.GetTextMapPropagator().Inject(ctx, propagation.GRPCMetadataCarrier(md)) - ctx = metadata.NewOutgoingContext(ctx, md) - return invoker(ctx, method, req, reply, cc, opts...) - } -} diff --git a/go.work b/go.work index 4a0f9d8..97db8b5 100644 --- a/go.work +++ b/go.work @@ -3,6 +3,7 @@ go 1.25.0 use ( ./auth ./gateway + ./profiles ./protos ./shared ) diff --git a/go.work.sum b/go.work.sum index 72e032d..f6796ea 100644 --- a/go.work.sum +++ b/go.work.sum @@ -2,58 +2,110 @@ cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss= cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +codeberg.org/go-fonts/liberation v0.5.0/go.mod h1:zS/2e1354/mJ4pGzIIaEtm/59VFCFnYC7YV6YdGl5GU= +codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9Dny04MHMw= +codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= +git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1/go.mod h1:xxCBG/f/4Vbmh2XQJBsOmNdxWUY5j/s27jujKPbQf14= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ClickHouse/ch-go v0.65.1 h1:SLuxmLl5Mjj44/XbINsK2HFvzqup0s6rwKLFH347ZhU= github.com/ClickHouse/ch-go v0.65.1/go.mod h1:bsodgURwmrkvkBe5jw1qnGDgyITsYErfONKAHn05nv4= +github.com/ClickHouse/ch-go v0.67.0/go.mod h1:2MSAeyVmgt+9a2k2SQPPG1b4qbTPzdGDpf1+bcHh+18= github.com/ClickHouse/clickhouse-go/v2 v2.34.0 h1:Y4rqkdrRHgExvC4o/NTbLdY5LFQ3LHS77/RNFxFX3Co= github.com/ClickHouse/clickhouse-go/v2 v2.34.0/go.mod h1:yioSINoRLVZkLyDzdMXPLRIqhDvel8iLBlwh6Iefso8= +github.com/ClickHouse/clickhouse-go/v2 v2.40.1/go.mod h1:GDzSBLVhladVm8V01aEB36IoBOVLLICfyeuiIp/8Ezc= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v6 v6.3.0 h1:mIdrSO2cPNWQY1truPg6uHLXyKHk3Z5Odx4wjKOASzA= github.com/checkpoint-restore/go-criu/v6 v6.3.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI= github.com/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg= github.com/cilium/ebpf v0.17.3/go.mod h1:G5EDHij8yiLzaqn0WjyfJHvRa+3aDlReIaLVRMvOyJk= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dmarkham/enumer v1.5.11/go.mod h1:yixql+kDDQRYqcuBM2n9Vlt7NoT9ixgXhaXry8vmRg8= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/elastic/go-sysinfo v1.8.1/go.mod h1:JfllUnzoQV/JRYymbH3dO1yggI3mV2oTKSXsDHM+uIM= github.com/elastic/go-sysinfo v1.15.3 h1:W+RnmhKFkqPTCRoFq2VCTmsT4p/fwpo+3gKNQsn1XU0= github.com/elastic/go-sysinfo v1.15.3/go.mod h1:K/cNrqYTDrSoMh2oDkYEMS2+a72GRxMvNP+GC+vRIlo= +github.com/elastic/go-sysinfo v1.15.4/go.mod h1:ZBVXmqS368dOn/jvijV/zHLfakWTYHBZPk3G244lHrU= +github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.2 h1:yoLLsAsV5cfg9FLhZ9EXZ2n2sQFKeDYrHenkcivY4vI= github.com/elastic/go-windows v1.0.2/go.mod h1:bGcDpBzXgYSqM0Gx3DM4+UxFj300SZLixie9u9ixLM8= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= @@ -61,6 +113,10 @@ github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AY github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= @@ -69,38 +125,90 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc= github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/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.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mfridman/xflag v0.1.0 h1:TWZrZwG1QklFX5S4j1vxfF1sZbZeZSGofMwPMLAF29M= github.com/mfridman/xflag v0.1.0/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE= github.com/microsoft/go-mssqldb v1.8.0 h1:7cyZ/AT7ycDsEoWPIXibd+aVKFtteUNhDGf3aobP+tw= github.com/microsoft/go-mssqldb v1.8.0/go.mod h1:6znkekS3T2vp0waiMhen4GPU1BiAsrP+iXHcE7a7rFo= +github.com/microsoft/go-mssqldb v1.9.2/go.mod h1:GBbW9ASTiDC+mpgWDGKdm3FnFLTUsLYN3iFL90lQ+PA= +github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk= github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.1 h1:F+S7ZlNKnrwHfSwdlgNSkKo67ReVf8o9fel6C3dkm/Q= github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/opencontainers/cgroups v0.0.1 h1:MXjMkkFpKv6kpuirUa4USFBas573sSAY082B4CiHEVA= @@ -109,18 +217,32 @@ github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8= github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= +github.com/pascaldekloe/name v1.0.1/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM= github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/rekby/fixenv v0.6.1/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= @@ -133,6 +255,8 @@ github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2 github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -141,8 +265,18 @@ github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU= github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s= github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= @@ -154,46 +288,150 @@ github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQ github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 h1:LY6cI8cP4B9rrpTleZk95+08kl2gF4rixG7+V/dwL6Q= github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= github.com/ydb-platform/ydb-go-sdk/v3 v3.108.1 h1:ixAiqjj2S/dNuJqrz4AxSqgw2P5OBMXp68hB5nNriUk= github.com/ydb-platform/ydb-go-sdk/v3 v3.108.1/go.mod h1:l5sSv153E18VvYcsmr51hok9Sjc16tEC8AXGbwrk+ho= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA= go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA= go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= +modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= +modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/migrations/001_metrics.sql b/migrations/001_metrics.sql index 781f8d8..9284188 100644 --- a/migrations/001_metrics.sql +++ b/migrations/001_metrics.sql @@ -2,6 +2,7 @@ -- +goose StatementBegin -- +goose ENVSUB ON CREATE USER ${METRICS_USER} WITH PASSWORD '${METRICS_PASS}'; + GRANT pg_monitor TO ${METRICS_USER}; -- +goose ENVSUB OFF -- +goose StatementEnd @@ -10,6 +11,7 @@ GRANT pg_monitor TO ${METRICS_USER}; -- +goose StatementBegin -- +goose ENVSUB ON REVOKE pg_monitor FROM ${METRICS_USER}; + DROP USER ${METRICS_USER}; -- +goose ENVSUB OFF --- +goose StatementEnd +-- +goose StatementEnd \ No newline at end of file diff --git a/migrations/002_auth.sql b/migrations/002_auth.sql index 0c6afb9..9ab1990 100644 --- a/migrations/002_auth.sql +++ b/migrations/002_auth.sql @@ -2,9 +2,13 @@ -- +goose StatementBegin -- +goose ENVSUB ON CREATE USER ${AUTH_USER} WITH PASSWORD '${AUTH_PASS}'; + CREATE SCHEMA auth AUTHORIZATION ${AUTH_USER}; + ALTER ROLE ${AUTH_USER} SET search_path TO auth; + GRANT USAGE ON SCHEMA auth TO ${AUTH_USER}; + GRANT CREATE ON SCHEMA auth TO ${AUTH_USER}; -- +goose ENVSUB OFF -- +goose StatementEnd @@ -13,6 +17,7 @@ GRANT CREATE ON SCHEMA auth TO ${AUTH_USER}; -- +goose StatementBegin -- +goose ENVSUB ON DROP USER IF EXISTS ${AUTH_USER}; + DROP SCHEMA IF EXISTS auth CASCADE; -- +goose ENVSUB OFF --- +goose StatementEnd +-- +goose StatementEnd \ No newline at end of file diff --git a/migrations/003_profiles.sql b/migrations/003_profiles.sql new file mode 100644 index 0000000..3de0be8 --- /dev/null +++ b/migrations/003_profiles.sql @@ -0,0 +1,23 @@ +-- +goose Up +-- +goose StatementBegin +-- +goose ENVSUB ON +CREATE USER ${PROFILES_USER} WITH PASSWORD '${PROFILES_PASS}'; + +CREATE SCHEMA profiles AUTHORIZATION ${PROFILES_USER}; + +ALTER ROLE ${PROFILES_USER} SET search_path TO profiles; + +GRANT USAGE ON SCHEMA profiles TO ${PROFILES_USER}; + +GRANT CREATE ON SCHEMA profiles TO ${PROFILES_USER}; +-- +goose ENVSUB OFF +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +-- +goose ENVSUB ON +DROP USER IF EXISTS ${PROFILES_USER}; + +DROP SCHEMA IF EXISTS profiles CASCADE; +-- +goose ENVSUB OFF +-- +goose StatementEnd \ No newline at end of file diff --git a/profiles/cmd/profiles/main.go b/profiles/cmd/profiles/main.go new file mode 100644 index 0000000..e00c905 --- /dev/null +++ b/profiles/cmd/profiles/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "context" + "log/slog" + "os" + "os/signal" + "syscall" + + "github.com/alexwatcher/gateofthings/profiles/internal/app" + "github.com/alexwatcher/gateofthings/profiles/internal/config" + "github.com/alexwatcher/gateofthings/profiles/internal/consts" + sharedpgsql "github.com/alexwatcher/gateofthings/shared/pkg/migrator/postgresql" + "github.com/alexwatcher/gateofthings/shared/pkg/telemetry" +) + +func main() { + ctx := context.Background() + cfg := config.MustLoad() + + res := telemetry.MustCreateResource(consts.ServiceName, consts.ServiceVersion, cfg.Env) + telemetry.MustInitLogger(context.Background(), res, cfg.Telemetry.LogsEndpoint) + telemetry.MustInitTracer(context.Background(), res, cfg.Telemetry.TraceEndpoint) + telemetry.MustInitMeter(context.Background(), res, cfg.Telemetry.MetricsEndpoint) + + slog.Info("start migration") + sharedpgsql.Migrate(cfg.Database) + slog.Info("end migration") + + slog.Info("starting application") + application := app.New(ctx, cfg.GRPC, cfg.Database) + go application.MustRun(ctx) + + stop := make(chan os.Signal, 1) + signal.Notify(stop, syscall.SIGTERM, syscall.SIGINT) + sig := <-stop + + slog.Info("stopping application", "signal", sig) + application.Stop(ctx) +} diff --git a/profiles/go.mod b/profiles/go.mod new file mode 100644 index 0000000..c0f02f3 --- /dev/null +++ b/profiles/go.mod @@ -0,0 +1,55 @@ +module github.com/alexwatcher/gateofthings/profiles + +go 1.25.0 + +replace github.com/alexwatcher/gateofthings/protos => ../protos + +replace github.com/alexwatcher/gateofthings/shared => ../shared + +require ( + github.com/Masterminds/squirrel v1.5.4 + github.com/alexwatcher/gateofthings/protos v0.0.0-00010101000000-000000000000 + github.com/alexwatcher/gateofthings/shared v0.0.0-00010101000000-000000000000 + github.com/caarlos0/env/v11 v11.3.1 + github.com/jackc/pgx/v5 v5.7.6 + google.golang.org/grpc v1.75.1 +) + +require ( + github.com/cenkalti/backoff/v5 v5.0.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/mfridman/interpolate v0.0.2 // indirect + github.com/pressly/goose/v3 v3.25.0 // indirect + github.com/sethvargo/go-retry v0.3.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.12.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/log v0.13.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect + 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 + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/protobuf v1.36.6 // indirect +) diff --git a/profiles/go.sum b/profiles/go.sum new file mode 100644 index 0000000..8039714 --- /dev/null +++ b/profiles/go.sum @@ -0,0 +1,124 @@ +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA= +github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk= +github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= +github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pressly/goose/v3 v3.25.0 h1:6WeYhMWGRCzpyd89SpODFnCBCKz41KrVbRT58nVjGng= +github.com/pressly/goose/v3 v3.25.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= +github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= +github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.12.0 h1:lFM7SZo8Ce01RzRfnUFQZEYeWRf/MtOA3A5MobOqk2g= +go.opentelemetry.io/contrib/bridges/otelslog v0.12.0/go.mod h1:Dw05mhFtrKAYu72Tkb3YBYeQpRUJ4quDgo2DQw3No5A= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 h1:z6lNIajgEBVtQZHjfw2hAccPEBDs+nx58VemmXWa2ec= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0/go.mod h1:+kyc3bRx/Qkq05P6OCu3mTEIOxYRYzoIg+JsUp5X+PM= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/log v0.13.0 h1:yoxRoIZcohB6Xf0lNv9QIyCzQvrtGZklVbdCoyb7dls= +go.opentelemetry.io/otel/log v0.13.0/go.mod h1:INKfG4k1O9CL25BaM1qLe0zIedOpvlS5Z7XgSbmN83E= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/log v0.13.0 h1:I3CGUszjM926OphK8ZdzF+kLqFvfRY/IIoFq/TjwfaQ= +go.opentelemetry.io/otel/sdk/log v0.13.0/go.mod h1:lOrQyCCXmpZdN7NchXb6DOZZa1N5G1R2tm5GMMTpDBw= +go.opentelemetry.io/otel/sdk/log/logtest v0.13.0 h1:9yio6AFZ3QD9j9oqshV1Ibm9gPLlHNxurno5BreMtIA= +go.opentelemetry.io/otel/sdk/log/logtest v0.13.0/go.mod h1:QOGiAJHl+fob8Nu85ifXfuQYmJTFAvcrxL6w5/tu168= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= +go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +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= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= +google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= +modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek= +modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E= diff --git a/profiles/internal/app/app.go b/profiles/internal/app/app.go new file mode 100644 index 0000000..1e7bc74 --- /dev/null +++ b/profiles/internal/app/app.go @@ -0,0 +1,78 @@ +package app + +import ( + "context" + "fmt" + "log/slog" + "net" + + grpcprofiles "github.com/alexwatcher/gateofthings/profiles/internal/grpc/profiles" + "github.com/alexwatcher/gateofthings/profiles/internal/repository/postgresql" + "github.com/alexwatcher/gateofthings/profiles/internal/services" + "github.com/alexwatcher/gateofthings/shared/pkg/config" + "github.com/alexwatcher/gateofthings/shared/pkg/grpc/interceptors/metadataextractor" + "github.com/alexwatcher/gateofthings/shared/pkg/grpc/interceptors/tracing" + "github.com/alexwatcher/gateofthings/shared/pkg/grpc/interceptors/valid" + sharedpgsql "github.com/alexwatcher/gateofthings/shared/pkg/repository/postgresql" + "google.golang.org/grpc" +) + +type App struct { + gRPCServer *grpc.Server + gRPConfig config.GRPCSrvConfig +} + +// New initializes a new instance of the App struct with a gRPC server +// listening on the specified port. It registers the authentication +// service with the server and returns the configured App instance. +func New(ctx context.Context, gRPConfig config.GRPCSrvConfig, dbConfig config.DatabaseConfig) *App { + + dbConn, err := sharedpgsql.NewConnection(ctx, dbConfig) + if err != nil { + slog.Error("failed to connect to database", "error", err) + panic(err) + } + repo := postgresql.NewProfilesRepo(dbConn) + + profilesService := services.NewProfiles(repo) + gRPCServer := grpc.NewServer( + grpc.ChainUnaryInterceptor( + tracing.TracingInterceptor(), + valid.UnaryInterceptor, + metadataextractor.ExtractMetadataInterceptor, + ), + ) + grpcprofiles.Register(gRPCServer, profilesService) + return &App{ + gRPCServer: gRPCServer, + gRPConfig: gRPConfig, + } +} + +// MustRun starts the gRPC server and panics if it can't be started. +func (a *App) MustRun(ctx context.Context) { + if err := a.Run(ctx); err != nil { + panic(err) + } +} + +// Run starts the gRPC server and logs the port it is listening on. If the +// server can't be started, it returns an error. +func (a *App) Run(ctx context.Context) error { + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", a.gRPConfig.Port)) + if err != nil { + return err + } + slog.Info("gRPC server started", "port", a.gRPConfig.Port) + if err := a.gRPCServer.Serve(lis); err != nil { + return fmt.Errorf("app.run: %w", err) + } + return nil +} + +// Stop gracefully stops the gRPC server, ensuring that it no longer accepts new connections +// and waits for all ongoing RPCs to complete before shutting down. +func (a *App) Stop(ctx context.Context) { + slog.Info("stopping gRPC server") + a.gRPCServer.GracefulStop() +} diff --git a/profiles/internal/config/config.go b/profiles/internal/config/config.go new file mode 100644 index 0000000..b9e7b82 --- /dev/null +++ b/profiles/internal/config/config.go @@ -0,0 +1,21 @@ +package config + +import ( + scfg "github.com/alexwatcher/gateofthings/shared/pkg/config" + "github.com/caarlos0/env/v11" +) + +type Config struct { + Env string `env:"ENV" envDefault:"local"` + Telemetry scfg.TelemetryConfig `envPrefix:"TELEMETRY_"` + GRPC scfg.GRPCSrvConfig `envPrefix:"GRPC_"` + Database scfg.DatabaseConfig `envPrefix:"DB_"` +} + +// MustLoad loads configuration from environment variables into a Config instance. +// If the environment variables can't be parsed, it panics with the error. +func MustLoad() *Config { + var cfg Config + err := env.Parse(&cfg) + return env.Must(&cfg, err) +} diff --git a/profiles/internal/consts/metadata.go b/profiles/internal/consts/metadata.go new file mode 100644 index 0000000..d02f8e8 --- /dev/null +++ b/profiles/internal/consts/metadata.go @@ -0,0 +1,3 @@ +package consts + +const MetaUserID = "x-user-id" diff --git a/profiles/internal/consts/service.go b/profiles/internal/consts/service.go new file mode 100644 index 0000000..df23a0c --- /dev/null +++ b/profiles/internal/consts/service.go @@ -0,0 +1,6 @@ +package consts + +const ( + ServiceName = "profiles" + ServiceVersion = "dev" +) diff --git a/profiles/internal/grpc/profiles/server.go b/profiles/internal/grpc/profiles/server.go new file mode 100644 index 0000000..4020eaf --- /dev/null +++ b/profiles/internal/grpc/profiles/server.go @@ -0,0 +1,68 @@ +package profiles + +import ( + "context" + "errors" + + "github.com/alexwatcher/gateofthings/profiles/internal/models" + profilesv1 "github.com/alexwatcher/gateofthings/protos/gen/go/profiles/v1" + "github.com/alexwatcher/gateofthings/shared/pkg/contextutils" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type Profiles interface { + Create(ctx context.Context, profile *models.Profile) (id string, err error) + GetMe(ctx context.Context) (profile *models.Profile, err error) +} + +type serverAPI struct { + profilesv1.UnimplementedProfilesServer + profiles Profiles +} + +func Register(gRPC *grpc.Server, profiles Profiles) { + profilesv1.RegisterProfilesServer(gRPC, &serverAPI{profiles: profiles}) +} + +func (s *serverAPI) Create(ctx context.Context, in *profilesv1.CreateRequest) (*profilesv1.CreateResponse, error) { + // validate authentication + userId := contextutils.XUserIdFromContext(ctx) + if userId != in.Porfile.Id { + return nil, status.Error(codes.Unauthenticated, models.ErrUnauthenticated.Error()) + } + + // + profile := &models.Profile{ + Id: in.Porfile.Id, + Name: in.Porfile.Name, + Avatar: in.Porfile.Avatar, + } + id, err := s.profiles.Create(ctx, profile) + if err != nil { + if errors.Is(err, models.ErrProfileAlreadyExists) { + return nil, status.Error(codes.AlreadyExists, err.Error()) + } + return nil, status.Error(codes.Internal, err.Error()) + } + return &profilesv1.CreateResponse{Id: id}, nil +} + +func (s *serverAPI) GetMe(ctx context.Context, in *profilesv1.GetMeRequest) (*profilesv1.GetMeResponse, error) { + profile, err := s.profiles.GetMe(ctx) + if err != nil { + if errors.Is(err, models.ErrProfileNotFound) { + return nil, status.Error(codes.NotFound, err.Error()) + } + if errors.Is(err, models.ErrUnauthenticated) { + return nil, status.Error(codes.Unauthenticated, err.Error()) + } + return nil, status.Error(codes.Internal, err.Error()) + } + return &profilesv1.GetMeResponse{Porfile: &profilesv1.Profile{ + Id: profile.Id, + Name: profile.Name, + Avatar: profile.Avatar, + }}, nil +} diff --git a/profiles/internal/models/errors.go b/profiles/internal/models/errors.go new file mode 100644 index 0000000..7ca8838 --- /dev/null +++ b/profiles/internal/models/errors.go @@ -0,0 +1,9 @@ +package models + +import "errors" + +var ( + ErrProfileNotFound = errors.New("profile not found") + ErrProfileAlreadyExists = errors.New("profile already exists") + ErrUnauthenticated = errors.New("unauthenticated") +) diff --git a/profiles/internal/models/profile.go b/profiles/internal/models/profile.go new file mode 100644 index 0000000..b2e71b9 --- /dev/null +++ b/profiles/internal/models/profile.go @@ -0,0 +1,7 @@ +package models + +type Profile struct { + Id string + Name string + Avatar []byte +} diff --git a/profiles/internal/repository/postgresql/profiles.go b/profiles/internal/repository/postgresql/profiles.go new file mode 100644 index 0000000..ad154b0 --- /dev/null +++ b/profiles/internal/repository/postgresql/profiles.go @@ -0,0 +1,68 @@ +package postgresql + +import ( + "context" + "errors" + "fmt" + + "github.com/Masterminds/squirrel" + "github.com/alexwatcher/gateofthings/profiles/internal/models" + spgsql "github.com/alexwatcher/gateofthings/shared/pkg/repository/postgresql" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type ProfilesRepo struct { + conn *pgx.Conn +} + +func NewProfilesRepo(conn *pgx.Conn) *ProfilesRepo { + return &ProfilesRepo{conn: conn} +} + +func (r *ProfilesRepo) Insert(ctx context.Context, profile *models.Profile) (string, error) { + op := "repository.profiles.Insert" + sql, args, err := spgsql.SqlBuilder. + Insert("user_profiles"). + Columns("id", "name", "avatar"). + Values(profile.Id, profile.Name, profile.Avatar). + ToSql() + if err != nil { + return "", fmt.Errorf("%s: %w", op, err) + } + + _, err = r.conn.Exec(ctx, sql, args...) + if err != nil { + var pgErr *pgconn.PgError + if errors.As(err, &pgErr) && pgErr.Code == spgsql.ErrCodeUniqueViolation { + return "", fmt.Errorf("%s: %w", op, models.ErrProfileAlreadyExists) + } + return "", fmt.Errorf("%s: %w", op, err) + } + + return profile.Id, nil +} + +func (r *ProfilesRepo) Get(ctx context.Context, id string) (*models.Profile, error) { + op := "repository.profiles.Get" + + var profile models.Profile + query, args, err := spgsql.SqlBuilder. + Select("id", "name", "avatar"). + From("user_profiles"). + Where(squirrel.Eq{"id": id}). + ToSql() + if err != nil { + return &profile, fmt.Errorf("%s: %w", op, err) + } + + err = r.conn.QueryRow(ctx, query, args...).Scan(&profile.Id, &profile.Name, &profile.Avatar) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return &profile, fmt.Errorf("%s: %w", op, models.ErrProfileNotFound) + } + return &profile, fmt.Errorf("%s: %w", op, err) + } + + return &profile, nil +} diff --git a/profiles/internal/services/profiles.go b/profiles/internal/services/profiles.go new file mode 100644 index 0000000..554cc51 --- /dev/null +++ b/profiles/internal/services/profiles.go @@ -0,0 +1,73 @@ +package services + +import ( + "context" + "errors" + "fmt" + "log/slog" + + "github.com/alexwatcher/gateofthings/profiles/internal/models" + "github.com/alexwatcher/gateofthings/shared/pkg/contextutils" +) + +type ProfilesRepo interface { + Insert(ctx context.Context, profile *models.Profile) (string, error) + Get(ctx context.Context, id string) (*models.Profile, error) +} + +type Profiles struct { + repo ProfilesRepo +} + +// NewProfiles initializes a new instance of the Profiles service with the given repository +func NewProfiles(repo ProfilesRepo) *Profiles { + return &Profiles{repo: repo} +} + +func (p *Profiles) Create(ctx context.Context, profile *models.Profile) (string, error) { + op := "profiles.create" + log := slog.With("op", op, "id", profile.Id, "name", profile.Name) + + userId := contextutils.XUserIdFromContext(ctx) + if userId != profile.Id { + log.Error("x-user-id not equalt to requested user id") + return "", fmt.Errorf("%s: %w", op, models.ErrUnauthenticated) + } + + log.Info("create profile") + profileId, err := p.repo.Insert(ctx, profile) + if err != nil { + if errors.Is(err, models.ErrProfileAlreadyExists) { + log.Error("profile already exists", "error", err) + return "", fmt.Errorf("%s: %w", op, err) + } + log.Error("failed create profile", "error", err) + return "", fmt.Errorf("%s: %w", op, err) + } + log.Info("profile created") + return profileId, nil +} + +func (p *Profiles) GetMe(ctx context.Context) (*models.Profile, error) { + op := "profiles.getme" + log := slog.With("op", op) + + userId := contextutils.XUserIdFromContext(ctx) + if userId == "" { + log.Error("x-user-id not specified") + return nil, fmt.Errorf("%s: %w", op, models.ErrUnauthenticated) + } + + log.Info("get my profile") + profile, err := p.repo.Get(ctx, userId) + if err != nil { + if errors.Is(err, models.ErrProfileNotFound) { + log.Error("profile not found", "error", err) + return nil, fmt.Errorf("%s: %w", op, err) + } + log.Error("failed get profile", "error", err) + return nil, fmt.Errorf("%s: %w", op, err) + } + log.Info("profile found") + return profile, nil +} diff --git a/profiles/migrations/001_init.sql b/profiles/migrations/001_init.sql new file mode 100644 index 0000000..e12fabe --- /dev/null +++ b/profiles/migrations/001_init.sql @@ -0,0 +1,11 @@ +-- +goose Up +CREATE TABLE IF NOT EXISTS user_profiles ( + id UUID PRIMARY KEY, + name TEXT, + avatar BYTEA CHECK (LENGTH(avatar) <= 131072), -- 128kB + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +-- +goose Down +DROP TABLE IF EXISTS user_profiles; diff --git a/protos/Taskfile.yaml b/protos/Taskfile.yaml index 230050d..7d4c471 100644 --- a/protos/Taskfile.yaml +++ b/protos/Taskfile.yaml @@ -25,33 +25,33 @@ tasks: generate: dir: "{{.TASKFILE_DIR}}" aliases: - - gen + - gen deps: [clear] desc: Generate proto files cmds: - - | - echo "Generating Go code from proto files..." - mkdir -p {{.OUT_DIR}}/go - mkdir -p {{.OUT_DIR}}/swagger - FILES=$(find {{.PROTO_DIR}} -name '*.proto') - echo "Found proto files: ${FILES}" - protoc \ - {{.INCLUDE_PROTOBUF_PATHS}} \ - -I {{.PROTO_DIR}} \ - -I {{.EXTERNAL_DIR}} \ - --go_out={{.OUT_DIR}}/go --go_opt=paths=source_relative \ - --go-grpc_out={{.OUT_DIR}}/go --go-grpc_opt=paths=source_relative \ - --grpc-gateway_out={{.OUT_DIR}}/go --grpc-gateway_opt=paths=source_relative \ - --openapiv2_out={{.OUT_DIR}}/swagger \ - ${FILES} - + - | + echo "Generating Go code from proto files..." + mkdir -p {{.OUT_DIR}}/go + mkdir -p {{.OUT_DIR}}/swagger + FILES=$(find {{.PROTO_DIR}} -name '*.proto') + echo "Found proto files: ${FILES}" + protoc \ + {{.INCLUDE_PROTOBUF_PATHS}} \ + -I {{.PROTO_DIR}} \ + -I {{.EXTERNAL_DIR}} \ + --go_out={{.OUT_DIR}}/go --go_opt=paths=source_relative \ + --go-grpc_out={{.OUT_DIR}}/go --go-grpc_opt=paths=source_relative \ + --grpc-gateway_out={{.OUT_DIR}}/go --grpc-gateway_opt=paths=source_relative \ + --openapiv2_out={{.OUT_DIR}}/swagger \ + ${FILES} + clear: dir: "{{.TASKFILE_DIR}}" aliases: - - clr + - clr desc: Remove generated files cmds: - - | - echo "Cleanup generated files" - rm -rf {{.OUT_DIR}}/go - rm -rf {{.OUT_DIR}}/swagger + - | + echo "Cleanup generated files" + rm -rf {{.OUT_DIR}}/go + rm -rf {{.OUT_DIR}}/swagger diff --git a/protos/gen/go/auth/v1/auth.pb.go b/protos/gen/go/auth/v1/auth.pb.go index 3effdf6..bfd109b 100644 --- a/protos/gen/go/auth/v1/auth.pb.go +++ b/protos/gen/go/auth/v1/auth.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.8 -// protoc v6.32.0 +// protoc v6.32.1 // source: auth/v1/auth.proto package authv1 diff --git a/protos/gen/go/auth/v1/auth_grpc.pb.go b/protos/gen/go/auth/v1/auth_grpc.pb.go index de18cf7..0a47ad5 100644 --- a/protos/gen/go/auth/v1/auth_grpc.pb.go +++ b/protos/gen/go/auth/v1/auth_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v6.32.0 +// - protoc v6.32.1 // source: auth/v1/auth.proto package authv1 diff --git a/protos/gen/go/profiles/v1/profiles.pb.go b/protos/gen/go/profiles/v1/profiles.pb.go new file mode 100644 index 0000000..0f3828b --- /dev/null +++ b/protos/gen/go/profiles/v1/profiles.pb.go @@ -0,0 +1,329 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.8 +// protoc v6.32.1 +// source: profiles/v1/profiles.proto + +package profilesv1 + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Profile struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Avatar []byte `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Profile) Reset() { + *x = Profile{} + mi := &file_profiles_v1_profiles_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Profile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Profile) ProtoMessage() {} + +func (x *Profile) ProtoReflect() protoreflect.Message { + mi := &file_profiles_v1_profiles_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Profile.ProtoReflect.Descriptor instead. +func (*Profile) Descriptor() ([]byte, []int) { + return file_profiles_v1_profiles_proto_rawDescGZIP(), []int{0} +} + +func (x *Profile) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Profile) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Profile) GetAvatar() []byte { + if x != nil { + return x.Avatar + } + return nil +} + +type CreateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Porfile *Profile `protobuf:"bytes,1,opt,name=porfile,proto3" json:"porfile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateRequest) Reset() { + *x = CreateRequest{} + mi := &file_profiles_v1_profiles_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateRequest) ProtoMessage() {} + +func (x *CreateRequest) ProtoReflect() protoreflect.Message { + mi := &file_profiles_v1_profiles_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateRequest.ProtoReflect.Descriptor instead. +func (*CreateRequest) Descriptor() ([]byte, []int) { + return file_profiles_v1_profiles_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateRequest) GetPorfile() *Profile { + if x != nil { + return x.Porfile + } + return nil +} + +type CreateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateResponse) Reset() { + *x = CreateResponse{} + mi := &file_profiles_v1_profiles_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateResponse) ProtoMessage() {} + +func (x *CreateResponse) ProtoReflect() protoreflect.Message { + mi := &file_profiles_v1_profiles_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateResponse.ProtoReflect.Descriptor instead. +func (*CreateResponse) Descriptor() ([]byte, []int) { + return file_profiles_v1_profiles_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateResponse) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetMeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMeRequest) Reset() { + *x = GetMeRequest{} + mi := &file_profiles_v1_profiles_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMeRequest) ProtoMessage() {} + +func (x *GetMeRequest) ProtoReflect() protoreflect.Message { + mi := &file_profiles_v1_profiles_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMeRequest.ProtoReflect.Descriptor instead. +func (*GetMeRequest) Descriptor() ([]byte, []int) { + return file_profiles_v1_profiles_proto_rawDescGZIP(), []int{3} +} + +type GetMeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Porfile *Profile `protobuf:"bytes,1,opt,name=porfile,proto3" json:"porfile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMeResponse) Reset() { + *x = GetMeResponse{} + mi := &file_profiles_v1_profiles_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMeResponse) ProtoMessage() {} + +func (x *GetMeResponse) ProtoReflect() protoreflect.Message { + mi := &file_profiles_v1_profiles_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMeResponse.ProtoReflect.Descriptor instead. +func (*GetMeResponse) Descriptor() ([]byte, []int) { + return file_profiles_v1_profiles_proto_rawDescGZIP(), []int{4} +} + +func (x *GetMeResponse) GetPorfile() *Profile { + if x != nil { + return x.Porfile + } + return nil +} + +var File_profiles_v1_profiles_proto protoreflect.FileDescriptor + +const file_profiles_v1_profiles_proto_rawDesc = "" + + "\n" + + "\x1aprofiles/v1/profiles.proto\x12\x04auth\x1a\x1cgoogle/api/annotations.proto\"E\n" + + "\aProfile\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x16\n" + + "\x06avatar\x18\x03 \x01(\fR\x06avatar\"8\n" + + "\rCreateRequest\x12'\n" + + "\aporfile\x18\x01 \x01(\v2\r.auth.ProfileR\aporfile\" \n" + + "\x0eCreateResponse\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"\x0e\n" + + "\fGetMeRequest\"8\n" + + "\rGetMeResponse\x12'\n" + + "\aporfile\x18\x01 \x01(\v2\r.auth.ProfileR\aporfile2\x8a\x01\n" + + "\bProfiles\x123\n" + + "\x06Create\x12\x13.auth.CreateRequest\x1a\x14.auth.CreateResponse\x12I\n" + + "\x05GetMe\x12\x12.auth.GetMeRequest\x1a\x13.auth.GetMeResponse\"\x17\x82\xd3\xe4\x93\x02\x11\x12\x0f/v1/profiles/meB\x18Z\x16profiles.v1;profilesv1b\x06proto3" + +var ( + file_profiles_v1_profiles_proto_rawDescOnce sync.Once + file_profiles_v1_profiles_proto_rawDescData []byte +) + +func file_profiles_v1_profiles_proto_rawDescGZIP() []byte { + file_profiles_v1_profiles_proto_rawDescOnce.Do(func() { + file_profiles_v1_profiles_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_profiles_v1_profiles_proto_rawDesc), len(file_profiles_v1_profiles_proto_rawDesc))) + }) + return file_profiles_v1_profiles_proto_rawDescData +} + +var file_profiles_v1_profiles_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_profiles_v1_profiles_proto_goTypes = []any{ + (*Profile)(nil), // 0: auth.Profile + (*CreateRequest)(nil), // 1: auth.CreateRequest + (*CreateResponse)(nil), // 2: auth.CreateResponse + (*GetMeRequest)(nil), // 3: auth.GetMeRequest + (*GetMeResponse)(nil), // 4: auth.GetMeResponse +} +var file_profiles_v1_profiles_proto_depIdxs = []int32{ + 0, // 0: auth.CreateRequest.porfile:type_name -> auth.Profile + 0, // 1: auth.GetMeResponse.porfile:type_name -> auth.Profile + 1, // 2: auth.Profiles.Create:input_type -> auth.CreateRequest + 3, // 3: auth.Profiles.GetMe:input_type -> auth.GetMeRequest + 2, // 4: auth.Profiles.Create:output_type -> auth.CreateResponse + 4, // 5: auth.Profiles.GetMe:output_type -> auth.GetMeResponse + 4, // [4:6] is the sub-list for method output_type + 2, // [2:4] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_profiles_v1_profiles_proto_init() } +func file_profiles_v1_profiles_proto_init() { + if File_profiles_v1_profiles_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_profiles_v1_profiles_proto_rawDesc), len(file_profiles_v1_profiles_proto_rawDesc)), + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_profiles_v1_profiles_proto_goTypes, + DependencyIndexes: file_profiles_v1_profiles_proto_depIdxs, + MessageInfos: file_profiles_v1_profiles_proto_msgTypes, + }.Build() + File_profiles_v1_profiles_proto = out.File + file_profiles_v1_profiles_proto_goTypes = nil + file_profiles_v1_profiles_proto_depIdxs = nil +} diff --git a/protos/gen/go/profiles/v1/profiles.pb.gw.go b/protos/gen/go/profiles/v1/profiles.pb.gw.go new file mode 100644 index 0000000..897fedf --- /dev/null +++ b/protos/gen/go/profiles/v1/profiles.pb.gw.go @@ -0,0 +1,151 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: profiles/v1/profiles.proto + +/* +Package profilesv1 is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package profilesv1 + +import ( + "context" + "errors" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var ( + _ codes.Code + _ io.Reader + _ status.Status + _ = errors.New + _ = runtime.String + _ = utilities.NewDoubleArray + _ = metadata.Join +) + +func request_Profiles_GetMe_0(ctx context.Context, marshaler runtime.Marshaler, client ProfilesClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetMeRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.GetMe(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_Profiles_GetMe_0(ctx context.Context, marshaler runtime.Marshaler, server ProfilesServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetMeRequest + metadata runtime.ServerMetadata + ) + msg, err := server.GetMe(ctx, &protoReq) + return msg, metadata, err +} + +// RegisterProfilesHandlerServer registers the http handlers for service Profiles to "mux". +// UnaryRPC :call ProfilesServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterProfilesHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. +func RegisterProfilesHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ProfilesServer) error { + mux.Handle(http.MethodGet, pattern_Profiles_GetMe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/auth.Profiles/GetMe", runtime.WithHTTPPathPattern("/v1/profiles/me")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Profiles_GetMe_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_Profiles_GetMe_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + + return nil +} + +// RegisterProfilesHandlerFromEndpoint is same as RegisterProfilesHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterProfilesHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.NewClient(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + return RegisterProfilesHandler(ctx, mux, conn) +} + +// RegisterProfilesHandler registers the http handlers for service Profiles to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterProfilesHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterProfilesHandlerClient(ctx, mux, NewProfilesClient(conn)) +} + +// RegisterProfilesHandlerClient registers the http handlers for service Profiles +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ProfilesClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ProfilesClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "ProfilesClient" to call the correct interceptors. This client ignores the HTTP middlewares. +func RegisterProfilesHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ProfilesClient) error { + mux.Handle(http.MethodGet, pattern_Profiles_GetMe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/auth.Profiles/GetMe", runtime.WithHTTPPathPattern("/v1/profiles/me")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Profiles_GetMe_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_Profiles_GetMe_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + return nil +} + +var ( + pattern_Profiles_GetMe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "profiles", "me"}, "")) +) + +var ( + forward_Profiles_GetMe_0 = runtime.ForwardResponseMessage +) diff --git a/protos/gen/go/profiles/v1/profiles_grpc.pb.go b/protos/gen/go/profiles/v1/profiles_grpc.pb.go new file mode 100644 index 0000000..acc1914 --- /dev/null +++ b/protos/gen/go/profiles/v1/profiles_grpc.pb.go @@ -0,0 +1,159 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v6.32.1 +// source: profiles/v1/profiles.proto + +package profilesv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Profiles_Create_FullMethodName = "/auth.Profiles/Create" + Profiles_GetMe_FullMethodName = "/auth.Profiles/GetMe" +) + +// ProfilesClient is the client API for Profiles service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ProfilesClient interface { + Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) + GetMe(ctx context.Context, in *GetMeRequest, opts ...grpc.CallOption) (*GetMeResponse, error) +} + +type profilesClient struct { + cc grpc.ClientConnInterface +} + +func NewProfilesClient(cc grpc.ClientConnInterface) ProfilesClient { + return &profilesClient{cc} +} + +func (c *profilesClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateResponse) + err := c.cc.Invoke(ctx, Profiles_Create_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *profilesClient) GetMe(ctx context.Context, in *GetMeRequest, opts ...grpc.CallOption) (*GetMeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetMeResponse) + err := c.cc.Invoke(ctx, Profiles_GetMe_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ProfilesServer is the server API for Profiles service. +// All implementations must embed UnimplementedProfilesServer +// for forward compatibility. +type ProfilesServer interface { + Create(context.Context, *CreateRequest) (*CreateResponse, error) + GetMe(context.Context, *GetMeRequest) (*GetMeResponse, error) + mustEmbedUnimplementedProfilesServer() +} + +// UnimplementedProfilesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedProfilesServer struct{} + +func (UnimplementedProfilesServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} +func (UnimplementedProfilesServer) GetMe(context.Context, *GetMeRequest) (*GetMeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetMe not implemented") +} +func (UnimplementedProfilesServer) mustEmbedUnimplementedProfilesServer() {} +func (UnimplementedProfilesServer) testEmbeddedByValue() {} + +// UnsafeProfilesServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ProfilesServer will +// result in compilation errors. +type UnsafeProfilesServer interface { + mustEmbedUnimplementedProfilesServer() +} + +func RegisterProfilesServer(s grpc.ServiceRegistrar, srv ProfilesServer) { + // If the following call pancis, it indicates UnimplementedProfilesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Profiles_ServiceDesc, srv) +} + +func _Profiles_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProfilesServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Profiles_Create_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProfilesServer).Create(ctx, req.(*CreateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Profiles_GetMe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetMeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProfilesServer).GetMe(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Profiles_GetMe_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProfilesServer).GetMe(ctx, req.(*GetMeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Profiles_ServiceDesc is the grpc.ServiceDesc for Profiles service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Profiles_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "auth.Profiles", + HandlerType: (*ProfilesServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Create", + Handler: _Profiles_Create_Handler, + }, + { + MethodName: "GetMe", + Handler: _Profiles_GetMe_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "profiles/v1/profiles.proto", +} diff --git a/protos/gen/swagger/profiles/v1/profiles.swagger.json b/protos/gen/swagger/profiles/v1/profiles.swagger.json new file mode 100644 index 0000000..7683330 --- /dev/null +++ b/protos/gen/swagger/profiles/v1/profiles.swagger.json @@ -0,0 +1,103 @@ +{ + "swagger": "2.0", + "info": { + "title": "profiles/v1/profiles.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "Profiles" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/profiles/me": { + "get": { + "operationId": "Profiles_GetMe", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/authGetMeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "Profiles" + ] + } + } + }, + "definitions": { + "authCreateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "authGetMeResponse": { + "type": "object", + "properties": { + "porfile": { + "$ref": "#/definitions/authProfile" + } + } + }, + "authProfile": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "avatar": { + "type": "string", + "format": "byte" + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/protos/proto/profiles/v1/profiles.proto b/protos/proto/profiles/v1/profiles.proto new file mode 100644 index 0000000..528ffbd --- /dev/null +++ b/protos/proto/profiles/v1/profiles.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package auth; + +import "google/api/annotations.proto"; + +option go_package = "profiles.v1;profilesv1"; + +service Profiles { + rpc Create(CreateRequest) returns (CreateResponse); + + rpc GetMe(GetMeRequest) returns (GetMeResponse) { + option (google.api.http) = { + get: "/v1/profiles/me" + }; + } +} + +message Profile { + string id = 1; + string name = 2; + bytes avatar = 3; +} + +message CreateRequest { + Profile porfile = 1; +}; + +message CreateResponse { + string id = 1; +}; + +message GetMeRequest { +}; + +message GetMeResponse { + Profile porfile = 1; +}; diff --git a/shared/pkg/contextutils/context.go b/shared/pkg/contextutils/context.go new file mode 100644 index 0000000..228e962 --- /dev/null +++ b/shared/pkg/contextutils/context.go @@ -0,0 +1,19 @@ +package contextutils + +import "context" + +type xUserId string + +const xUserIdKey xUserId = "x-user-id" + +func ContextWithXUserId(ctx context.Context, userId string) context.Context { + return context.WithValue(ctx, xUserIdKey, userId) +} + +func XUserIdFromContext(ctx context.Context) string { + userIdAny := ctx.Value(xUserIdKey) + if userId, ok := userIdAny.(string); ok { + return userId + } + return "" +} diff --git a/shared/pkg/grpc/interceptors/metadataextractor/metadata.go b/shared/pkg/grpc/interceptors/metadataextractor/metadata.go new file mode 100644 index 0000000..27d215c --- /dev/null +++ b/shared/pkg/grpc/interceptors/metadataextractor/metadata.go @@ -0,0 +1,18 @@ +package metadataextractor + +import ( + "context" + + "github.com/alexwatcher/gateofthings/shared/pkg/contextutils" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +func ExtractMetadataInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + if md, ok := metadata.FromIncomingContext(ctx); ok { + if userid, ok := md["x-user-id"]; ok && len(userid) > 0 { + return handler(contextutils.ContextWithXUserId(ctx, userid[0]), req) + } + } + return handler(ctx, req) +} diff --git a/auth/internal/grpc/interceptors/tracing/tracing.go b/shared/pkg/grpc/interceptors/tracing/tracing.go similarity index 100% rename from auth/internal/grpc/interceptors/tracing/tracing.go rename to shared/pkg/grpc/interceptors/tracing/tracing.go diff --git a/auth/internal/grpc/interceptors/valid/validation.go b/shared/pkg/grpc/interceptors/valid/validation.go similarity index 89% rename from auth/internal/grpc/interceptors/valid/validation.go rename to shared/pkg/grpc/interceptors/valid/validation.go index 75d1984..6047b58 100644 --- a/auth/internal/grpc/interceptors/valid/validation.go +++ b/shared/pkg/grpc/interceptors/valid/validation.go @@ -11,12 +11,8 @@ import ( var rulesMap = map[string]func(any) error{} -func getStructId(s any) string { - t := reflect.TypeOf(s) - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t.PkgPath() + "/" + t.Name() +func RegisterRule(s any, f func(s any) error) { + rulesMap[getStructId(s)] = f } func UnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { @@ -27,3 +23,11 @@ func UnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServ } return handler(ctx, req) } + +func getStructId(s any) string { + t := reflect.TypeOf(s) + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.PkgPath() + "/" + t.Name() +} diff --git a/auth/internal/migrator/postgresql/migrator.go b/shared/pkg/migrator/postgresql/migrator.go similarity index 100% rename from auth/internal/migrator/postgresql/migrator.go rename to shared/pkg/migrator/postgresql/migrator.go diff --git a/auth/internal/repository/postgresql/connect.go b/shared/pkg/repository/postgresql/connection.go similarity index 90% rename from auth/internal/repository/postgresql/connect.go rename to shared/pkg/repository/postgresql/connection.go index edab22d..01bba57 100644 --- a/auth/internal/repository/postgresql/connect.go +++ b/shared/pkg/repository/postgresql/connection.go @@ -9,7 +9,7 @@ import ( "github.com/jackc/pgx/v5" ) -var sqlBuilder = sq.StatementBuilder.PlaceholderFormat(sq.Dollar) +var SqlBuilder = sq.StatementBuilder.PlaceholderFormat(sq.Dollar) func NewConnection(ctx context.Context, cfg config.DatabaseConfig) (*pgx.Conn, error) { sslMode := "disable" diff --git a/shared/pkg/repository/postgresql/constants.go b/shared/pkg/repository/postgresql/constants.go new file mode 100644 index 0000000..ac67d63 --- /dev/null +++ b/shared/pkg/repository/postgresql/constants.go @@ -0,0 +1,7 @@ +package postgresql + +const ( + ErrCodeUniqueViolation = "23505" + ErrCodeForeignKey = "23503" + ErrCodeNotNull = "23502" +)