From 0341a938fdc1cfe28710a6e6a6c79a47a07e5efc Mon Sep 17 00:00:00 2001 From: Declan Date: Wed, 27 Sep 2023 16:17:47 +0100 Subject: [PATCH] init post-service --- services/post-service/.env.example | 11 + services/post-service/Dockerfile | 17 + services/post-service/Makefile | 13 + services/post-service/README.md | 65 + .../post-service/cmd/post-service/main.go | 42 + .../post-service/cmd/post-service/tools.go | 12 + services/post-service/go.mod | 40 + services/post-service/go.sum | 163 +++ services/post-service/internal/config.go | 89 ++ services/post-service/internal/errors.go | 80 ++ .../internal/kafka/consumers/panel.go | 76 ++ .../kafka/consumers/panelv1/panel.pb.go | 861 +++++++++++++ .../kafka/consumers/panelv1/panel_grpc.pb.go | 322 +++++ .../internal/kafka/consumers/user.go | 75 ++ .../kafka/consumers/userv1/user.pb.go | 849 ++++++++++++ .../kafka/consumers/userv1/user_grpc.pb.go | 322 +++++ services/post-service/internal/kafka/kafka.go | 23 + .../internal/kafka/producer/post.go | 60 + services/post-service/internal/post.go | 162 +++ .../migrations/000001_initialise_db.down.sql | 1 + .../migrations/000001_initialise_db.up.sql | 9 + .../post-service/internal/postgres/post.go | 262 ++++ .../internal/postgres/postgres.go | 24 + services/post-service/internal/redis/post.go | 151 +++ services/post-service/internal/redis/redis.go | 29 + services/post-service/internal/rpc/post.go | 179 +++ .../internal/rpc/postv1/conversion.go | 55 + .../internal/rpc/postv1/post.pb.go | 1145 +++++++++++++++++ .../internal/rpc/postv1/post_grpc.pb.go | 358 ++++++ services/post-service/internal/rpc/rpc.go | 77 ++ .../post-service/internal/service/post.go | 94 ++ 31 files changed, 5666 insertions(+) create mode 100644 services/post-service/.env.example create mode 100644 services/post-service/Dockerfile create mode 100644 services/post-service/Makefile create mode 100644 services/post-service/README.md create mode 100644 services/post-service/cmd/post-service/main.go create mode 100644 services/post-service/cmd/post-service/tools.go create mode 100644 services/post-service/go.mod create mode 100644 services/post-service/go.sum create mode 100644 services/post-service/internal/config.go create mode 100644 services/post-service/internal/errors.go create mode 100644 services/post-service/internal/kafka/consumers/panel.go create mode 100644 services/post-service/internal/kafka/consumers/panelv1/panel.pb.go create mode 100644 services/post-service/internal/kafka/consumers/panelv1/panel_grpc.pb.go create mode 100644 services/post-service/internal/kafka/consumers/user.go create mode 100644 services/post-service/internal/kafka/consumers/userv1/user.pb.go create mode 100644 services/post-service/internal/kafka/consumers/userv1/user_grpc.pb.go create mode 100644 services/post-service/internal/kafka/kafka.go create mode 100644 services/post-service/internal/kafka/producer/post.go create mode 100644 services/post-service/internal/post.go create mode 100644 services/post-service/internal/postgres/migrations/000001_initialise_db.down.sql create mode 100644 services/post-service/internal/postgres/migrations/000001_initialise_db.up.sql create mode 100644 services/post-service/internal/postgres/post.go create mode 100644 services/post-service/internal/postgres/postgres.go create mode 100644 services/post-service/internal/redis/post.go create mode 100644 services/post-service/internal/redis/redis.go create mode 100644 services/post-service/internal/rpc/post.go create mode 100644 services/post-service/internal/rpc/postv1/conversion.go create mode 100644 services/post-service/internal/rpc/postv1/post.pb.go create mode 100644 services/post-service/internal/rpc/postv1/post_grpc.pb.go create mode 100644 services/post-service/internal/rpc/rpc.go create mode 100644 services/post-service/internal/service/post.go diff --git a/services/post-service/.env.example b/services/post-service/.env.example new file mode 100644 index 0000000..a47c366 --- /dev/null +++ b/services/post-service/.env.example @@ -0,0 +1,11 @@ +POSTGRES_USER=postgres +POSTGRES_PASS=postgres +POSTGRES_HOST=localhost:5433 +POSTGRES_DATABASE=postgres + +REDIS_HOST=localhost:6380 +REDIS_PASS=redis + +KAFKA_BROKERS=localhost:9092 + +LOG_LEVEL=debug \ No newline at end of file diff --git a/services/post-service/Dockerfile b/services/post-service/Dockerfile new file mode 100644 index 0000000..04ce721 --- /dev/null +++ b/services/post-service/Dockerfile @@ -0,0 +1,17 @@ +FROM golang:1.20 AS build +WORKDIR /app + +# Install required modules +COPY go.mod go.sum ./ +RUN go mod download + +# Build the service +COPY . . +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /bin/post-service ./cmd/post-service + +# Runtime environment (for minifying image size) +FROM gcr.io/distroless/static-debian12 + +COPY --from=build /bin/post-service . +EXPOSE 9090 +CMD ["./post-service"] \ No newline at end of file diff --git a/services/post-service/Makefile b/services/post-service/Makefile new file mode 100644 index 0000000..3dbf865 --- /dev/null +++ b/services/post-service/Makefile @@ -0,0 +1,13 @@ +migration-new: + migrate create -ext sql -dir internal/postgres/migrations -seq ${MIGRATION_NAME} + +migration-upgrade: + migrate -path internal/postgres/migrations/ -database "postgres://${POSTGRES_USER}:${POSTGRES_PASS}@${POSTGRES_HOST}/${POSTGRES_DATABASE}?sslmode=disable" up + +migration-downgrade: + migrate -path internal/postgres/migrations/ -database "postgres://${POSTGRES_USER}:${POSTGRES_PASS}@${POSTGRES_HOST}/${POSTGRES_DATABASE}?sslmode=disable" down + +protobufs-compile: + protoc --proto_path=../../protobufs/ --go_out=. --go_opt=Mpost.proto=./internal/rpc/postv1 --go-grpc_out=. --go-grpc_opt=Mpost.proto=./internal/rpc/postv1 post.proto + protoc --proto_path=../../protobufs/ --go_out=. --go_opt=Muser.proto=./internal/kafka/consumers/userv1 --go-grpc_out=. --go-grpc_opt=Muser.proto=./internal/kafka/consumers/userv1 user.proto + protoc --proto_path=../../protobufs/ --go_out=. --go_opt=Mpanel.proto=./internal/kafka/consumers/panelv1 --go-grpc_out=. --go-grpc_opt=Mpanel.proto=./internal/kafka/consumers/panelv1 panel.proto \ No newline at end of file diff --git a/services/post-service/README.md b/services/post-service/README.md new file mode 100644 index 0000000..1fa62f8 --- /dev/null +++ b/services/post-service/README.md @@ -0,0 +1,65 @@ +# Post Service + +## Event Documentation + +* Events Produced: + * **Topic:** "``post``" | **Schema:** "``PostEvent``" protobuf + * Type: ``"created"`` | Data: ``Post`` + * Type: ``"updated"`` | Data: ``Post`` + * Type: ``"deleted"`` | Data: ``Post`` (only with ``Post.id`` attribute) + +* Events Consumed: + * **Topic:** "``panel``" | **Schema:** "``PanelEvent``" protobuf + * Type: ``"deleted"`` | Data: ``Post`` (only with ``Post.id`` attribute) + * **Topic:** "``user``" | **Schema:** "``UserEvent``" protobuf + * Type: ``"deleted"`` | Data: ``User`` + +## Configuration + +### Environment Variables + +**PostgreSQL:** + +``POSTGRES_USER`` (Required) + +* e.g. "postgres" + +``POSTGRES_PASS`` (Required) + +* e.g. "postgres" + +``POSTGRES_HOST`` (Required) + +* e.g. "localhost:5432" + +``POSTGRES_DATABASE`` (Required) + +* e.g. "postgres" + +--- + +**Redis:** + +``REDIS_HOST`` (Required) + +* e.g. "localhost:6379" + +``REDIS_PASS`` (Required) + +* e.g. "redis" + +--- + +**Kafka:** + +``KAFKA_BROKERS`` (Required) + +* e.g. "localhost:9092" or "localhost:9092,localhost:9093" + +--- + +**Other:** + +``LOG_LEVEL`` (Default: "info") + +* i.e. "debug", "info", "warn", "error", "fatal", "panic" or "disabled" diff --git a/services/post-service/cmd/post-service/main.go b/services/post-service/cmd/post-service/main.go new file mode 100644 index 0000000..ce6508a --- /dev/null +++ b/services/post-service/cmd/post-service/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + + "github.com/rs/zerolog" + + "github.com/hexolan/panels/post-service/internal" + "github.com/hexolan/panels/post-service/internal/postgres" + "github.com/hexolan/panels/post-service/internal/redis" + "github.com/hexolan/panels/post-service/internal/kafka" + "github.com/hexolan/panels/post-service/internal/kafka/producer" + "github.com/hexolan/panels/post-service/internal/rpc" + "github.com/hexolan/panels/post-service/internal/service" +) + +func main() { + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix + + // Load the configuration + cfg := internal.NewConfig() + zerolog.SetGlobalLevel(cfg.GetLogLevel()) + + // Create the interface dependencies + ctx := context.Background() + db := postgres.NewPostgresInterface(ctx, cfg) + rdb := redis.NewRedisInterface(ctx, cfg) + events := producer.NewPostEventProducer(cfg) + + // Create the repositories and services + dbRepo := postgres.NewPostRepository(db) + cacheRepo := redis.NewPostRepository(rdb, dbRepo) + service := service.NewPostService(events, cacheRepo) + + // Start the event consumers + eventConsumers := kafka.NewEventConsumers(cfg, dbRepo, events) + eventConsumers.Start() + + // Create and serve RPC + rpcServer := rpc.NewRPCServer(service) + rpcServer.Serve() +} \ No newline at end of file diff --git a/services/post-service/cmd/post-service/tools.go b/services/post-service/cmd/post-service/tools.go new file mode 100644 index 0000000..5c15732 --- /dev/null +++ b/services/post-service/cmd/post-service/tools.go @@ -0,0 +1,12 @@ +//go:build tools +package main + +import ( + // Protobuf Generation + _ "google.golang.org/protobuf/cmd/protoc-gen-go" + _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" + + // DB Migrations + _ "github.com/golang-migrate/migrate/v4" + _ "github.com/golang-migrate/migrate/v4/database/postgres" +) \ No newline at end of file diff --git a/services/post-service/go.mod b/services/post-service/go.mod new file mode 100644 index 0000000..567eb18 --- /dev/null +++ b/services/post-service/go.mod @@ -0,0 +1,40 @@ +module github.com/hexolan/panels/post-service + +go 1.20 + +require ( + github.com/doug-martin/goqu/v9 v9.18.0 + github.com/go-ozzo/ozzo-validation/v4 v4.3.0 + github.com/golang-migrate/migrate/v4 v4.16.2 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 + github.com/jackc/pgx/v5 v5.3.1 + github.com/redis/go-redis/v9 v9.0.5 + github.com/rs/zerolog v1.30.0 + github.com/segmentio/kafka-go v0.4.42 + google.golang.org/grpc v1.57.0 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/puddle/v2 v2.2.0 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/lib/pq v1.10.2 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/pierrec/lz4/v4 v4.1.16 // indirect + go.uber.org/atomic v1.7.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect +) diff --git a/services/post-service/go.sum b/services/post-service/go.sum new file mode 100644 index 0000000..d46e1a3 --- /dev/null +++ b/services/post-service/go.sum @@ -0,0 +1,163 @@ +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +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/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.3.16 h1:i6gq2YQEtcrjKbeJpBkWjE8MmLZPYllcjOFbTZuPDnw= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/doug-martin/goqu/v9 v9.18.0 h1:/6bcuEtAe6nsSMVK/M+fOiXUNfyFF3yYtE07DBPFMYY= +github.com/doug-martin/goqu/v9 v9.18.0/go.mod h1:nf0Wc2/hV3gYK9LiyqIrzBEVGlI8qW3GuDCEobC4wBQ= +github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= +github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/golang-migrate/migrate/v4 v4.16.2 h1:8coYbMKUyInrFk1lfGfRovTLAW7PhWp8qQDT2iKfuoA= +github.com/golang-migrate/migrate/v4 v4.16.2/go.mod h1:pfcJX4nPHaVdc5nmdCikFBWtm+UBpiZjRNNsyBbp0/o= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 h1:3IZOAnD058zZllQTZNBioTlrzrBG/IjpiZ133IEtusM= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5/go.mod h1:xbKERva94Pw2cPen0s79J3uXmGzbbpDYFBFDlZ4mV/w= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +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-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk= +github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.16 h1:kQPfno+wyx6C5572ABwV+Uo3pDFzQ7yhyGchSyRda0c= +github.com/pierrec/lz4/v4 v4.1.16/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= +github.com/segmentio/kafka-go v0.4.42 h1:qffhBZCz4WcWyNuHEclHjIMLs2slp6mZO8px+5W5tfU= +github.com/segmentio/kafka-go v0.4.42/go.mod h1:d0g15xPMqoUookug0OU75DhGZxXwCFxSLeJ4uphwJzg= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= +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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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= diff --git a/services/post-service/internal/config.go b/services/post-service/internal/config.go new file mode 100644 index 0000000..f75fc8e --- /dev/null +++ b/services/post-service/internal/config.go @@ -0,0 +1,89 @@ +package internal + +import ( + "os" + "fmt" + "strings" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func NewConfig() Config { + // Parse the log level + logLvl, err := zerolog.ParseLevel(optFromEnvFallback("LOG_LEVEL", "info")) + if err != nil { + log.Fatal().Err(err).Msg("invalid log level specified") + } + + // Parse the kafka brokers + kafkaBrokers := strings.Split(optFromEnvRequire("KAFKA_BROKERS"), ",") + if len(kafkaBrokers) == 0 { + log.Fatal().Err(err).Msg("no kafka brokers provided in configuration") + } + + // Create the config + cfg := Config{ + RedisHost: optFromEnvRequire("REDIS_HOST"), + RedisPass: optFromEnvRequire("REDIS_PASS"), + KafkaBrokers: kafkaBrokers, + LogLevel: logLvl, + } + + // Assemble the Config.PostgresURL + cfg.SetPostgresURL( + optFromEnvRequire("POSTGRES_USER"), + optFromEnvRequire("POSTGRES_PASS"), + optFromEnvRequire("POSTGRES_HOST"), + optFromEnvRequire("POSTGRES_DATABASE"), + ) + + return cfg +} + +func optFromEnv(opt string) *string { + optValue, exists := os.LookupEnv(opt) + if !exists || optValue == "" { + return nil + } + return &optValue +} + +func optFromEnvRequire(opt string) string { + optValue := optFromEnv(opt) + if optValue == nil { + log.Fatal().Str("option", opt).Msg("failed to load required config option") + } + return *optValue +} + +func optFromEnvFallback(opt string, fallback string) string { + optValue := optFromEnv(opt) + if optValue == nil { + return fallback + } + return *optValue +} + +type Config struct { + PostgresURL string + + RedisHost string + RedisPass string + + KafkaBrokers []string + + LogLevel zerolog.Level +} + +func (cfg *Config) SetPostgresURL(user string, pass string, host string, db string) { + cfg.PostgresURL = fmt.Sprintf("postgresql://%s:%s@%s/%s?sslmode=disable", user, pass, host, db) +} + +func (cfg Config) GetPostgresURL() string { + return cfg.PostgresURL +} + +func (cfg Config) GetLogLevel() zerolog.Level { + return cfg.LogLevel +} \ No newline at end of file diff --git a/services/post-service/internal/errors.go b/services/post-service/internal/errors.go new file mode 100644 index 0000000..620f874 --- /dev/null +++ b/services/post-service/internal/errors.go @@ -0,0 +1,80 @@ +package internal + +import ( + "fmt" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func NewServiceError(code ErrorCode, msg string) error { + return &ServiceError{ + code: code, + msg: msg, + } +} + +func NewServiceErrorf(code ErrorCode, msg string, args ...interface{}) error { + return NewServiceError(code, fmt.Sprintf(msg, args...)) +} + +func WrapServiceError(original_err error, code ErrorCode, msg string) error { + return &ServiceError{ + code: code, + msg: msg, + original_err: original_err, + } +} + +type ErrorCode int32 + +const ( + UnknownErrorCode ErrorCode = iota + NotFoundErrorCode + ConflictErrorCode + ForbiddenErrorCode + InvalidArgumentErrorCode + ConnectionErrorCode +) + +func (c ErrorCode) GRPCCode() codes.Code { + codeMap := map[ErrorCode]codes.Code{ + UnknownErrorCode: codes.Unknown, + NotFoundErrorCode: codes.NotFound, + ConflictErrorCode: codes.AlreadyExists, + ForbiddenErrorCode: codes.PermissionDenied, + InvalidArgumentErrorCode: codes.InvalidArgument, + ConnectionErrorCode: codes.Unavailable, + } + + grpcCode, mapped := codeMap[c] + if mapped { + return grpcCode + } + return codes.Unknown +} + +type ServiceError struct { + code ErrorCode + msg string + original_err error +} + +func (e ServiceError) Error() string { + if e.original_err != nil { + return fmt.Sprintf("%s: %s", e.msg, e.original_err.Error()) + } + return e.msg +} + +func (e ServiceError) Code() ErrorCode { + return e.code +} + +func (e ServiceError) GRPCStatus() *status.Status { + return status.New(e.Code().GRPCCode(), e.msg) +} + +func (e ServiceError) Unwrap() error { + return e.original_err +} \ No newline at end of file diff --git a/services/post-service/internal/kafka/consumers/panel.go b/services/post-service/internal/kafka/consumers/panel.go new file mode 100644 index 0000000..418970f --- /dev/null +++ b/services/post-service/internal/kafka/consumers/panel.go @@ -0,0 +1,76 @@ +package consumers + +import ( + "context" + + "github.com/rs/zerolog/log" + "github.com/segmentio/kafka-go" + "google.golang.org/protobuf/proto" + + "github.com/hexolan/panels/post-service/internal" + "github.com/hexolan/panels/post-service/internal/kafka/producer" + "github.com/hexolan/panels/post-service/internal/kafka/consumers/panelv1" +) + +type PanelEventConsumer struct { + reader *kafka.Reader + + dbRepo internal.PostDBRepository + eventProd producer.PostEventProducer +} + +func NewPanelEventConsumer(cfg internal.Config, dbRepo internal.PostDBRepository, eventProd producer.PostEventProducer) PanelEventConsumer { + return PanelEventConsumer{ + reader: kafka.NewReader(kafka.ReaderConfig{ + Brokers: cfg.KafkaBrokers, + GroupID: "post-service", + Topic: "panel", + }), + dbRepo: dbRepo, + eventProd: eventProd, + } +} + +func (ec PanelEventConsumer) ProcessEvent(evt *panelv1.PanelEvent) { + if evt.GetData() == nil { + log.Error().Str("src", "panel-event-consumer").Any("event", evt).Msg("no event data provided") + return + } + + if evt.Type == "deleted" { + postIds, err := ec.dbRepo.DeletePostsOnPanel(context.Background(), evt.GetData().GetId()) + if err == nil { + for _, postId := range postIds { + ec.eventProd.DispatchDeletedEvent(postId) + } + } + log.Debug().Str("src", "panel-event-consumer").Any("event", evt).Msg("processed panel deleted event") + } +} + +func (ec PanelEventConsumer) ProcessMessage(msg kafka.Message) { + var evt panelv1.PanelEvent + err := proto.Unmarshal(msg.Value, &evt) + if err != nil { + log.Error().Err(err).Str("src", "panel-event-consumer").Msg("failed to unmarshal event") + return + } + + ec.ProcessEvent(&evt) +} + +func (ec PanelEventConsumer) Start() { + for { + msg, err := ec.reader.FetchMessage(context.Background()) + if err != nil { + log.Error().Err(err).Str("src", "panel-event-consumer").Msg("failed to fetch msg from Kafka") + break + } + ec.ProcessMessage(msg) + } + + // Attempt to close the reader connection (after experiencing a Kafka error) + if err := ec.reader.Close(); err != nil { + log.Panic().Err(err).Str("src", "panel-event-consumer").Msg("failed to close Kafka reader") + } +} \ No newline at end of file diff --git a/services/post-service/internal/kafka/consumers/panelv1/panel.pb.go b/services/post-service/internal/kafka/consumers/panelv1/panel.pb.go new file mode 100644 index 0000000..aab4723 --- /dev/null +++ b/services/post-service/internal/kafka/consumers/panelv1/panel.pb.go @@ -0,0 +1,861 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v4.23.4 +// source: panel.proto + +package panelv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +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 Panel struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` +} + +func (x *Panel) Reset() { + *x = Panel{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Panel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Panel) ProtoMessage() {} + +func (x *Panel) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Panel.ProtoReflect.Descriptor instead. +func (*Panel) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{0} +} + +func (x *Panel) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Panel) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Panel) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Panel) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Panel) GetUpdatedAt() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type PanelMutable struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name *string `protobuf:"bytes,1,opt,name=name,proto3,oneof" json:"name,omitempty"` + Description *string `protobuf:"bytes,2,opt,name=description,proto3,oneof" json:"description,omitempty"` +} + +func (x *PanelMutable) Reset() { + *x = PanelMutable{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PanelMutable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PanelMutable) ProtoMessage() {} + +func (x *PanelMutable) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PanelMutable.ProtoReflect.Descriptor instead. +func (*PanelMutable) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{1} +} + +func (x *PanelMutable) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *PanelMutable) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +type CreatePanelRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data *PanelMutable `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *CreatePanelRequest) Reset() { + *x = CreatePanelRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreatePanelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreatePanelRequest) ProtoMessage() {} + +func (x *CreatePanelRequest) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreatePanelRequest.ProtoReflect.Descriptor instead. +func (*CreatePanelRequest) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{2} +} + +func (x *CreatePanelRequest) GetData() *PanelMutable { + if x != nil { + return x.Data + } + return nil +} + +type GetPanelByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *GetPanelByIdRequest) Reset() { + *x = GetPanelByIdRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPanelByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPanelByIdRequest) ProtoMessage() {} + +func (x *GetPanelByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPanelByIdRequest.ProtoReflect.Descriptor instead. +func (*GetPanelByIdRequest) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{3} +} + +func (x *GetPanelByIdRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetPanelByNameRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *GetPanelByNameRequest) Reset() { + *x = GetPanelByNameRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPanelByNameRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPanelByNameRequest) ProtoMessage() {} + +func (x *GetPanelByNameRequest) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPanelByNameRequest.ProtoReflect.Descriptor instead. +func (*GetPanelByNameRequest) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{4} +} + +func (x *GetPanelByNameRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type UpdatePanelByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Data *PanelMutable `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *UpdatePanelByIdRequest) Reset() { + *x = UpdatePanelByIdRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdatePanelByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePanelByIdRequest) ProtoMessage() {} + +func (x *UpdatePanelByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePanelByIdRequest.ProtoReflect.Descriptor instead. +func (*UpdatePanelByIdRequest) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{5} +} + +func (x *UpdatePanelByIdRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdatePanelByIdRequest) GetData() *PanelMutable { + if x != nil { + return x.Data + } + return nil +} + +type UpdatePanelByNameRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Data *PanelMutable `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *UpdatePanelByNameRequest) Reset() { + *x = UpdatePanelByNameRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdatePanelByNameRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePanelByNameRequest) ProtoMessage() {} + +func (x *UpdatePanelByNameRequest) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePanelByNameRequest.ProtoReflect.Descriptor instead. +func (*UpdatePanelByNameRequest) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdatePanelByNameRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdatePanelByNameRequest) GetData() *PanelMutable { + if x != nil { + return x.Data + } + return nil +} + +type DeletePanelByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *DeletePanelByIdRequest) Reset() { + *x = DeletePanelByIdRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeletePanelByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePanelByIdRequest) ProtoMessage() {} + +func (x *DeletePanelByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletePanelByIdRequest.ProtoReflect.Descriptor instead. +func (*DeletePanelByIdRequest) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{7} +} + +func (x *DeletePanelByIdRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type DeletePanelByNameRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *DeletePanelByNameRequest) Reset() { + *x = DeletePanelByNameRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeletePanelByNameRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePanelByNameRequest) ProtoMessage() {} + +func (x *DeletePanelByNameRequest) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletePanelByNameRequest.ProtoReflect.Descriptor instead. +func (*DeletePanelByNameRequest) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{8} +} + +func (x *DeletePanelByNameRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Kafka Event Schema +type PanelEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Data *Panel `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *PanelEvent) Reset() { + *x = PanelEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_panel_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PanelEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PanelEvent) ProtoMessage() {} + +func (x *PanelEvent) ProtoReflect() protoreflect.Message { + mi := &file_panel_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PanelEvent.ProtoReflect.Descriptor instead. +func (*PanelEvent) Descriptor() ([]byte, []int) { + return file_panel_proto_rawDescGZIP(), []int{9} +} + +func (x *PanelEvent) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *PanelEvent) GetData() *Panel { + if x != nil { + return x.Data + } + return nil +} + +var File_panel_proto protoreflect.FileDescriptor + +var file_panel_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x1a, 0x1b, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x01, 0x0a, + 0x05, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x22, 0x67, 0x0a, 0x0c, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4d, 0x75, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, + 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x47, 0x0a, 0x12, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x31, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, + 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2b, 0x0a, 0x15, 0x47, + 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5b, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x31, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x61, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, + 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4d, 0x75, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x28, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x22, 0x2e, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, + 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x22, 0x4c, 0x0a, 0x0a, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x32, 0xd4, 0x04, 0x0a, 0x0c, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, + 0x12, 0x23, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x22, 0x00, 0x12, + 0x4a, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x12, 0x24, 0x2e, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0e, 0x47, + 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x2e, + 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x22, 0x00, 0x12, + 0x50, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x12, 0x27, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x49, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x22, + 0x00, 0x12, 0x58, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, + 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, + 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0b, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x12, 0x27, 0x2e, 0x70, 0x61, 0x6e, + 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x58, 0x0a, + 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x42, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x29, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x6e, 0x65, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x6e, 0x65, 0x6c, + 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_panel_proto_rawDescOnce sync.Once + file_panel_proto_rawDescData = file_panel_proto_rawDesc +) + +func file_panel_proto_rawDescGZIP() []byte { + file_panel_proto_rawDescOnce.Do(func() { + file_panel_proto_rawDescData = protoimpl.X.CompressGZIP(file_panel_proto_rawDescData) + }) + return file_panel_proto_rawDescData +} + +var file_panel_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_panel_proto_goTypes = []interface{}{ + (*Panel)(nil), // 0: panels.panel.v1.Panel + (*PanelMutable)(nil), // 1: panels.panel.v1.PanelMutable + (*CreatePanelRequest)(nil), // 2: panels.panel.v1.CreatePanelRequest + (*GetPanelByIdRequest)(nil), // 3: panels.panel.v1.GetPanelByIdRequest + (*GetPanelByNameRequest)(nil), // 4: panels.panel.v1.GetPanelByNameRequest + (*UpdatePanelByIdRequest)(nil), // 5: panels.panel.v1.UpdatePanelByIdRequest + (*UpdatePanelByNameRequest)(nil), // 6: panels.panel.v1.UpdatePanelByNameRequest + (*DeletePanelByIdRequest)(nil), // 7: panels.panel.v1.DeletePanelByIdRequest + (*DeletePanelByNameRequest)(nil), // 8: panels.panel.v1.DeletePanelByNameRequest + (*PanelEvent)(nil), // 9: panels.panel.v1.PanelEvent + (*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 11: google.protobuf.Empty +} +var file_panel_proto_depIdxs = []int32{ + 10, // 0: panels.panel.v1.Panel.created_at:type_name -> google.protobuf.Timestamp + 10, // 1: panels.panel.v1.Panel.updated_at:type_name -> google.protobuf.Timestamp + 1, // 2: panels.panel.v1.CreatePanelRequest.data:type_name -> panels.panel.v1.PanelMutable + 1, // 3: panels.panel.v1.UpdatePanelByIdRequest.data:type_name -> panels.panel.v1.PanelMutable + 1, // 4: panels.panel.v1.UpdatePanelByNameRequest.data:type_name -> panels.panel.v1.PanelMutable + 0, // 5: panels.panel.v1.PanelEvent.data:type_name -> panels.panel.v1.Panel + 2, // 6: panels.panel.v1.PanelService.CreatePanel:input_type -> panels.panel.v1.CreatePanelRequest + 3, // 7: panels.panel.v1.PanelService.GetPanel:input_type -> panels.panel.v1.GetPanelByIdRequest + 4, // 8: panels.panel.v1.PanelService.GetPanelByName:input_type -> panels.panel.v1.GetPanelByNameRequest + 5, // 9: panels.panel.v1.PanelService.UpdatePanel:input_type -> panels.panel.v1.UpdatePanelByIdRequest + 6, // 10: panels.panel.v1.PanelService.UpdatePanelByName:input_type -> panels.panel.v1.UpdatePanelByNameRequest + 7, // 11: panels.panel.v1.PanelService.DeletePanel:input_type -> panels.panel.v1.DeletePanelByIdRequest + 8, // 12: panels.panel.v1.PanelService.DeletePanelByName:input_type -> panels.panel.v1.DeletePanelByNameRequest + 0, // 13: panels.panel.v1.PanelService.CreatePanel:output_type -> panels.panel.v1.Panel + 0, // 14: panels.panel.v1.PanelService.GetPanel:output_type -> panels.panel.v1.Panel + 0, // 15: panels.panel.v1.PanelService.GetPanelByName:output_type -> panels.panel.v1.Panel + 0, // 16: panels.panel.v1.PanelService.UpdatePanel:output_type -> panels.panel.v1.Panel + 0, // 17: panels.panel.v1.PanelService.UpdatePanelByName:output_type -> panels.panel.v1.Panel + 11, // 18: panels.panel.v1.PanelService.DeletePanel:output_type -> google.protobuf.Empty + 11, // 19: panels.panel.v1.PanelService.DeletePanelByName:output_type -> google.protobuf.Empty + 13, // [13:20] is the sub-list for method output_type + 6, // [6:13] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_panel_proto_init() } +func file_panel_proto_init() { + if File_panel_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_panel_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Panel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PanelMutable); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreatePanelRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPanelByIdRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPanelByNameRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdatePanelByIdRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdatePanelByNameRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeletePanelByIdRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeletePanelByNameRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_panel_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PanelEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_panel_proto_msgTypes[1].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_panel_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_panel_proto_goTypes, + DependencyIndexes: file_panel_proto_depIdxs, + MessageInfos: file_panel_proto_msgTypes, + }.Build() + File_panel_proto = out.File + file_panel_proto_rawDesc = nil + file_panel_proto_goTypes = nil + file_panel_proto_depIdxs = nil +} diff --git a/services/post-service/internal/kafka/consumers/panelv1/panel_grpc.pb.go b/services/post-service/internal/kafka/consumers/panelv1/panel_grpc.pb.go new file mode 100644 index 0000000..74a0694 --- /dev/null +++ b/services/post-service/internal/kafka/consumers/panelv1/panel_grpc.pb.go @@ -0,0 +1,322 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v4.23.4 +// source: panel.proto + +package panelv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// 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.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// PanelServiceClient is the client API for PanelService 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 PanelServiceClient interface { + CreatePanel(ctx context.Context, in *CreatePanelRequest, opts ...grpc.CallOption) (*Panel, error) + GetPanel(ctx context.Context, in *GetPanelByIdRequest, opts ...grpc.CallOption) (*Panel, error) + GetPanelByName(ctx context.Context, in *GetPanelByNameRequest, opts ...grpc.CallOption) (*Panel, error) + UpdatePanel(ctx context.Context, in *UpdatePanelByIdRequest, opts ...grpc.CallOption) (*Panel, error) + UpdatePanelByName(ctx context.Context, in *UpdatePanelByNameRequest, opts ...grpc.CallOption) (*Panel, error) + DeletePanel(ctx context.Context, in *DeletePanelByIdRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + DeletePanelByName(ctx context.Context, in *DeletePanelByNameRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) +} + +type panelServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewPanelServiceClient(cc grpc.ClientConnInterface) PanelServiceClient { + return &panelServiceClient{cc} +} + +func (c *panelServiceClient) CreatePanel(ctx context.Context, in *CreatePanelRequest, opts ...grpc.CallOption) (*Panel, error) { + out := new(Panel) + err := c.cc.Invoke(ctx, "/panels.panel.v1.PanelService/CreatePanel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *panelServiceClient) GetPanel(ctx context.Context, in *GetPanelByIdRequest, opts ...grpc.CallOption) (*Panel, error) { + out := new(Panel) + err := c.cc.Invoke(ctx, "/panels.panel.v1.PanelService/GetPanel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *panelServiceClient) GetPanelByName(ctx context.Context, in *GetPanelByNameRequest, opts ...grpc.CallOption) (*Panel, error) { + out := new(Panel) + err := c.cc.Invoke(ctx, "/panels.panel.v1.PanelService/GetPanelByName", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *panelServiceClient) UpdatePanel(ctx context.Context, in *UpdatePanelByIdRequest, opts ...grpc.CallOption) (*Panel, error) { + out := new(Panel) + err := c.cc.Invoke(ctx, "/panels.panel.v1.PanelService/UpdatePanel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *panelServiceClient) UpdatePanelByName(ctx context.Context, in *UpdatePanelByNameRequest, opts ...grpc.CallOption) (*Panel, error) { + out := new(Panel) + err := c.cc.Invoke(ctx, "/panels.panel.v1.PanelService/UpdatePanelByName", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *panelServiceClient) DeletePanel(ctx context.Context, in *DeletePanelByIdRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/panels.panel.v1.PanelService/DeletePanel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *panelServiceClient) DeletePanelByName(ctx context.Context, in *DeletePanelByNameRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/panels.panel.v1.PanelService/DeletePanelByName", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PanelServiceServer is the server API for PanelService service. +// All implementations must embed UnimplementedPanelServiceServer +// for forward compatibility +type PanelServiceServer interface { + CreatePanel(context.Context, *CreatePanelRequest) (*Panel, error) + GetPanel(context.Context, *GetPanelByIdRequest) (*Panel, error) + GetPanelByName(context.Context, *GetPanelByNameRequest) (*Panel, error) + UpdatePanel(context.Context, *UpdatePanelByIdRequest) (*Panel, error) + UpdatePanelByName(context.Context, *UpdatePanelByNameRequest) (*Panel, error) + DeletePanel(context.Context, *DeletePanelByIdRequest) (*emptypb.Empty, error) + DeletePanelByName(context.Context, *DeletePanelByNameRequest) (*emptypb.Empty, error) + mustEmbedUnimplementedPanelServiceServer() +} + +// UnimplementedPanelServiceServer must be embedded to have forward compatible implementations. +type UnimplementedPanelServiceServer struct { +} + +func (UnimplementedPanelServiceServer) CreatePanel(context.Context, *CreatePanelRequest) (*Panel, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreatePanel not implemented") +} +func (UnimplementedPanelServiceServer) GetPanel(context.Context, *GetPanelByIdRequest) (*Panel, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPanel not implemented") +} +func (UnimplementedPanelServiceServer) GetPanelByName(context.Context, *GetPanelByNameRequest) (*Panel, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPanelByName not implemented") +} +func (UnimplementedPanelServiceServer) UpdatePanel(context.Context, *UpdatePanelByIdRequest) (*Panel, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdatePanel not implemented") +} +func (UnimplementedPanelServiceServer) UpdatePanelByName(context.Context, *UpdatePanelByNameRequest) (*Panel, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdatePanelByName not implemented") +} +func (UnimplementedPanelServiceServer) DeletePanel(context.Context, *DeletePanelByIdRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeletePanel not implemented") +} +func (UnimplementedPanelServiceServer) DeletePanelByName(context.Context, *DeletePanelByNameRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeletePanelByName not implemented") +} +func (UnimplementedPanelServiceServer) mustEmbedUnimplementedPanelServiceServer() {} + +// UnsafePanelServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PanelServiceServer will +// result in compilation errors. +type UnsafePanelServiceServer interface { + mustEmbedUnimplementedPanelServiceServer() +} + +func RegisterPanelServiceServer(s grpc.ServiceRegistrar, srv PanelServiceServer) { + s.RegisterService(&PanelService_ServiceDesc, srv) +} + +func _PanelService_CreatePanel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreatePanelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PanelServiceServer).CreatePanel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.panel.v1.PanelService/CreatePanel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PanelServiceServer).CreatePanel(ctx, req.(*CreatePanelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PanelService_GetPanel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPanelByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PanelServiceServer).GetPanel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.panel.v1.PanelService/GetPanel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PanelServiceServer).GetPanel(ctx, req.(*GetPanelByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PanelService_GetPanelByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPanelByNameRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PanelServiceServer).GetPanelByName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.panel.v1.PanelService/GetPanelByName", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PanelServiceServer).GetPanelByName(ctx, req.(*GetPanelByNameRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PanelService_UpdatePanel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdatePanelByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PanelServiceServer).UpdatePanel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.panel.v1.PanelService/UpdatePanel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PanelServiceServer).UpdatePanel(ctx, req.(*UpdatePanelByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PanelService_UpdatePanelByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdatePanelByNameRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PanelServiceServer).UpdatePanelByName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.panel.v1.PanelService/UpdatePanelByName", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PanelServiceServer).UpdatePanelByName(ctx, req.(*UpdatePanelByNameRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PanelService_DeletePanel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeletePanelByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PanelServiceServer).DeletePanel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.panel.v1.PanelService/DeletePanel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PanelServiceServer).DeletePanel(ctx, req.(*DeletePanelByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PanelService_DeletePanelByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeletePanelByNameRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PanelServiceServer).DeletePanelByName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.panel.v1.PanelService/DeletePanelByName", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PanelServiceServer).DeletePanelByName(ctx, req.(*DeletePanelByNameRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// PanelService_ServiceDesc is the grpc.ServiceDesc for PanelService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PanelService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "panels.panel.v1.PanelService", + HandlerType: (*PanelServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreatePanel", + Handler: _PanelService_CreatePanel_Handler, + }, + { + MethodName: "GetPanel", + Handler: _PanelService_GetPanel_Handler, + }, + { + MethodName: "GetPanelByName", + Handler: _PanelService_GetPanelByName_Handler, + }, + { + MethodName: "UpdatePanel", + Handler: _PanelService_UpdatePanel_Handler, + }, + { + MethodName: "UpdatePanelByName", + Handler: _PanelService_UpdatePanelByName_Handler, + }, + { + MethodName: "DeletePanel", + Handler: _PanelService_DeletePanel_Handler, + }, + { + MethodName: "DeletePanelByName", + Handler: _PanelService_DeletePanelByName_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "panel.proto", +} diff --git a/services/post-service/internal/kafka/consumers/user.go b/services/post-service/internal/kafka/consumers/user.go new file mode 100644 index 0000000..b8c769d --- /dev/null +++ b/services/post-service/internal/kafka/consumers/user.go @@ -0,0 +1,75 @@ +package consumers + +import ( + "context" + + "github.com/rs/zerolog/log" + "github.com/segmentio/kafka-go" + "google.golang.org/protobuf/proto" + + "github.com/hexolan/panels/post-service/internal" + "github.com/hexolan/panels/post-service/internal/kafka/producer" + "github.com/hexolan/panels/post-service/internal/kafka/consumers/userv1" +) + +type UserEventConsumer struct { + reader *kafka.Reader + + dbRepo internal.PostDBRepository + eventProd producer.PostEventProducer +} + +func NewUserEventConsumer(cfg internal.Config, dbRepo internal.PostDBRepository, eventProd producer.PostEventProducer) UserEventConsumer { + return UserEventConsumer{ + reader: kafka.NewReader(kafka.ReaderConfig{ + Brokers: cfg.KafkaBrokers, + GroupID: "post-service", + Topic: "user", + }), + dbRepo: dbRepo, + } +} + +func (ec UserEventConsumer) ProcessEvent(evt *userv1.UserEvent) { + if evt.GetData() == nil { + log.Error().Str("src", "user-event-consumer").Any("event", evt).Msg("no event data provided") + return + } + + if evt.Type == "deleted" { + postIds, err := ec.dbRepo.DeletePostsByUser(context.Background(), evt.GetData().GetId()) + if err == nil { + for _, postId := range postIds { + ec.eventProd.DispatchDeletedEvent(postId) + } + } + log.Debug().Str("src", "user-event-consumer").Any("event", evt).Msg("processed user deleted event") + } +} + +func (ec UserEventConsumer) ProcessMessage(msg kafka.Message) { + var evt userv1.UserEvent + err := proto.Unmarshal(msg.Value, &evt) + if err != nil { + log.Error().Err(err).Str("src", "user-event-consumer").Msg("failed to unmarshal event") + return + } + + ec.ProcessEvent(&evt) +} + +func (ec UserEventConsumer) Start() { + for { + msg, err := ec.reader.FetchMessage(context.Background()) + if err != nil { + log.Error().Err(err).Str("src", "user-event-consumer").Msg("failed to fetch msg from Kafka") + break + } + ec.ProcessMessage(msg) + } + + // Attempt to close the reader connection (after experiencing a Kafka error) + if err := ec.reader.Close(); err != nil { + log.Panic().Err(err).Str("src", "user-event-consumer").Msg("failed to close Kafka reader") + } +} \ No newline at end of file diff --git a/services/post-service/internal/kafka/consumers/userv1/user.pb.go b/services/post-service/internal/kafka/consumers/userv1/user.pb.go new file mode 100644 index 0000000..bb9c12a --- /dev/null +++ b/services/post-service/internal/kafka/consumers/userv1/user.pb.go @@ -0,0 +1,849 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v4.23.4 +// source: user.proto + +package userv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +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 User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + IsAdmin bool `protobuf:"varint,3,opt,name=is_admin,json=isAdmin,proto3" json:"is_admin,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{0} +} + +func (x *User) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *User) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *User) GetIsAdmin() bool { + if x != nil { + return x.IsAdmin + } + return false +} + +func (x *User) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *User) GetUpdatedAt() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type UserMutable struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username *string `protobuf:"bytes,1,opt,name=username,proto3,oneof" json:"username,omitempty"` +} + +func (x *UserMutable) Reset() { + *x = UserMutable{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserMutable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserMutable) ProtoMessage() {} + +func (x *UserMutable) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserMutable.ProtoReflect.Descriptor instead. +func (*UserMutable) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{1} +} + +func (x *UserMutable) GetUsername() string { + if x != nil && x.Username != nil { + return *x.Username + } + return "" +} + +type CreateUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data *UserMutable `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *CreateUserRequest) Reset() { + *x = CreateUserRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateUserRequest) ProtoMessage() {} + +func (x *CreateUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateUserRequest.ProtoReflect.Descriptor instead. +func (*CreateUserRequest) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateUserRequest) GetData() *UserMutable { + if x != nil { + return x.Data + } + return nil +} + +type GetUserByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *GetUserByIdRequest) Reset() { + *x = GetUserByIdRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserByIdRequest) ProtoMessage() {} + +func (x *GetUserByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserByIdRequest.ProtoReflect.Descriptor instead. +func (*GetUserByIdRequest) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{3} +} + +func (x *GetUserByIdRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetUserByNameRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` +} + +func (x *GetUserByNameRequest) Reset() { + *x = GetUserByNameRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserByNameRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserByNameRequest) ProtoMessage() {} + +func (x *GetUserByNameRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserByNameRequest.ProtoReflect.Descriptor instead. +func (*GetUserByNameRequest) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{4} +} + +func (x *GetUserByNameRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +type UpdateUserByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Data *UserMutable `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *UpdateUserByIdRequest) Reset() { + *x = UpdateUserByIdRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserByIdRequest) ProtoMessage() {} + +func (x *UpdateUserByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserByIdRequest.ProtoReflect.Descriptor instead. +func (*UpdateUserByIdRequest) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{5} +} + +func (x *UpdateUserByIdRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateUserByIdRequest) GetData() *UserMutable { + if x != nil { + return x.Data + } + return nil +} + +type UpdateUserByNameRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Data *UserMutable `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *UpdateUserByNameRequest) Reset() { + *x = UpdateUserByNameRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserByNameRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserByNameRequest) ProtoMessage() {} + +func (x *UpdateUserByNameRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserByNameRequest.ProtoReflect.Descriptor instead. +func (*UpdateUserByNameRequest) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateUserByNameRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *UpdateUserByNameRequest) GetData() *UserMutable { + if x != nil { + return x.Data + } + return nil +} + +type DeleteUserByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *DeleteUserByIdRequest) Reset() { + *x = DeleteUserByIdRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteUserByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserByIdRequest) ProtoMessage() {} + +func (x *DeleteUserByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteUserByIdRequest.ProtoReflect.Descriptor instead. +func (*DeleteUserByIdRequest) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{7} +} + +func (x *DeleteUserByIdRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type DeleteUserByNameRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` +} + +func (x *DeleteUserByNameRequest) Reset() { + *x = DeleteUserByNameRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteUserByNameRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserByNameRequest) ProtoMessage() {} + +func (x *DeleteUserByNameRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteUserByNameRequest.ProtoReflect.Descriptor instead. +func (*DeleteUserByNameRequest) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{8} +} + +func (x *DeleteUserByNameRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +// Kafka Event Schema +type UserEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Data *User `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *UserEvent) Reset() { + *x = UserEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserEvent) ProtoMessage() {} + +func (x *UserEvent) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserEvent.ProtoReflect.Descriptor instead. +func (*UserEvent) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{9} +} + +func (x *UserEvent) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *UserEvent) GetData() *User { + if x != nil { + return x.Data + } + return nil +} + +var File_user_proto protoreflect.FileDescriptor + +var file_user_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, + 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x01, 0x0a, 0x04, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x22, 0x3b, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, + 0x1f, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, + 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x44, 0x0a, + 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x22, 0x24, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, + 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x32, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x58, 0x0a, + 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x49, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x66, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, + 0x27, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x49, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x35, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x49, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0xb4, 0x04, 0x0a, 0x0b, 0x55, + 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, + 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x22, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x2e, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0a, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x25, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x2e, 0x70, 0x61, 0x6e, + 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0a, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x25, 0x2e, 0x70, 0x61, 0x6e, 0x65, + 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x10, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, + 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_user_proto_rawDescOnce sync.Once + file_user_proto_rawDescData = file_user_proto_rawDesc +) + +func file_user_proto_rawDescGZIP() []byte { + file_user_proto_rawDescOnce.Do(func() { + file_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_proto_rawDescData) + }) + return file_user_proto_rawDescData +} + +var file_user_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_user_proto_goTypes = []interface{}{ + (*User)(nil), // 0: panels.user.v1.User + (*UserMutable)(nil), // 1: panels.user.v1.UserMutable + (*CreateUserRequest)(nil), // 2: panels.user.v1.CreateUserRequest + (*GetUserByIdRequest)(nil), // 3: panels.user.v1.GetUserByIdRequest + (*GetUserByNameRequest)(nil), // 4: panels.user.v1.GetUserByNameRequest + (*UpdateUserByIdRequest)(nil), // 5: panels.user.v1.UpdateUserByIdRequest + (*UpdateUserByNameRequest)(nil), // 6: panels.user.v1.UpdateUserByNameRequest + (*DeleteUserByIdRequest)(nil), // 7: panels.user.v1.DeleteUserByIdRequest + (*DeleteUserByNameRequest)(nil), // 8: panels.user.v1.DeleteUserByNameRequest + (*UserEvent)(nil), // 9: panels.user.v1.UserEvent + (*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 11: google.protobuf.Empty +} +var file_user_proto_depIdxs = []int32{ + 10, // 0: panels.user.v1.User.created_at:type_name -> google.protobuf.Timestamp + 10, // 1: panels.user.v1.User.updated_at:type_name -> google.protobuf.Timestamp + 1, // 2: panels.user.v1.CreateUserRequest.data:type_name -> panels.user.v1.UserMutable + 1, // 3: panels.user.v1.UpdateUserByIdRequest.data:type_name -> panels.user.v1.UserMutable + 1, // 4: panels.user.v1.UpdateUserByNameRequest.data:type_name -> panels.user.v1.UserMutable + 0, // 5: panels.user.v1.UserEvent.data:type_name -> panels.user.v1.User + 2, // 6: panels.user.v1.UserService.CreateUser:input_type -> panels.user.v1.CreateUserRequest + 3, // 7: panels.user.v1.UserService.GetUser:input_type -> panels.user.v1.GetUserByIdRequest + 4, // 8: panels.user.v1.UserService.GetUserByName:input_type -> panels.user.v1.GetUserByNameRequest + 5, // 9: panels.user.v1.UserService.UpdateUser:input_type -> panels.user.v1.UpdateUserByIdRequest + 6, // 10: panels.user.v1.UserService.UpdateUserByName:input_type -> panels.user.v1.UpdateUserByNameRequest + 7, // 11: panels.user.v1.UserService.DeleteUser:input_type -> panels.user.v1.DeleteUserByIdRequest + 8, // 12: panels.user.v1.UserService.DeleteUserByName:input_type -> panels.user.v1.DeleteUserByNameRequest + 0, // 13: panels.user.v1.UserService.CreateUser:output_type -> panels.user.v1.User + 0, // 14: panels.user.v1.UserService.GetUser:output_type -> panels.user.v1.User + 0, // 15: panels.user.v1.UserService.GetUserByName:output_type -> panels.user.v1.User + 0, // 16: panels.user.v1.UserService.UpdateUser:output_type -> panels.user.v1.User + 0, // 17: panels.user.v1.UserService.UpdateUserByName:output_type -> panels.user.v1.User + 11, // 18: panels.user.v1.UserService.DeleteUser:output_type -> google.protobuf.Empty + 11, // 19: panels.user.v1.UserService.DeleteUserByName:output_type -> google.protobuf.Empty + 13, // [13:20] is the sub-list for method output_type + 6, // [6:13] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_user_proto_init() } +func file_user_proto_init() { + if File_user_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserMutable); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserByIdRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserByNameRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserByIdRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserByNameRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteUserByIdRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteUserByNameRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_user_proto_msgTypes[1].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_user_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_user_proto_goTypes, + DependencyIndexes: file_user_proto_depIdxs, + MessageInfos: file_user_proto_msgTypes, + }.Build() + File_user_proto = out.File + file_user_proto_rawDesc = nil + file_user_proto_goTypes = nil + file_user_proto_depIdxs = nil +} diff --git a/services/post-service/internal/kafka/consumers/userv1/user_grpc.pb.go b/services/post-service/internal/kafka/consumers/userv1/user_grpc.pb.go new file mode 100644 index 0000000..a2cfefa --- /dev/null +++ b/services/post-service/internal/kafka/consumers/userv1/user_grpc.pb.go @@ -0,0 +1,322 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v4.23.4 +// source: user.proto + +package userv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// 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.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// UserServiceClient is the client API for UserService 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 UserServiceClient interface { + CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*User, error) + GetUser(ctx context.Context, in *GetUserByIdRequest, opts ...grpc.CallOption) (*User, error) + GetUserByName(ctx context.Context, in *GetUserByNameRequest, opts ...grpc.CallOption) (*User, error) + UpdateUser(ctx context.Context, in *UpdateUserByIdRequest, opts ...grpc.CallOption) (*User, error) + UpdateUserByName(ctx context.Context, in *UpdateUserByNameRequest, opts ...grpc.CallOption) (*User, error) + DeleteUser(ctx context.Context, in *DeleteUserByIdRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + DeleteUserByName(ctx context.Context, in *DeleteUserByNameRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) +} + +type userServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient { + return &userServiceClient{cc} +} + +func (c *userServiceClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/panels.user.v1.UserService/CreateUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserByIdRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/panels.user.v1.UserService/GetUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) GetUserByName(ctx context.Context, in *GetUserByNameRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/panels.user.v1.UserService/GetUserByName", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) UpdateUser(ctx context.Context, in *UpdateUserByIdRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/panels.user.v1.UserService/UpdateUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) UpdateUserByName(ctx context.Context, in *UpdateUserByNameRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/panels.user.v1.UserService/UpdateUserByName", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) DeleteUser(ctx context.Context, in *DeleteUserByIdRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/panels.user.v1.UserService/DeleteUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) DeleteUserByName(ctx context.Context, in *DeleteUserByNameRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/panels.user.v1.UserService/DeleteUserByName", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServiceServer is the server API for UserService service. +// All implementations must embed UnimplementedUserServiceServer +// for forward compatibility +type UserServiceServer interface { + CreateUser(context.Context, *CreateUserRequest) (*User, error) + GetUser(context.Context, *GetUserByIdRequest) (*User, error) + GetUserByName(context.Context, *GetUserByNameRequest) (*User, error) + UpdateUser(context.Context, *UpdateUserByIdRequest) (*User, error) + UpdateUserByName(context.Context, *UpdateUserByNameRequest) (*User, error) + DeleteUser(context.Context, *DeleteUserByIdRequest) (*emptypb.Empty, error) + DeleteUserByName(context.Context, *DeleteUserByNameRequest) (*emptypb.Empty, error) + mustEmbedUnimplementedUserServiceServer() +} + +// UnimplementedUserServiceServer must be embedded to have forward compatible implementations. +type UnimplementedUserServiceServer struct { +} + +func (UnimplementedUserServiceServer) CreateUser(context.Context, *CreateUserRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateUser not implemented") +} +func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserByIdRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") +} +func (UnimplementedUserServiceServer) GetUserByName(context.Context, *GetUserByNameRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserByName not implemented") +} +func (UnimplementedUserServiceServer) UpdateUser(context.Context, *UpdateUserByIdRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUser not implemented") +} +func (UnimplementedUserServiceServer) UpdateUserByName(context.Context, *UpdateUserByNameRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUserByName not implemented") +} +func (UnimplementedUserServiceServer) DeleteUser(context.Context, *DeleteUserByIdRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteUser not implemented") +} +func (UnimplementedUserServiceServer) DeleteUserByName(context.Context, *DeleteUserByNameRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteUserByName not implemented") +} +func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {} + +// UnsafeUserServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserServiceServer will +// result in compilation errors. +type UnsafeUserServiceServer interface { + mustEmbedUnimplementedUserServiceServer() +} + +func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) { + s.RegisterService(&UserService_ServiceDesc, srv) +} + +func _UserService_CreateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).CreateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.user.v1.UserService/CreateUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).CreateUser(ctx, req.(*CreateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).GetUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.user.v1.UserService/GetUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).GetUser(ctx, req.(*GetUserByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_GetUserByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserByNameRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).GetUserByName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.user.v1.UserService/GetUserByName", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).GetUserByName(ctx, req.(*GetUserByNameRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_UpdateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).UpdateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.user.v1.UserService/UpdateUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).UpdateUser(ctx, req.(*UpdateUserByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_UpdateUserByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserByNameRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).UpdateUserByName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.user.v1.UserService/UpdateUserByName", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).UpdateUserByName(ctx, req.(*UpdateUserByNameRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_DeleteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).DeleteUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.user.v1.UserService/DeleteUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).DeleteUser(ctx, req.(*DeleteUserByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_DeleteUserByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserByNameRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).DeleteUserByName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.user.v1.UserService/DeleteUserByName", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).DeleteUserByName(ctx, req.(*DeleteUserByNameRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// UserService_ServiceDesc is the grpc.ServiceDesc for UserService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var UserService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "panels.user.v1.UserService", + HandlerType: (*UserServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateUser", + Handler: _UserService_CreateUser_Handler, + }, + { + MethodName: "GetUser", + Handler: _UserService_GetUser_Handler, + }, + { + MethodName: "GetUserByName", + Handler: _UserService_GetUserByName_Handler, + }, + { + MethodName: "UpdateUser", + Handler: _UserService_UpdateUser_Handler, + }, + { + MethodName: "UpdateUserByName", + Handler: _UserService_UpdateUserByName_Handler, + }, + { + MethodName: "DeleteUser", + Handler: _UserService_DeleteUser_Handler, + }, + { + MethodName: "DeleteUserByName", + Handler: _UserService_DeleteUserByName_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "user.proto", +} diff --git a/services/post-service/internal/kafka/kafka.go b/services/post-service/internal/kafka/kafka.go new file mode 100644 index 0000000..9834ce7 --- /dev/null +++ b/services/post-service/internal/kafka/kafka.go @@ -0,0 +1,23 @@ +package kafka + +import ( + "github.com/hexolan/panels/post-service/internal" + "github.com/hexolan/panels/post-service/internal/kafka/producer" + "github.com/hexolan/panels/post-service/internal/kafka/consumers" +) + +type eventConsumers struct { + userEC consumers.UserEventConsumer + panelEC consumers.PanelEventConsumer +} + +func NewEventConsumers(cfg internal.Config, dbRepo internal.PostDBRepository, eventProd producer.PostEventProducer) eventConsumers { + return eventConsumers{ + userEC: consumers.NewUserEventConsumer(cfg, dbRepo, eventProd), + panelEC: consumers.NewPanelEventConsumer(cfg, dbRepo, eventProd), + } +} + +func (ecs eventConsumers) Start() { + go ecs.panelEC.Start() +} \ No newline at end of file diff --git a/services/post-service/internal/kafka/producer/post.go b/services/post-service/internal/kafka/producer/post.go new file mode 100644 index 0000000..a9d31c1 --- /dev/null +++ b/services/post-service/internal/kafka/producer/post.go @@ -0,0 +1,60 @@ +package producer + +import ( + "context" + + "github.com/rs/zerolog/log" + "github.com/segmentio/kafka-go" + "google.golang.org/protobuf/proto" + + "github.com/hexolan/panels/post-service/internal" + "github.com/hexolan/panels/post-service/internal/rpc/postv1" +) + +type PostEventProducer struct { + writer *kafka.Writer +} + +func NewPostEventProducer(cfg internal.Config) PostEventProducer { + writer := &kafka.Writer{ + Addr: kafka.TCP(cfg.KafkaBrokers...), + Topic: "post", + Balancer: &kafka.LeastBytes{}, + } + + return PostEventProducer{writer: writer} +} + +func (ep PostEventProducer) SendEvent(event *postv1.PostEvent) { + evtBytes, err := proto.Marshal(event) + if err != nil { + log.Panic().Err(err).Msg("failed to marshal event") + } + + // Write to kafka + err = ep.writer.WriteMessages(context.Background(), kafka.Message{Value: evtBytes}) + if err != nil { + log.Panic().Err(err).Msg("failed to dispatch event") + } +} + +func (ep PostEventProducer) DispatchCreatedEvent(post *internal.Post) { + go ep.SendEvent(&postv1.PostEvent{ + Type: "created", + Data: postv1.PostToProto(post), + }) +} + +func (ep PostEventProducer) DispatchUpdatedEvent(post *internal.Post) { + go ep.SendEvent(&postv1.PostEvent{ + Type: "updated", + Data: postv1.PostToProto(post), + }) +} + +func (ep PostEventProducer) DispatchDeletedEvent(id internal.PostId) { + go ep.SendEvent(&postv1.PostEvent{ + Type: "deleted", + Data: &postv1.Post{Id: id.GetReprId()}, + }) +} \ No newline at end of file diff --git a/services/post-service/internal/post.go b/services/post-service/internal/post.go new file mode 100644 index 0000000..7dcf971 --- /dev/null +++ b/services/post-service/internal/post.go @@ -0,0 +1,162 @@ +package internal + +import ( + "regexp" + "context" + "strconv" + "encoding/json" + "database/sql" + "database/sql/driver" + + "github.com/jackc/pgx/v5/pgtype" + "github.com/go-ozzo/ozzo-validation/v4" +) + +// Post Models +type Post struct { + Id PostId `json:"id"` + + PanelId string `json:"panel_id"` + AuthorId string `json:"author_id"` + + Title string `json:"title"` + Content string `json:"content"` + + CreatedAt pgtype.Timestamp `json:"created_at"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` +} + +type PostCreate struct { + Title string `json:"title"` + Content string `json:"content"` +} + +func (p *PostCreate) Validate() error { + return validation.ValidateStruct( + p, + validation.Field(&p.Title, validation.Required, validation.Length(3, 512), validation.Match(regexp.MustCompile("^[^_][\\w ]+[^_]$"))), + validation.Field(&p.Content, validation.Required, validation.Length(3, 2048)), + ) +} + +type PostUpdate struct { + Title *string `json:"title,omitempty"` + Content *string `json:"content,omitempty"` +} + +func (p *PostUpdate) Validate() error { + return validation.ValidateStruct( + p, + validation.Field(&p.Title, validation.NilOrNotEmpty, validation.Length(3, 512), validation.Match(regexp.MustCompile("^[^_][\\w ]+[^_]$"))), + validation.Field(&p.Content, validation.NilOrNotEmpty, validation.Length(3, 2048)), + ) +} + +// Service Interface Methods +type PostService interface { + PostRepository +} + +type PostRepository interface { + CreatePost(ctx context.Context, panelId string, authorId string, data PostCreate) (*Post, error) + GetPost(ctx context.Context, id PostId) (*Post, error) + GetPanelPost(ctx context.Context, id PostId, panelId string) (*Post, error) + UpdatePost(ctx context.Context, id PostId, data PostUpdate) (*Post, error) + DeletePost(ctx context.Context, id PostId) error + + GetFeedPosts(ctx context.Context) ([]*Post, error) + GetUserPosts(ctx context.Context, userId string) ([]*Post, error) + GetPanelPosts(ctx context.Context, panelId string) ([]*Post, error) +} + +type PostDBRepository interface { + PostRepository + + DeletePostsByUser(ctx context.Context, userId string) ([]PostId, error) + DeletePostsOnPanel(ctx context.Context, panelId string) ([]PostId, error) +} + +// Converts IDs between int64 (base 10) internally and string (base 36) externally +type PostId struct { + Id int64 +} + +func (pid *PostId) GetId() int64 { + if pid == nil { + return 0 + } + return pid.Id +} + +func (pid *PostId) GetReprId() string { + if pid.GetId() == 0 { + return "" + } + + return strconv.FormatInt(pid.GetId(), 36) +} + +func (pid *PostId) Scan(value interface{}) error { + scnr := sql.NullInt64{} + err := scnr.Scan(value) + if err != nil { + return NewServiceError(InvalidArgumentErrorCode, "failed to scan post id: must be of type int64") + } else if scnr.Int64 < 1 { + return NewServiceError(InvalidArgumentErrorCode, "invalid post id: value must be greater than 0") + } + + pid.Id = scnr.Int64 + return nil +} + +func (pid PostId) Value() (driver.Value, error) { + if pid.GetId() == 0 { + return nil, NewServiceError(InvalidArgumentErrorCode, "post id not provided (of default value)") + } + + return driver.Value(pid.GetId()), nil +} + +func (pid PostId) MarshalJSON() ([]byte, error) { + return json.Marshal(pid.GetReprId()) +} + +func (pid *PostId) UnmarshalJSON(data []byte) error { + // Attempt to unmarshal the representative id + var repr_id string + err := json.Unmarshal(data, &repr_id) + if err != nil { + return err + } + + // Reconstruct the ID using the representative ID + id, err := getIdFromRepr(repr_id) + if err != nil { + return err + } + + pid.Id = *id + return nil +} + +func NewPostId(id int64) (*PostId, error) { + if id < 1 { + return nil, NewServiceError(InvalidArgumentErrorCode, "invalid post id: value must be greater than 0") + } + + return &PostId{Id: id}, nil +} + +func NewPostIdFromRepr(reprId string) (*PostId, error) { + id, err := getIdFromRepr(reprId) + if err != nil { + return nil, err + } + + return NewPostId(*id) +} + +func getIdFromRepr(reprId string) (*int64, error) { + id, err := strconv.ParseInt(reprId, 36, 64) + return &id, err +} \ No newline at end of file diff --git a/services/post-service/internal/postgres/migrations/000001_initialise_db.down.sql b/services/post-service/internal/postgres/migrations/000001_initialise_db.down.sql new file mode 100644 index 0000000..181b11a --- /dev/null +++ b/services/post-service/internal/postgres/migrations/000001_initialise_db.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS posts CASCADE; \ No newline at end of file diff --git a/services/post-service/internal/postgres/migrations/000001_initialise_db.up.sql b/services/post-service/internal/postgres/migrations/000001_initialise_db.up.sql new file mode 100644 index 0000000..764d566 --- /dev/null +++ b/services/post-service/internal/postgres/migrations/000001_initialise_db.up.sql @@ -0,0 +1,9 @@ +CREATE TABLE posts ( + "id" serial PRIMARY KEY, + "panel_id" varchar(64) NOT NULL, + "author_id" varchar(64) NOT NULL, + "title" varchar(512) NOT NULL, + "content" TEXT NOT NULL, + "created_at" timestamp NOT NULL DEFAULT timezone('utc', now()), + "updated_at" timestamp +); \ No newline at end of file diff --git a/services/post-service/internal/postgres/post.go b/services/post-service/internal/postgres/post.go new file mode 100644 index 0000000..a2e162b --- /dev/null +++ b/services/post-service/internal/postgres/post.go @@ -0,0 +1,262 @@ +package postgres + +import ( + "context" + "strings" + "encoding/json" + + "github.com/rs/zerolog/log" + "github.com/doug-martin/goqu/v9" + _ "github.com/doug-martin/goqu/v9/dialect/postgres" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + + "github.com/hexolan/panels/post-service/internal" +) + +type postDatabaseRepo struct { + db *pgxpool.Pool +} + +func NewPostRepository(db *pgxpool.Pool) internal.PostDBRepository { + return postDatabaseRepo{ + db: db, + } +} + +func (r postDatabaseRepo) CreatePost(ctx context.Context, panelId string, authorId string, data internal.PostCreate) (*internal.Post, error) { + var id internal.PostId + err := r.db.QueryRow(ctx, "INSERT INTO posts (panel_id, author_id, title, content) VALUES ($1, $2, $3, $4) RETURNING id", panelId, authorId, data.Title, data.Content).Scan(&id) + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("unaccounted error whilst creating post") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to create post") + } + + return r.GetPost(ctx, id) +} + +func (r postDatabaseRepo) GetPost(ctx context.Context, id internal.PostId) (*internal.Post, error) { + var post internal.Post + row := r.db.QueryRow(ctx, "SELECT id, panel_id, author_id, title, content, created_at, updated_at FROM posts WHERE id=$1", id) + err := row.Scan(&post.Id, &post.PanelId, &post.AuthorId, &post.Title, &post.Content, &post.CreatedAt, &post.UpdatedAt) + if err != nil { + if err == pgx.ErrNoRows { + return nil, internal.WrapServiceError(err, internal.NotFoundErrorCode, "post not found") + } else if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("unaccounted error whilst getting post") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get post") + } + + return &post, nil +} + +func (r postDatabaseRepo) GetPanelPost(ctx context.Context, id internal.PostId, panelId string) (*internal.Post, error) { + var post internal.Post + row := r.db.QueryRow(ctx, "SELECT id, panel_id, author_id, title, content, created_at, updated_at FROM posts WHERE id=$1 AND panel_id=$2", id, panelId) + err := row.Scan(&post.Id, &post.PanelId, &post.AuthorId, &post.Title, &post.Content, &post.CreatedAt, &post.UpdatedAt) + if err != nil { + if err == pgx.ErrNoRows { + return nil, internal.WrapServiceError(err, internal.NotFoundErrorCode, "post not found on that panel") + } else if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("unaccounted error whilst getting post") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get post") + } + + return &post, nil +} + +func (r postDatabaseRepo) UpdatePost(ctx context.Context, id internal.PostId, data internal.PostUpdate) (*internal.Post, error) { + // Transform request to patch data (marshal to remove omitted keys) + patchData := goqu.Record{"updated_at": goqu.L("timezone('utc', now())")} + marshalled, _ := json.Marshal(data) + _ = json.Unmarshal(marshalled, &patchData) + + // Build a statement to updated the post + statement, args, _ := goqu.Dialect("postgres").Update("posts").Prepared(true).Set(patchData).Where(goqu.C("id").Eq(id)).ToSQL() + + // Execute the query + result, err := r.db.Exec(ctx, statement, args...) + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("unaccounted error whilst updating post") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to update post") + } + + // Check if any rows were affected by the query + rows_affected := result.RowsAffected() + if rows_affected != 1 { + return nil, internal.NewServiceError(internal.NotFoundErrorCode, "post not found") + } + + // Return the updated post + return r.GetPost(ctx, id) +} + +func (r postDatabaseRepo) DeletePost(ctx context.Context, id internal.PostId) error { + result, err := r.db.Exec(ctx, "DELETE FROM posts WHERE id=$1", id) + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("error whilst deleting post") + return internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to delete post") + } + + // Check if any rows were affected by the query + rows_affected := result.RowsAffected() + if rows_affected != 1 { + return internal.NewServiceError(internal.NotFoundErrorCode, "post not found") + } + + return nil +} + +func (r postDatabaseRepo) GetFeedPosts(ctx context.Context) ([]*internal.Post, error) { + // todo: pagination + rows, err := r.db.Query(ctx, "SELECT id, panel_id, author_id, title, content, created_at, updated_at FROM posts ORDER BY created_at DESC LIMIT 25") + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("unaccounted error whilst getting posts") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get posts") + } + + posts := []*internal.Post{} + for rows.Next() { + var post internal.Post + err := rows.Scan(&post.Id, &post.PanelId, &post.AuthorId, &post.Title, &post.Content, &post.CreatedAt, &post.UpdatedAt) + if err != nil { + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to scan posts") + } + posts = append(posts, &post) + } + + if rows.Err() != nil { + log.Error().Err(err).Msg("query error whilst retrieving posts") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get posts") + } + + return posts, nil +} + +func (r postDatabaseRepo) GetUserPosts(ctx context.Context, userId string) ([]*internal.Post, error) { + // todo: pagination + rows, err := r.db.Query(ctx, "SELECT id, panel_id, author_id, title, content, created_at, updated_at FROM posts WHERE author_id=$1 ORDER BY created_at DESC LIMIT 25", userId) + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("unaccounted error whilst getting posts by user") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get posts") + } + + posts := []*internal.Post{} + for rows.Next() { + var post internal.Post + err := rows.Scan(&post.Id, &post.PanelId, &post.AuthorId, &post.Title, &post.Content, &post.CreatedAt, &post.UpdatedAt) + if err != nil { + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to scan posts") + } + posts = append(posts, &post) + } + + if rows.Err() != nil { + log.Error().Err(err).Msg("query error whilst retrieving posts by user") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get posts") + } + + return posts, nil +} + +func (r postDatabaseRepo) GetPanelPosts(ctx context.Context, panelId string) ([]*internal.Post, error) { + // todo: pagination + rows, err := r.db.Query(ctx, "SELECT id, panel_id, author_id, title, content, created_at, updated_at FROM posts WHERE panel_id=$1 ORDER BY created_at DESC LIMIT 25", panelId) + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("unaccounted error whilst getting posts from panel") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get posts") + } + + posts := []*internal.Post{} + for rows.Next() { + var post internal.Post + err := rows.Scan(&post.Id, &post.PanelId, &post.AuthorId, &post.Title, &post.Content, &post.CreatedAt, &post.UpdatedAt) + if err != nil { + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to scan posts") + } + posts = append(posts, &post) + } + + if rows.Err() != nil { + log.Error().Err(err).Msg("query error whilst retrieving posts from panel") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to get posts") + } + + return posts, nil +} + +func (r postDatabaseRepo) DeletePostsByUser(ctx context.Context, userId string) ([]internal.PostId, error) { + // Get post IDs for sending events + deletedIds := []internal.PostId{} + rows, err := r.db.Query(ctx, "SELECT id FROM posts WHERE author_id=$1", userId) + if err == nil { + for rows.Next() { + var postId internal.PostId + err = rows.Scan(&postId) + if err == nil { + deletedIds = append(deletedIds, postId) + } + } + } + + // Delete posts + _, err = r.db.Exec(ctx, "DELETE FROM posts WHERE author_id=$1", userId) + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("error whilst deleting posts by user") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to delete posts") + } + + return deletedIds, nil +} + +func (r postDatabaseRepo) DeletePostsOnPanel(ctx context.Context, panelId string) ([]internal.PostId, error) { + // Get post IDs for sending events + deletedIds := []internal.PostId{} + rows, err := r.db.Query(ctx, "SELECT id FROM posts WHERE panel_id=$1", panelId) + if err == nil { + for rows.Next() { + var postId internal.PostId + err = rows.Scan(&postId) + if err == nil { + deletedIds = append(deletedIds, postId) + } + } + } + + // Delete posts + _, err = r.db.Exec(ctx, "DELETE FROM posts WHERE panel_id=$1", panelId) + if err != nil { + if strings.Contains(err.Error(), "failed to connect to") { + return nil, internal.WrapServiceError(err, internal.ConnectionErrorCode, "failed to connect to database") + } + log.Error().Err(err).Msg("error whilst deleting posts from panel") + return nil, internal.WrapServiceError(err, internal.UnknownErrorCode, "failed to delete posts") + } + + return deletedIds, nil +} \ No newline at end of file diff --git a/services/post-service/internal/postgres/postgres.go b/services/post-service/internal/postgres/postgres.go new file mode 100644 index 0000000..88331d3 --- /dev/null +++ b/services/post-service/internal/postgres/postgres.go @@ -0,0 +1,24 @@ +package postgres + +import ( + "context" + + "github.com/rs/zerolog/log" + "github.com/jackc/pgx/v5/pgxpool" + + "github.com/hexolan/panels/post-service/internal" +) + +func NewPostgresInterface(ctx context.Context, cfg internal.Config) *pgxpool.Pool { + db, err := pgxpool.New(ctx, cfg.GetPostgresURL()) + if err != nil { + log.Panic().Err(err).Caller().Msg("") + } + + err = db.Ping(ctx) + if err != nil { + log.Warn().Err(err).Msg("failed Postgres ping") + } + + return db +} \ No newline at end of file diff --git a/services/post-service/internal/redis/post.go b/services/post-service/internal/redis/post.go new file mode 100644 index 0000000..66670bf --- /dev/null +++ b/services/post-service/internal/redis/post.go @@ -0,0 +1,151 @@ +package redis + +import ( + "time" + "context" + "encoding/json" + + "github.com/rs/zerolog/log" + "github.com/redis/go-redis/v9" + + "github.com/hexolan/panels/post-service/internal" +) + +type postCacheRepo struct { + rdb *redis.Client + + repo internal.PostRepository +} + +func NewPostRepository(rdb *redis.Client, repo internal.PostRepository) internal.PostRepository { + return postCacheRepo{ + rdb: rdb, + repo: repo, + } +} + +func (r postCacheRepo) getCachedPost(ctx context.Context, id internal.PostId) *internal.Post { + value, err := r.rdb.Get(ctx, id.GetReprId()).Result() + if err == redis.Nil { + return nil + } else if err != nil { + log.Error().Err(err).Msg("failed to get cached post") + return nil + } + + var post internal.Post + err = json.Unmarshal([]byte(value), &post) + if err != nil { + log.Error().Err(err).Msg("failed to unmarshal cached post") + return nil + } + + return &post +} + +func (r postCacheRepo) cachePost(ctx context.Context, post *internal.Post) { + value, err := json.Marshal(post) + if err != nil { + log.Error().Err(err).Msg("failed to marshal post for caching") + return + } + + err = r.rdb.Set(ctx, post.Id.GetReprId(), string(value), 2 * time.Minute).Err() + if err != nil { + log.Error().Err(err).Msg("failed to cache post") + return + } +} + +func (r postCacheRepo) purgeCachedPost(ctx context.Context, id internal.PostId) { + err := r.rdb.Del(ctx, id.GetReprId()).Err() + if err != nil && err != redis.Nil { + log.Error().Err(err).Msg("error while purging cached post") + } +} + +func (r postCacheRepo) CreatePost(ctx context.Context, panelId string, authorId string, data internal.PostCreate) (*internal.Post, error) { + // Create the post (using downstream DB repo) + post, err := r.repo.CreatePost(ctx, panelId, authorId, data) + if err != nil { + return post, err + } + + // Cache and return the created post. + r.cachePost(ctx, post) + return post, err +} + +func (r postCacheRepo) GetPost(ctx context.Context, id internal.PostId) (*internal.Post, error) { + // Check for a cached version of the post + if post := r.getCachedPost(ctx, id); post != nil { + return post, nil + } + + // Post is not cached (fetch from DB) + post, err := r.repo.GetPost(ctx, id) + if err != nil { + return post, err + } + + // Cache and return the fetched post + r.cachePost(ctx, post) + return post, err +} + +func (r postCacheRepo) GetPanelPost(ctx context.Context, id internal.PostId, panelId string) (*internal.Post, error) { + // Check for a cached version of the post + if post := r.getCachedPost(ctx, id); post != nil { + // The post is cached. Ensure panelId is a match. + if post.PanelId != panelId { + return nil, internal.NewServiceError(internal.NotFoundErrorCode, "post not found on that panel") + } + return post, nil + } + + // Post is not cached (fetch from DB) + post, err := r.repo.GetPanelPost(ctx, id, panelId) + if err != nil { + return post, err + } + + // Cache and return the fetched post + r.cachePost(ctx, post) + return post, err +} + +func (r postCacheRepo) UpdatePost(ctx context.Context, id internal.PostId, data internal.PostUpdate) (*internal.Post, error) { + // Update the post at the downstream repo. + post, err := r.repo.UpdatePost(ctx, id, data) + if err != nil { + return post, err + } + + // Cache and return the updated post. + r.cachePost(ctx, post) + return post, err +} + +func (r postCacheRepo) DeletePost(ctx context.Context, id internal.PostId) error { + // Delete the post downstream. + err := r.repo.DeletePost(ctx, id) + if err != nil { + return err + } + + // Purge any cached version of the post. + r.purgeCachedPost(ctx, id) + return err +} + +func (r postCacheRepo) GetFeedPosts(ctx context.Context) ([]*internal.Post, error) { + return r.repo.GetFeedPosts(ctx) +} + +func (r postCacheRepo) GetUserPosts(ctx context.Context, userId string) ([]*internal.Post, error) { + return r.repo.GetUserPosts(ctx, userId) +} + +func (r postCacheRepo) GetPanelPosts(ctx context.Context, panelId string) ([]*internal.Post, error) { + return r.repo.GetPanelPosts(ctx, panelId) +} \ No newline at end of file diff --git a/services/post-service/internal/redis/redis.go b/services/post-service/internal/redis/redis.go new file mode 100644 index 0000000..4581666 --- /dev/null +++ b/services/post-service/internal/redis/redis.go @@ -0,0 +1,29 @@ +package redis + +import ( + "time" + "context" + + "github.com/rs/zerolog/log" + "github.com/redis/go-redis/v9" + + "github.com/hexolan/panels/post-service/internal" +) + +func NewRedisInterface(ctx context.Context, cfg internal.Config) *redis.Client { + rdb := redis.NewClient(&redis.Options{ + Addr: cfg.RedisHost, + Password: cfg.RedisPass, + DB: 0, + + DialTimeout: time.Millisecond * 250, + ReadTimeout: time.Millisecond * 500, + }) + + _, err := rdb.Ping(ctx).Result() + if err != nil { + log.Warn().Err(err).Msg("failed Redis ping") + } + + return rdb +} \ No newline at end of file diff --git a/services/post-service/internal/rpc/post.go b/services/post-service/internal/rpc/post.go new file mode 100644 index 0000000..c589dc4 --- /dev/null +++ b/services/post-service/internal/rpc/post.go @@ -0,0 +1,179 @@ +package rpc + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/hexolan/panels/post-service/internal" + pb "github.com/hexolan/panels/post-service/internal/rpc/postv1" +) + +type postServer struct { + pb.UnimplementedPostServiceServer + + service internal.PostService +} + +func NewPostServer(service internal.PostService) postServer { + return postServer{service: service} +} + +func (svr *postServer) CreatePost(ctx context.Context, request *pb.CreatePostRequest) (*pb.Post, error) { + // Ensure the required args are provided + if request.GetData() == nil { + return nil, status.Error(codes.InvalidArgument, "malformed request") + } + + if request.GetPanelId() == "" { + return nil, status.Error(codes.InvalidArgument, "panel id not provided") + } + + if request.GetUserId() == "" { + return nil, status.Error(codes.InvalidArgument, "user id not provided") + } + + // Convert to service model + data := pb.PostCreateFromProto(request.GetData()) + + // Pass to service method for creation + post, err := svr.service.CreatePost(ctx, request.GetPanelId(), request.GetUserId(), data) + if err != nil { + return nil, err + } + + return pb.PostToProto(post), nil +} + +func (svr *postServer) GetPost(ctx context.Context, request *pb.GetPostRequest) (*pb.Post, error) { + // Ensure the required args are provided + if request.GetId() == "" { + return nil, status.Error(codes.InvalidArgument, "post id not provided") + } + + // Convert to business model + id, err := internal.NewPostIdFromRepr(request.GetId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid post id") + } + + // Pass to service method for retrieval + post, err := svr.service.GetPost(ctx, *id) + if err != nil { + return nil, err + } + return pb.PostToProto(post), nil +} + +func (svr *postServer) GetPanelPost(ctx context.Context, request *pb.GetPanelPostRequest) (*pb.Post, error) { + // Ensure the required args are provided + if request.GetId() == "" { + return nil, status.Error(codes.InvalidArgument, "post id not provided") + } + + if request.GetPanelId() == "" { + return nil, status.Error(codes.InvalidArgument, "panel id not provided") + } + + // Convert to service model + id, err := internal.NewPostIdFromRepr(request.GetId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid post id") + } + + // Pass to service method for retrieval + post, err := svr.service.GetPanelPost(ctx, *id, request.GetPanelId()) + if err != nil { + return nil, err + } + return pb.PostToProto(post), nil +} + +func (svr *postServer) UpdatePost(ctx context.Context, request *pb.UpdatePostRequest) (*pb.Post, error) { + // Ensure the required args are provided + if request.GetId() == "" { + return nil, status.Error(codes.InvalidArgument, "post id not provided") + } + + if request.GetData() == nil { + return nil, status.Error(codes.InvalidArgument, "malformed request") + } + + // Convert to service models + id, err := internal.NewPostIdFromRepr(request.GetId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid post id") + } + + data := pb.PostUpdateFromProto(request.GetData()) + + // Pass to service method for update + post, err := svr.service.UpdatePost(ctx, *id, data) + if err != nil { + return nil, err + } + + return pb.PostToProto(post), nil +} + +func (svr *postServer) DeletePost(ctx context.Context, request *pb.DeletePostRequest) (*emptypb.Empty, error) { + // Ensure the required args are provided + if request.GetId() == "" { + return nil, status.Error(codes.InvalidArgument, "post id not provided") + } + + // Convert to service model + id, err := internal.NewPostIdFromRepr(request.GetId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid post id") + } + + // Pass to service method for deletion + err = svr.service.DeletePost(ctx, *id) + if err != nil { + return nil, err + } + return &emptypb.Empty{}, nil +} + +func (svr *postServer) GetFeedPosts(ctx context.Context, request *pb.GetFeedPostsRequest) (*pb.FeedPosts, error) { + // Get the posts + posts, err := svr.service.GetFeedPosts(ctx) + if err != nil { + return nil, err + } + + return &pb.FeedPosts{Posts: pb.PostsToProto(posts)}, nil +} + +func (svr *postServer) GetUserPosts(ctx context.Context, request *pb.GetUserPostsRequest) (*pb.UserPosts, error) { + // Ensure the required args are provided + if request.GetUserId() == "" { + return nil, status.Error(codes.InvalidArgument, "user id not provided") + } + + // Get the posts + posts, err := svr.service.GetUserPosts(ctx, request.GetUserId()) + if err != nil { + return nil, err + } + + return &pb.UserPosts{Posts: pb.PostsToProto(posts)}, nil +} + +func (svr *postServer) GetPanelPosts(ctx context.Context, request *pb.GetPanelPostsRequest) (*pb.PanelPosts, error) { + // Ensure the required args are provided + if request.GetPanelId() == "" { + return nil, status.Error(codes.InvalidArgument, "panel id not provided") + } + + // Get the posts + posts, err := svr.service.GetPanelPosts(ctx, request.GetPanelId()) + if err != nil { + return nil, err + } + + return &pb.PanelPosts{Posts: pb.PostsToProto(posts)}, nil +} \ No newline at end of file diff --git a/services/post-service/internal/rpc/postv1/conversion.go b/services/post-service/internal/rpc/postv1/conversion.go new file mode 100644 index 0000000..3002e1e --- /dev/null +++ b/services/post-service/internal/rpc/postv1/conversion.go @@ -0,0 +1,55 @@ +// Handles conversion between Protobuf types and service types +package postv1 + +import ( + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/hexolan/panels/post-service/internal" +) + +// Post -> Protobuf 'Post' +func PostToProto(post *internal.Post) *Post { + proto := Post{ + Id: post.Id.GetReprId(), + + PanelId: post.PanelId, + AuthorId: post.AuthorId, + + Title: post.Title, + Content: post.Content, + + CreatedAt: timestamppb.New(post.CreatedAt.Time), + } + + // convert nullable attributes to PB form (if present) + if post.UpdatedAt.Valid == true { + proto.UpdatedAt = timestamppb.New(post.UpdatedAt.Time) + } + + return &proto +} + +// []Post -> []Protobuf 'Post' +func PostsToProto(posts []*internal.Post) []*Post { + protoPosts := []*Post{} + for _, post := range posts { + protoPosts = append(protoPosts, PostToProto(post)) + } + return protoPosts +} + +// Protobuf 'PostMutable' -> PostCreate +func PostCreateFromProto(proto *PostMutable) internal.PostCreate { + return internal.PostCreate{ + Title: proto.GetTitle(), + Content: proto.GetContent(), + } +} + +// Protobuf 'PostMutable' -> PostUpdate +func PostUpdateFromProto(proto *PostMutable) internal.PostUpdate { + return internal.PostUpdate{ + Title: proto.Title, + Content: proto.Content, + } +} \ No newline at end of file diff --git a/services/post-service/internal/rpc/postv1/post.pb.go b/services/post-service/internal/rpc/postv1/post.pb.go new file mode 100644 index 0000000..0477e8d --- /dev/null +++ b/services/post-service/internal/rpc/postv1/post.pb.go @@ -0,0 +1,1145 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v4.23.4 +// source: post.proto + +package postv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +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 Post struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + PanelId string `protobuf:"bytes,2,opt,name=panel_id,json=panelId,proto3" json:"panel_id,omitempty"` // External Ref: Panel Id + AuthorId string `protobuf:"bytes,3,opt,name=author_id,json=authorId,proto3" json:"author_id,omitempty"` // External Ref: User Id + Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"` + Content string `protobuf:"bytes,5,opt,name=content,proto3" json:"content,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` +} + +func (x *Post) Reset() { + *x = Post{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Post) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Post) ProtoMessage() {} + +func (x *Post) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Post.ProtoReflect.Descriptor instead. +func (*Post) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{0} +} + +func (x *Post) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Post) GetPanelId() string { + if x != nil { + return x.PanelId + } + return "" +} + +func (x *Post) GetAuthorId() string { + if x != nil { + return x.AuthorId + } + return "" +} + +func (x *Post) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *Post) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *Post) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Post) GetUpdatedAt() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type PostMutable struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Title *string `protobuf:"bytes,1,opt,name=title,proto3,oneof" json:"title,omitempty"` + Content *string `protobuf:"bytes,2,opt,name=content,proto3,oneof" json:"content,omitempty"` +} + +func (x *PostMutable) Reset() { + *x = PostMutable{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostMutable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostMutable) ProtoMessage() {} + +func (x *PostMutable) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostMutable.ProtoReflect.Descriptor instead. +func (*PostMutable) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{1} +} + +func (x *PostMutable) GetTitle() string { + if x != nil && x.Title != nil { + return *x.Title + } + return "" +} + +func (x *PostMutable) GetContent() string { + if x != nil && x.Content != nil { + return *x.Content + } + return "" +} + +type CreatePostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PanelId string `protobuf:"bytes,1,opt,name=panel_id,json=panelId,proto3" json:"panel_id,omitempty"` // External Ref: Panel Id + UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // External Ref: User Id + Data *PostMutable `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *CreatePostRequest) Reset() { + *x = CreatePostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreatePostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreatePostRequest) ProtoMessage() {} + +func (x *CreatePostRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreatePostRequest.ProtoReflect.Descriptor instead. +func (*CreatePostRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{2} +} + +func (x *CreatePostRequest) GetPanelId() string { + if x != nil { + return x.PanelId + } + return "" +} + +func (x *CreatePostRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *CreatePostRequest) GetData() *PostMutable { + if x != nil { + return x.Data + } + return nil +} + +type GetPostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *GetPostRequest) Reset() { + *x = GetPostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPostRequest) ProtoMessage() {} + +func (x *GetPostRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPostRequest.ProtoReflect.Descriptor instead. +func (*GetPostRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{3} +} + +func (x *GetPostRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetPanelPostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PanelId string `protobuf:"bytes,1,opt,name=panel_id,json=panelId,proto3" json:"panel_id,omitempty"` // External Ref: Panel Id + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *GetPanelPostRequest) Reset() { + *x = GetPanelPostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPanelPostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPanelPostRequest) ProtoMessage() {} + +func (x *GetPanelPostRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPanelPostRequest.ProtoReflect.Descriptor instead. +func (*GetPanelPostRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{4} +} + +func (x *GetPanelPostRequest) GetPanelId() string { + if x != nil { + return x.PanelId + } + return "" +} + +func (x *GetPanelPostRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type UpdatePostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Data *PostMutable `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *UpdatePostRequest) Reset() { + *x = UpdatePostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdatePostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePostRequest) ProtoMessage() {} + +func (x *UpdatePostRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePostRequest.ProtoReflect.Descriptor instead. +func (*UpdatePostRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{5} +} + +func (x *UpdatePostRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdatePostRequest) GetData() *PostMutable { + if x != nil { + return x.Data + } + return nil +} + +type DeletePostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *DeletePostRequest) Reset() { + *x = DeletePostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeletePostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePostRequest) ProtoMessage() {} + +func (x *DeletePostRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletePostRequest.ProtoReflect.Descriptor instead. +func (*DeletePostRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{6} +} + +func (x *DeletePostRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetFeedPostsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetFeedPostsRequest) Reset() { + *x = GetFeedPostsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFeedPostsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeedPostsRequest) ProtoMessage() {} + +func (x *GetFeedPostsRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeedPostsRequest.ProtoReflect.Descriptor instead. +func (*GetFeedPostsRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{7} +} + +type FeedPosts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"` +} + +func (x *FeedPosts) Reset() { + *x = FeedPosts{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FeedPosts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FeedPosts) ProtoMessage() {} + +func (x *FeedPosts) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FeedPosts.ProtoReflect.Descriptor instead. +func (*FeedPosts) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{8} +} + +func (x *FeedPosts) GetPosts() []*Post { + if x != nil { + return x.Posts + } + return nil +} + +type GetUserPostsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // External Ref: User Id +} + +func (x *GetUserPostsRequest) Reset() { + *x = GetUserPostsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserPostsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserPostsRequest) ProtoMessage() {} + +func (x *GetUserPostsRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserPostsRequest.ProtoReflect.Descriptor instead. +func (*GetUserPostsRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{9} +} + +func (x *GetUserPostsRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +type UserPosts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"` +} + +func (x *UserPosts) Reset() { + *x = UserPosts{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserPosts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserPosts) ProtoMessage() {} + +func (x *UserPosts) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserPosts.ProtoReflect.Descriptor instead. +func (*UserPosts) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{10} +} + +func (x *UserPosts) GetPosts() []*Post { + if x != nil { + return x.Posts + } + return nil +} + +type GetPanelPostsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PanelId string `protobuf:"bytes,1,opt,name=panel_id,json=panelId,proto3" json:"panel_id,omitempty"` // External Ref: Panel Id +} + +func (x *GetPanelPostsRequest) Reset() { + *x = GetPanelPostsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPanelPostsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPanelPostsRequest) ProtoMessage() {} + +func (x *GetPanelPostsRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPanelPostsRequest.ProtoReflect.Descriptor instead. +func (*GetPanelPostsRequest) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{11} +} + +func (x *GetPanelPostsRequest) GetPanelId() string { + if x != nil { + return x.PanelId + } + return "" +} + +type PanelPosts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"` +} + +func (x *PanelPosts) Reset() { + *x = PanelPosts{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PanelPosts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PanelPosts) ProtoMessage() {} + +func (x *PanelPosts) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PanelPosts.ProtoReflect.Descriptor instead. +func (*PanelPosts) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{12} +} + +func (x *PanelPosts) GetPosts() []*Post { + if x != nil { + return x.Posts + } + return nil +} + +// Kafka Event Schema +type PostEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Data *Post `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *PostEvent) Reset() { + *x = PostEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostEvent) ProtoMessage() {} + +func (x *PostEvent) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostEvent.ProtoReflect.Descriptor instead. +func (*PostEvent) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{13} +} + +func (x *PostEvent) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *PostEvent) GetData() *Post { + if x != nil { + return x.Data + } + return nil +} + +var File_post_proto protoreflect.FileDescriptor + +var file_post_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, + 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf4, 0x01, 0x0a, 0x04, 0x50, + 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x1b, + 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x22, 0x5d, 0x0a, 0x0b, 0x50, 0x6f, 0x73, 0x74, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x12, 0x19, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x22, 0x78, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x49, 0x64, + 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, + 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x4d, 0x75, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x20, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x40, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x54, + 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x23, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x65, 0x74, + 0x46, 0x65, 0x65, 0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0x37, 0x0a, 0x09, 0x46, 0x65, 0x65, 0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x2a, 0x0a, + 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, + 0x73, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x22, 0x2e, 0x0a, 0x13, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x37, 0x0a, 0x09, 0x55, 0x73, 0x65, + 0x72, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, + 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x73, + 0x74, 0x73, 0x22, 0x31, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x50, 0x6f, + 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x22, 0x38, 0x0a, 0x0a, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x50, 0x6f, + 0x73, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x22, + 0x49, 0x0a, 0x09, 0x50, 0x6f, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0xf3, 0x04, 0x0a, 0x0b, 0x50, + 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x21, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, + 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x73, + 0x74, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x1e, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x6f, 0x73, 0x74, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x50, 0x61, 0x6e, + 0x65, 0x6c, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x23, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, + 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, + 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, + 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x73, + 0x74, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, + 0x74, 0x12, 0x21, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, + 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0a, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x21, 0x2e, 0x70, 0x61, 0x6e, + 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x46, 0x65, + 0x65, 0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, + 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, + 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, + 0x65, 0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0c, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x70, 0x61, 0x6e, 0x65, + 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0d, 0x47, + 0x65, 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x22, 0x00, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_post_proto_rawDescOnce sync.Once + file_post_proto_rawDescData = file_post_proto_rawDesc +) + +func file_post_proto_rawDescGZIP() []byte { + file_post_proto_rawDescOnce.Do(func() { + file_post_proto_rawDescData = protoimpl.X.CompressGZIP(file_post_proto_rawDescData) + }) + return file_post_proto_rawDescData +} + +var file_post_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_post_proto_goTypes = []interface{}{ + (*Post)(nil), // 0: panels.post.v1.Post + (*PostMutable)(nil), // 1: panels.post.v1.PostMutable + (*CreatePostRequest)(nil), // 2: panels.post.v1.CreatePostRequest + (*GetPostRequest)(nil), // 3: panels.post.v1.GetPostRequest + (*GetPanelPostRequest)(nil), // 4: panels.post.v1.GetPanelPostRequest + (*UpdatePostRequest)(nil), // 5: panels.post.v1.UpdatePostRequest + (*DeletePostRequest)(nil), // 6: panels.post.v1.DeletePostRequest + (*GetFeedPostsRequest)(nil), // 7: panels.post.v1.GetFeedPostsRequest + (*FeedPosts)(nil), // 8: panels.post.v1.FeedPosts + (*GetUserPostsRequest)(nil), // 9: panels.post.v1.GetUserPostsRequest + (*UserPosts)(nil), // 10: panels.post.v1.UserPosts + (*GetPanelPostsRequest)(nil), // 11: panels.post.v1.GetPanelPostsRequest + (*PanelPosts)(nil), // 12: panels.post.v1.PanelPosts + (*PostEvent)(nil), // 13: panels.post.v1.PostEvent + (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 15: google.protobuf.Empty +} +var file_post_proto_depIdxs = []int32{ + 14, // 0: panels.post.v1.Post.created_at:type_name -> google.protobuf.Timestamp + 14, // 1: panels.post.v1.Post.updated_at:type_name -> google.protobuf.Timestamp + 1, // 2: panels.post.v1.CreatePostRequest.data:type_name -> panels.post.v1.PostMutable + 1, // 3: panels.post.v1.UpdatePostRequest.data:type_name -> panels.post.v1.PostMutable + 0, // 4: panels.post.v1.FeedPosts.posts:type_name -> panels.post.v1.Post + 0, // 5: panels.post.v1.UserPosts.posts:type_name -> panels.post.v1.Post + 0, // 6: panels.post.v1.PanelPosts.posts:type_name -> panels.post.v1.Post + 0, // 7: panels.post.v1.PostEvent.data:type_name -> panels.post.v1.Post + 2, // 8: panels.post.v1.PostService.CreatePost:input_type -> panels.post.v1.CreatePostRequest + 3, // 9: panels.post.v1.PostService.GetPost:input_type -> panels.post.v1.GetPostRequest + 4, // 10: panels.post.v1.PostService.GetPanelPost:input_type -> panels.post.v1.GetPanelPostRequest + 5, // 11: panels.post.v1.PostService.UpdatePost:input_type -> panels.post.v1.UpdatePostRequest + 6, // 12: panels.post.v1.PostService.DeletePost:input_type -> panels.post.v1.DeletePostRequest + 7, // 13: panels.post.v1.PostService.GetFeedPosts:input_type -> panels.post.v1.GetFeedPostsRequest + 9, // 14: panels.post.v1.PostService.GetUserPosts:input_type -> panels.post.v1.GetUserPostsRequest + 11, // 15: panels.post.v1.PostService.GetPanelPosts:input_type -> panels.post.v1.GetPanelPostsRequest + 0, // 16: panels.post.v1.PostService.CreatePost:output_type -> panels.post.v1.Post + 0, // 17: panels.post.v1.PostService.GetPost:output_type -> panels.post.v1.Post + 0, // 18: panels.post.v1.PostService.GetPanelPost:output_type -> panels.post.v1.Post + 0, // 19: panels.post.v1.PostService.UpdatePost:output_type -> panels.post.v1.Post + 15, // 20: panels.post.v1.PostService.DeletePost:output_type -> google.protobuf.Empty + 8, // 21: panels.post.v1.PostService.GetFeedPosts:output_type -> panels.post.v1.FeedPosts + 10, // 22: panels.post.v1.PostService.GetUserPosts:output_type -> panels.post.v1.UserPosts + 12, // 23: panels.post.v1.PostService.GetPanelPosts:output_type -> panels.post.v1.PanelPosts + 16, // [16:24] is the sub-list for method output_type + 8, // [8:16] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name +} + +func init() { file_post_proto_init() } +func file_post_proto_init() { + if File_post_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_post_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Post); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostMutable); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreatePostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPanelPostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdatePostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeletePostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFeedPostsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FeedPosts); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserPostsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserPosts); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPanelPostsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PanelPosts); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_post_proto_msgTypes[1].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_post_proto_rawDesc, + NumEnums: 0, + NumMessages: 14, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_post_proto_goTypes, + DependencyIndexes: file_post_proto_depIdxs, + MessageInfos: file_post_proto_msgTypes, + }.Build() + File_post_proto = out.File + file_post_proto_rawDesc = nil + file_post_proto_goTypes = nil + file_post_proto_depIdxs = nil +} diff --git a/services/post-service/internal/rpc/postv1/post_grpc.pb.go b/services/post-service/internal/rpc/postv1/post_grpc.pb.go new file mode 100644 index 0000000..b004ca4 --- /dev/null +++ b/services/post-service/internal/rpc/postv1/post_grpc.pb.go @@ -0,0 +1,358 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v4.23.4 +// source: post.proto + +package postv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// 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.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// PostServiceClient is the client API for PostService 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 PostServiceClient interface { + CreatePost(ctx context.Context, in *CreatePostRequest, opts ...grpc.CallOption) (*Post, error) + GetPost(ctx context.Context, in *GetPostRequest, opts ...grpc.CallOption) (*Post, error) + GetPanelPost(ctx context.Context, in *GetPanelPostRequest, opts ...grpc.CallOption) (*Post, error) + UpdatePost(ctx context.Context, in *UpdatePostRequest, opts ...grpc.CallOption) (*Post, error) + DeletePost(ctx context.Context, in *DeletePostRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + GetFeedPosts(ctx context.Context, in *GetFeedPostsRequest, opts ...grpc.CallOption) (*FeedPosts, error) + GetUserPosts(ctx context.Context, in *GetUserPostsRequest, opts ...grpc.CallOption) (*UserPosts, error) + GetPanelPosts(ctx context.Context, in *GetPanelPostsRequest, opts ...grpc.CallOption) (*PanelPosts, error) +} + +type postServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewPostServiceClient(cc grpc.ClientConnInterface) PostServiceClient { + return &postServiceClient{cc} +} + +func (c *postServiceClient) CreatePost(ctx context.Context, in *CreatePostRequest, opts ...grpc.CallOption) (*Post, error) { + out := new(Post) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/CreatePost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) GetPost(ctx context.Context, in *GetPostRequest, opts ...grpc.CallOption) (*Post, error) { + out := new(Post) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/GetPost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) GetPanelPost(ctx context.Context, in *GetPanelPostRequest, opts ...grpc.CallOption) (*Post, error) { + out := new(Post) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/GetPanelPost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) UpdatePost(ctx context.Context, in *UpdatePostRequest, opts ...grpc.CallOption) (*Post, error) { + out := new(Post) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/UpdatePost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) DeletePost(ctx context.Context, in *DeletePostRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/DeletePost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) GetFeedPosts(ctx context.Context, in *GetFeedPostsRequest, opts ...grpc.CallOption) (*FeedPosts, error) { + out := new(FeedPosts) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/GetFeedPosts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) GetUserPosts(ctx context.Context, in *GetUserPostsRequest, opts ...grpc.CallOption) (*UserPosts, error) { + out := new(UserPosts) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/GetUserPosts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) GetPanelPosts(ctx context.Context, in *GetPanelPostsRequest, opts ...grpc.CallOption) (*PanelPosts, error) { + out := new(PanelPosts) + err := c.cc.Invoke(ctx, "/panels.post.v1.PostService/GetPanelPosts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PostServiceServer is the server API for PostService service. +// All implementations must embed UnimplementedPostServiceServer +// for forward compatibility +type PostServiceServer interface { + CreatePost(context.Context, *CreatePostRequest) (*Post, error) + GetPost(context.Context, *GetPostRequest) (*Post, error) + GetPanelPost(context.Context, *GetPanelPostRequest) (*Post, error) + UpdatePost(context.Context, *UpdatePostRequest) (*Post, error) + DeletePost(context.Context, *DeletePostRequest) (*emptypb.Empty, error) + GetFeedPosts(context.Context, *GetFeedPostsRequest) (*FeedPosts, error) + GetUserPosts(context.Context, *GetUserPostsRequest) (*UserPosts, error) + GetPanelPosts(context.Context, *GetPanelPostsRequest) (*PanelPosts, error) + mustEmbedUnimplementedPostServiceServer() +} + +// UnimplementedPostServiceServer must be embedded to have forward compatible implementations. +type UnimplementedPostServiceServer struct { +} + +func (UnimplementedPostServiceServer) CreatePost(context.Context, *CreatePostRequest) (*Post, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreatePost not implemented") +} +func (UnimplementedPostServiceServer) GetPost(context.Context, *GetPostRequest) (*Post, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPost not implemented") +} +func (UnimplementedPostServiceServer) GetPanelPost(context.Context, *GetPanelPostRequest) (*Post, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPanelPost not implemented") +} +func (UnimplementedPostServiceServer) UpdatePost(context.Context, *UpdatePostRequest) (*Post, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdatePost not implemented") +} +func (UnimplementedPostServiceServer) DeletePost(context.Context, *DeletePostRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeletePost not implemented") +} +func (UnimplementedPostServiceServer) GetFeedPosts(context.Context, *GetFeedPostsRequest) (*FeedPosts, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFeedPosts not implemented") +} +func (UnimplementedPostServiceServer) GetUserPosts(context.Context, *GetUserPostsRequest) (*UserPosts, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserPosts not implemented") +} +func (UnimplementedPostServiceServer) GetPanelPosts(context.Context, *GetPanelPostsRequest) (*PanelPosts, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPanelPosts not implemented") +} +func (UnimplementedPostServiceServer) mustEmbedUnimplementedPostServiceServer() {} + +// UnsafePostServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PostServiceServer will +// result in compilation errors. +type UnsafePostServiceServer interface { + mustEmbedUnimplementedPostServiceServer() +} + +func RegisterPostServiceServer(s grpc.ServiceRegistrar, srv PostServiceServer) { + s.RegisterService(&PostService_ServiceDesc, srv) +} + +func _PostService_CreatePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreatePostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).CreatePost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/CreatePost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).CreatePost(ctx, req.(*CreatePostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_GetPost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).GetPost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/GetPost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).GetPost(ctx, req.(*GetPostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_GetPanelPost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPanelPostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).GetPanelPost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/GetPanelPost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).GetPanelPost(ctx, req.(*GetPanelPostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_UpdatePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdatePostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).UpdatePost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/UpdatePost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).UpdatePost(ctx, req.(*UpdatePostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_DeletePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeletePostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).DeletePost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/DeletePost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).DeletePost(ctx, req.(*DeletePostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_GetFeedPosts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFeedPostsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).GetFeedPosts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/GetFeedPosts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).GetFeedPosts(ctx, req.(*GetFeedPostsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_GetUserPosts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserPostsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).GetUserPosts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/GetUserPosts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).GetUserPosts(ctx, req.(*GetUserPostsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_GetPanelPosts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPanelPostsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).GetPanelPosts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/panels.post.v1.PostService/GetPanelPosts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).GetPanelPosts(ctx, req.(*GetPanelPostsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// PostService_ServiceDesc is the grpc.ServiceDesc for PostService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PostService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "panels.post.v1.PostService", + HandlerType: (*PostServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreatePost", + Handler: _PostService_CreatePost_Handler, + }, + { + MethodName: "GetPost", + Handler: _PostService_GetPost_Handler, + }, + { + MethodName: "GetPanelPost", + Handler: _PostService_GetPanelPost_Handler, + }, + { + MethodName: "UpdatePost", + Handler: _PostService_UpdatePost_Handler, + }, + { + MethodName: "DeletePost", + Handler: _PostService_DeletePost_Handler, + }, + { + MethodName: "GetFeedPosts", + Handler: _PostService_GetFeedPosts_Handler, + }, + { + MethodName: "GetUserPosts", + Handler: _PostService_GetUserPosts_Handler, + }, + { + MethodName: "GetPanelPosts", + Handler: _PostService_GetPanelPosts_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "post.proto", +} diff --git a/services/post-service/internal/rpc/rpc.go b/services/post-service/internal/rpc/rpc.go new file mode 100644 index 0000000..9307a13 --- /dev/null +++ b/services/post-service/internal/rpc/rpc.go @@ -0,0 +1,77 @@ +package rpc + +import ( + "net" + "context" + + "google.golang.org/grpc" + "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" + + "github.com/hexolan/panels/post-service/internal" + "github.com/hexolan/panels/post-service/internal/rpc/postv1" +) + +type RPCServer struct { + grpcSvr *grpc.Server +} + +func NewRPCServer(service internal.PostService) *RPCServer { + logger := log.Logger.With().Timestamp().Str("src", "rpc").Logger() + + svr := grpc.NewServer( + grpc.ChainUnaryInterceptor( + logging.UnaryServerInterceptor(loggingInterceptor(logger)), + ), + grpc.ChainStreamInterceptor( + logging.StreamServerInterceptor(loggingInterceptor(logger)), + ), + ) + + // Post Service Server + postSvr := NewPostServer(service) + postv1.RegisterPostServiceServer(svr, &postSvr) + + // Health Check Server + healthSvr := health.NewServer() + grpc_health_v1.RegisterHealthServer(svr, healthSvr) + + return &RPCServer{grpcSvr: svr} +} + +func loggingInterceptor(logger zerolog.Logger) logging.Logger { + return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) { + logger := logger.With().Fields(fields).Logger() + + switch lvl { + case logging.LevelError: + logger.Error().Msg(msg) + case logging.LevelWarn: + logger.Warn().Msg(msg) + case logging.LevelInfo: + logger.Info().Msg(msg) + case logging.LevelDebug: + logger.Debug().Msg(msg) + default: + logger.Debug().Interface("unknown-log-level", lvl).Msg(msg) + } + }) +} + +func (r *RPCServer) Serve() { + // Prepare the listening port + lis, err := net.Listen("tcp", "0.0.0.0:9090") + if err != nil { + log.Panic().Err(err).Caller().Msg("failed to listen on RPC port (:9090)") + } + + // Begin serving RPC + log.Info().Str("address", lis.Addr().String()).Msg("Attempting to serve RPC...") + err = r.grpcSvr.Serve(lis) + if err != nil { + log.Panic().Err(err).Caller().Msg("failed to serve RPC") + } +} \ No newline at end of file diff --git a/services/post-service/internal/service/post.go b/services/post-service/internal/service/post.go new file mode 100644 index 0000000..4b19a20 --- /dev/null +++ b/services/post-service/internal/service/post.go @@ -0,0 +1,94 @@ +package service + +import ( + "context" + "strings" + + "github.com/hexolan/panels/post-service/internal" + "github.com/hexolan/panels/post-service/internal/kafka/producer" +) + +type postService struct { + events producer.PostEventProducer + + repo internal.PostRepository +} + +func NewPostService(events producer.PostEventProducer, repo internal.PostRepository) internal.PostService { + return postService{ + events: events, + repo: repo, + } +} + +func (srv postService) CreatePost(ctx context.Context, panelId string, authorId string, data internal.PostCreate) (*internal.Post, error) { + // Validate the data + err := data.Validate() + if err != nil { + return nil, internal.NewServiceErrorf(internal.InvalidArgumentErrorCode, "invalid argument: %s", err.Error()) + } + + // Create the post + post, err := srv.repo.CreatePost(ctx, panelId, authorId, data) + + // Dispatch post created event + if err == nil { + srv.events.DispatchCreatedEvent(post) + } + + return post, err +} + +func (srv postService) GetPost(ctx context.Context, id internal.PostId) (*internal.Post, error) { + return srv.repo.GetPost(ctx, id) +} + +func (srv postService) GetPanelPost(ctx context.Context, id internal.PostId, panelId string) (*internal.Post, error) { + panelId = strings.ToLower(panelId) // Panel IDs are case insensitive + return srv.repo.GetPanelPost(ctx, id, panelId) +} + +func (srv postService) UpdatePost(ctx context.Context, id internal.PostId, data internal.PostUpdate) (*internal.Post, error) { + // Validate the data + if data == (internal.PostUpdate{}) { + return nil, internal.NewServiceError(internal.InvalidArgumentErrorCode, "no values provided") + } + + err := data.Validate() + if err != nil { + return nil, internal.NewServiceErrorf(internal.InvalidArgumentErrorCode, "invalid argument: %s", err.Error()) + } + + // Update the post + post, err := srv.repo.UpdatePost(ctx, id, data) + + // Dispatch post created event + if err == nil { + srv.events.DispatchUpdatedEvent(post) + } + + return post, err +} + +func (srv postService) DeletePost(ctx context.Context, id internal.PostId) error { + err := srv.repo.DeletePost(ctx, id) + + // Dispatch post deleted event + if err == nil { + srv.events.DispatchDeletedEvent(id) + } + + return err +} + +func (srv postService) GetFeedPosts(ctx context.Context) ([]*internal.Post, error) { + return srv.repo.GetFeedPosts(ctx) +} + +func (srv postService) GetUserPosts(ctx context.Context, userId string) ([]*internal.Post, error) { + return srv.repo.GetUserPosts(ctx, userId) +} + +func (srv postService) GetPanelPosts(ctx context.Context, panelId string) ([]*internal.Post, error) { + return srv.repo.GetPanelPosts(ctx, panelId) +} \ No newline at end of file