diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b3a31c2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "go/protocol"] + path = go/protocol + url = https://github.com/flowy-live/protocol diff --git a/go/Dockerfile b/go/Dockerfile new file mode 100644 index 0000000..e6c7ebd --- /dev/null +++ b/go/Dockerfile @@ -0,0 +1,22 @@ +# golang two stage build +FROM golang:1.25 AS first-stage + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download && go mod verify + +COPY . . + +WORKDIR /app/cmd/orion +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main +RUN ls + +FROM alpine:latest AS second-stage +# for health check +RUN apk --no-cache add curl + +WORKDIR /app +COPY --from=first-stage /app/cmd/orion . +RUN echo "copied over binary to production stage" +CMD ["./main"] diff --git a/go/Dockerfile.migrations b/go/Dockerfile.migrations new file mode 100644 index 0000000..149d7c1 --- /dev/null +++ b/go/Dockerfile.migrations @@ -0,0 +1,5 @@ +FROM migrate/migrate:latest + +WORKDIR / + +COPY ./migrations ./migrations diff --git a/go/Makefile b/go/Makefile new file mode 100644 index 0000000..77376a4 --- /dev/null +++ b/go/Makefile @@ -0,0 +1,50 @@ + +.PHONY: generate +generate: + ./genproto.sh + go generate ./... + +.PHONY: test +test: + go test -json ./... | docker run -i ghcr.io/gotesttools/gotestfmt:latest + +.PHONY: migrate-dev-db +migrate-dev-db: + ./migrate_dev.sh + +# .PHONY: migrate-prod-db +# migrate-prod-db: +# ./migrate_prod.sh + +# ex: make create-migration ARG="create_users_table" +create-migration: + echo "Creating migration with name $(ARG)" + docker run -v ./migrations:/migrations --network host migrate/migrate create -ext sql -seq -dir /migrations $(ARG) + +dev-database: + kubectl run postgres-client \ + --rm -it --image=postgres:latest \ + --env="LLINK_POSTGRES_CONNECTION_URL=$$(kubectl get secret shared-secrets -o jsonpath='{.data.LLINK_POSTGRES_CONNECTION_URL}' --context dev | base64 --decode)" \ + --context dev \ + --command -- /bin/bash -c "psql \$$LLINK_POSTGRES_CONNECTION_URL" + +# prod-database: +# kubectl run postgres-client \ +# --rm -it --image=postgres:latest \ +# --env="LLINK_POSTGRES_CONNECTION_URL=$$(kubectl get secret shared-secrets -o jsonpath='{.data.LLINK_POSTGRES_CONNECTION_URL}' --context prod | base64 --decode)" \ +# --context prod \ +# --command -- /bin/bash -c "psql \$$LLINK_POSTGRES_CONNECTION_URL" + +.PHONY: deploy-dev +deploy-dev: generate test + ./deploy_dev.sh + +# .PHONY: release +# deploy-prod: generate test +# # Check for any changes (both staged and unstaged) +# @if [ -n "$(git status --porcelain)" ]; then \ +# echo "Error: You have uncommitted changes in your Git repository."; \ +# exit 1; \ +# fi +# ./deploy_prod.sh +# diff --git a/go/cmd/orion/main.go b/go/cmd/orion/main.go new file mode 100644 index 0000000..24a1e05 --- /dev/null +++ b/go/cmd/orion/main.go @@ -0,0 +1,151 @@ +package main + +import ( + "context" + "fmt" + "log/slog" + "net/http" + "os" + + "cloud.google.com/go/storage" + pbaero "github.com/flowy-live/llink/genproto/aero" + "github.com/flowy-live/llink/internal" + "github.com/flowy-live/llink/internal/auth" + "github.com/flowy-live/llink/internal/db" + "github.com/flowy-live/llink/internal/depot" + "github.com/flowy-live/llink/internal/handler" + "github.com/flowy-live/llink/internal/human" + "github.com/flowy-live/llink/internal/middleware" + "github.com/flowy-live/llink/internal/network" + "github.com/flowy-live/llink/internal/particle" + "github.com/flowy-live/llink/internal/utils" + "github.com/redis/go-redis/v9" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +const ( + // FIX: Use separate redis instance. We start with higher number because use this same instance in helios. + REDIS_DATABASE_FOR_AUTH int = 4 +) + +func redisForAuth() *redis.Client { + return internal.ConnectAndTestRedis(REDIS_DATABASE_FOR_AUTH) +} + +func main() { + port := utils.MustGetEnv("PORT") + gcsBucket := utils.MustGetEnv("GCS_BUCKET") + + // Initialize database + db.Init() + defer db.Cleanup() + + // Initialize Redis for auth + redisClient := redisForAuth() + + // Initialize GCS client + ctx := context.Background() + storageClient, err := storage.NewClient(ctx) + if err != nil { + slog.Error("failed to create GCS client", "error", err) + os.Exit(1) + } + defer storageClient.Close() + + aeroAddr := utils.MustGetEnv("AERO_ADDR") + if aeroAddr == "" { + slog.Error("must provide AERO_ADDR") + os.Exit(1) + } + aeroServer, err := grpc.NewClient(aeroAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + slog.Error("connection to aero server invalid", "error", err) + os.Exit(1) + } + defer aeroServer.Close() + aeroSvc := pbaero.NewPrimaryClient(aeroServer) + + // Initialize services + authSvc := auth.NewAuthService(redisClient, aeroSvc) + humanSvc := human.NewService(db.Pool()) + networkSvc := network.NewService(db.Pool()) + particleSvc := particle.NewService(db.Pool(), networkSvc) + depotSvc := depot.NewService(db.Pool(), storageClient, depot.Config{ + GoogleServiceAccountEmail: utils.MustGetEnv("GOOGLE_SERVICE_ACCOUNT_EMAIL"), + BucketName: gcsBucket, + }) + + // Initialize handler + h := handler.NewHandler(authSvc, humanSvc, networkSvc, particleSvc, depotSvc) + + // Helper to wrap handlers with auth middleware + withAuth := func(hf http.HandlerFunc) http.Handler { + return middleware.Auth(authSvc)(http.HandlerFunc(hf)) + } + + mux := http.NewServeMux() + + // ========================================================================== + // Public routes (no auth) + // ========================================================================== + mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + mux.HandleFunc("POST /auth/request-code", h.RequestSignInCode) + mux.HandleFunc("POST /auth/sign-in", h.SignIn) + + // ========================================================================== + // Protected routes (auth required) + // ========================================================================== + + // Auth + mux.Handle("POST /auth/sign-out", withAuth(h.SignOut)) + mux.Handle("GET /auth/me", withAuth(h.GetCurrentHuman)) + + // Bootstrap startup data + mux.Handle("GET /startup", withAuth(h.StartupData)) + + // Networks + mux.Handle("POST /networks", withAuth(h.CreateNetwork)) + mux.Handle("GET /networks", withAuth(h.ListNetworks)) + mux.Handle("GET /networks/{id}", withAuth(h.GetNetwork)) + mux.Handle("POST /networks/{id}/members", withAuth(h.AddMembersToNetwork)) + // TODO: what about members who are part of streams visibility within this network? + mux.Handle("DELETE /networks/{id}/members/{email}", withAuth(h.RemoveMemberFromNetwork)) + mux.Handle("PUT /networks/{id}/capacity", withAuth(h.SetOpenStreamCapacity)) + + // Streams + mux.Handle("POST /networks/{network_id}/streams", withAuth(h.CreateStream)) + mux.Handle("GET /streams/{id}", withAuth(h.GetStream)) + mux.Handle("PATCH /streams/{id}", withAuth(h.UpdateStream)) + mux.Handle("POST /streams/{id}/particles", withAuth(h.CreateStreamParticle)) + mux.Handle("POST /streams/{id}/open", withAuth(h.OpenStream)) + mux.Handle("POST /streams/{id}/close", withAuth(h.CloseStream)) + mux.Handle("POST /streams/{id}/members", withAuth(h.AddMembers)) + mux.Handle("DELETE /streams/{id}/members", withAuth(h.RemoveMembers)) + + // Particles + mux.Handle("GET /networks/{network_id}/particles", withAuth(h.ListParticles)) + mux.Handle("GET /particles/{id}", withAuth(h.GetParticle)) + mux.Handle("PATCH /particles/{id}", withAuth(h.UpdateParticle)) + mux.Handle("DELETE /particles/{id}", withAuth(h.DeleteParticle)) + mux.Handle("POST /particles/{id}/seen", withAuth(h.MarkSeen)) + mux.Handle("POST /particles/{id}/ack", withAuth(h.AckParticle)) + mux.Handle("GET /particles/{id}/download", withAuth(h.DownloadParticle)) + mux.Handle("POST /particles/seen", withAuth(h.MarkSeenBatch)) + + // Depot + mux.Handle("POST /depot/upload", withAuth(h.PrepareUpload)) + mux.Handle("POST /depot/objects/{id}/confirm", withAuth(h.ConfirmUpload)) + + addr := fmt.Sprintf("0.0.0.0:%s", port) + slog.Info("running server", "addr", addr) + if err := http.ListenAndServe(addr, mux); err != nil { + slog.Error("server failed", "error", err) + os.Exit(1) + } +} diff --git a/go/deploy_dev.sh b/go/deploy_dev.sh new file mode 100755 index 0000000..a08a341 --- /dev/null +++ b/go/deploy_dev.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +export KUBE_CONTEXT=dev +export SKAFFOLD_DEFAULT_REPO=us-west2-docker.pkg.dev/flowy-dev-440017/deployments +skaffold run -p dev --kube-context dev --port-forward --tail diff --git a/go/docker-compose.yaml b/go/docker-compose.yaml new file mode 100644 index 0000000..8d7c8a5 --- /dev/null +++ b/go/docker-compose.yaml @@ -0,0 +1,35 @@ +version: '3.8' + +services: + postgres: + image: postgres:16 + restart: always + environment: + POSTGRES_USER: username + POSTGRES_PASSWORD: password + POSTGRES_DB: mydatabase + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + networks: + - app-network + + redis: + image: redis:latest + restart: always + command: redis-server --appendonly yes + ports: + - "6379:6379" + volumes: + - redis_data:/data + networks: + - app-network + +volumes: + postgres_data: + redis_data: + +networks: + app-network: + driver: bridge diff --git a/go/docs/api.md b/go/docs/api.md new file mode 100644 index 0000000..c44ac1c --- /dev/null +++ b/go/docs/api.md @@ -0,0 +1,617 @@ +# API Documentation + +All protected endpoints require a `Bearer` token in the `Authorization` header. + +## Authentication + +### Request Sign-In Code +`POST /auth/request-code` + +Sends a 4-digit sign-in code to the provided email. Creates user if not exists. + +**Request Body:** +```json +{ + "email": "user@example.com" +} +``` + +**Response:** `204 No Content` + +### Sign In +`POST /auth/sign-in` + +Verifies the code and returns a session token. + +**Request Body:** +```json +{ + "email": "user@example.com", + "code": "1234" +} +``` + +**Response:** +```json +{ + "human": { "id": "...", "email": "...", "email_prefix": "...", "created_at": "..." }, + "token": "session_token" +} +``` + +### Sign Out +`POST /auth/sign-out` (Protected) + +Invalidates the current session. Returns `204 No Content`. + +### Get Current User +`GET /auth/me` (Protected) + +Returns the authenticated user. + +--- + +## Startup + +### Get Startup Data +`GET /startup` (Protected) + +Bootstrap endpoint for initial app load. Returns all networks the user belongs to, with all streams and their particles fully enriched. + +**Response:** +```json +{ + "networks": [ + { + "id": "net-456", + "name": "My Team", + "admin_human": { "id": "...", "email": "...", "email_prefix": "...", "created_at": "..." }, + "humans": [{ "id": "...", "email": "...", "email_prefix": "...", "created_at": "..." }], + "open_stream_count": 2, + "open_stream_capacity": 5, + "created_at": "2025-01-15T10:30:00Z", + "streams": [ + { + "id": "p-001", + "name": "Sprint Planning", + "description": "Weekly sync", + "status": "open", + "members": ["alice@example.com"], + "particles": [ + { + "id": "p-002", + "type": "text", + "data": { "content": "Hello" }, + "created_by_email": "alice@example.com", + "seen": true, + "acks": [], + "updated_at": "...", + "created_at": "..." + } + ], + "unseen_count": 0 + } + ] + } + ] +} +``` + +--- + +## Networks + +### Create Network +`POST /networks` (Protected) + +**Request Body:** +```json +{ + "name": "My Network" +} +``` + +### List Networks +`GET /networks` (Protected) + +Returns all networks the user is a member of. + +### Get Network +`GET /networks/{id}` (Protected) + +Returns a specific network by ID. + +### Add Members to Network +`POST /networks/{id}/members` (Protected) + +**Request Body:** +```json +{ + "email_addresses": ["user1@example.com", "user2@example.com"] +} +``` + +### Remove Member from Network +`DELETE /networks/{id}/members/{email}` (Protected) + +Removes a member by email from the network. + +### Set Open Stream Capacity +`PUT /networks/{id}/capacity` (Protected, Admin only) + +**Request Body:** +```json +{ + "capacity": 10 +} +``` + +--- + +## Streams + +Streams are top-level particles of type `stream`. They have dedicated endpoints for creation and management, and contain child particles. + +### Create Stream +`POST /networks/{network_id}/streams` (Protected) + +**Request Body:** +```json +{ + "name": "Sprint Planning", + "description": "Weekly sync", + "visibility": "custom", + "members": ["user@example.com"] +} +``` + +- `visibility`: `network_all` (default) or `custom` +- `members` is required when visibility is `custom` + +**Response:** `201 Created` — returns a [Stream](#stream-1) object. + +### Get Stream +`GET /streams/{id}` (Protected) + +Returns a stream with all its child particles, enriched with seen/ack state. + +**Response:** returns a [Stream](#stream-1) object. + +### Update Stream +`PATCH /streams/{id}` (Protected) + +Updates a stream's name and/or description. Status is not affected (use the open/close endpoints instead). Only provided fields are updated. + +**Request Body:** +```json +{ + "name": "New Name", + "description": "New description" +} +``` + +- Both fields are optional — omit a field to leave it unchanged +- `name` cannot be empty if provided + +**Response:** returns the updated [Stream](#stream-1) object. + +### Create Stream Particle +`POST /streams/{id}/particles` (Protected) + +Creates a child particle inside a stream. Child particles inherit visibility from the stream. + +**Request Body:** +```json +{ + "type": "text|media|file|quest|paper", + "data": {} +} +``` + +- Cannot create `stream` or `folder` types as children +- For `media` and `file` types, `data` must include a valid `object_id` from depot + +**Response:** `201 Created` — returns a [StreamParticle](#streamparticle) object. + +### Open Stream +`POST /streams/{id}/open` (Protected) + +Opens a closed stream. Fails with `409` if capacity would be exceeded. + +### Close Stream +`POST /streams/{id}/close` (Protected) + +Closes an open stream. + +### Add Members to Stream +`POST /streams/{id}/members` (Protected) + +**Request Body:** +```json +{ + "emails": ["user@example.com"] +} +``` + +### Remove Members from Stream +`DELETE /streams/{id}/members` (Protected) + +**Request Body:** +```json +{ + "emails": ["user@example.com"] +} +``` + +--- + +## Particles + +### List Particles +`GET /networks/{network_id}/particles` (Protected) + +**Query Parameters:** +- `parent_id` (optional): Filter by parent particle +- `cursor` (optional): Pagination cursor +- `direction` (optional): `after` or `before` (default: `after`) +- `type` (optional, repeatable): Filter by particle type + +**Response enrichment:** +Each particle in the response includes: +- `seen` (boolean): Whether the requester has marked this particle as seen +- `acks` (array): List of acknowledgments `[{email, acked_at}]` +- `unseen_count` (integer, streams only): Count of unseen child particles + +### Get Particle +`GET /particles/{id}` (Protected) + +### Update Particle +`PATCH /particles/{id}` (Protected) + +**Request Body:** +```json +{ + "data": {} +} +``` + +### Delete Particle +`DELETE /particles/{id}` (Protected) + +Deletes the particle and all children. If it references a depot object, that is also deleted. + +### Download Particle +`GET /particles/{id}/download` (Protected) + +Returns a `302` redirect to a signed download URL. Only works for `media` and `file` particles. + +### Mark Seen +`POST /particles/{id}/seen` (Protected) + +Marks a particle as seen by the requester. This is private state, only visible to the requester. + +Returns `204 No Content` on success. + +### Mark Seen (Batch) +`POST /particles/seen` (Protected) + +Marks multiple particles as seen by the requester. + +**Request Body:** +```json +{ + "particle_ids": ["particle_uuid1", "particle_uuid2"] +} +``` + +Returns `204 No Content` on success. + +### Acknowledge Particle +`POST /particles/{id}/ack` (Protected) + +Acknowledges a particle. Acknowledgments are public and permanent, visible to all users with access. Also marks the particle as seen. + +Returns `204 No Content` on success. + +--- + +## Depot (File Storage) + +### Prepare Upload +`POST /depot/upload` (Protected) + +Prepares a signed URL for direct upload to GCS. + +**Request Body:** +```json +{ + "network_id": "network_uuid", + "name": "filename.png", + "content_type": "image/png", + "content_length": 12345 +} +``` + +**Response:** +```json +{ + "object_id": "uuid", + "upload_url": "https://storage.googleapis.com/...", + "upload_headers": { "Content-Type": "image/png" } +} +``` + +### Confirm Upload +`POST /depot/objects/{id}/confirm` (Protected) + +Confirms that an upload has been completed. + +**Response:** +```json +{ + "id": "uuid", + "name": "filename.png", + "content_type": "image/png", + "content_length": 12345, + "contains_content": true, + "created_at": "..." +} +``` + +### Upload Flow + +1. `POST /depot/upload` — get signed URL and `object_id` +2. Upload file directly to GCS using the signed URL +3. `POST /depot/objects/{id}/confirm` — mark upload complete +4. Create a `media` or `file` particle with the `object_id` in its data + +--- + +## Object Reference + +### Human + +| Field | Type | Description | +|-------|------|-------------| +| `id` | `string \| null` | Unique identifier. Null if not yet registered. | +| `email` | `string` | Email address (stable identifier). | +| `email_prefix` | `string` | The local part of the email (before `@`). | +| `created_at` | `string \| null` | ISO 8601 timestamp. Null if not registered. | + +```json +{ + "id": "abc-123", + "email": "alice@example.com", + "email_prefix": "alice", + "created_at": "2025-01-15T10:30:00Z" +} +``` + +### Network + +| Field | Type | Description | +|-------|------|-------------| +| `id` | `string` | Unique identifier. | +| `name` | `string` | Display name of the network. | +| `admin_human` | `Human` | The network administrator. | +| `humans` | `Human[]` | All members of the network (including admin). | +| `open_stream_count` | `integer` | Number of currently open streams. | +| `open_stream_capacity` | `integer` | Maximum number of concurrent open streams (default: 5). | +| `created_at` | `string` | ISO 8601 timestamp. | + +```json +{ + "id": "net-456", + "name": "My Team", + "admin_human": { "id": "abc-123", "email": "alice@example.com", "email_prefix": "alice", "created_at": "..." }, + "humans": [ + { "id": "abc-123", "email": "alice@example.com", "email_prefix": "alice", "created_at": "..." } + ], + "open_stream_count": 2, + "open_stream_capacity": 5, + "created_at": "2025-01-15T10:30:00Z" +} +``` + +### Stream + +| Field | Type | Description | +|-------|------|-------------| +| `id` | `string` | Unique identifier (this is a particle ID). | +| `name` | `string` | Stream name. | +| `description` | `string` | Stream description. | +| `status` | `string` | `"open"`, `"closed"`, or `"unspecified"`. | +| `members` | `string[]` | Emails of stream members. Omitted for `network_all` visibility. | +| `particles` | `StreamParticle[]` | Child particles in the stream. | +| `unseen_count` | `integer` | Number of unseen child particles for the requester. | + +```json +{ + "id": "p-001", + "name": "Sprint Planning", + "description": "Weekly sync", + "status": "open", + "members": ["alice@example.com"], + "particles": [], + "unseen_count": 0 +} +``` + +### StreamParticle + +| Field | Type | Description | +|-------|------|-------------| +| `id` | `string` | Unique identifier. | +| `type` | `string` | One of: `media`, `file`, `text`, `quest`, `paper`. | +| `data` | `object` | Type-specific payload (see [Particle Data by Type](#particle-data-by-type)). | +| `created_by_email` | `string` | Email of the creator. | +| `seen` | `boolean` | Whether the requester has seen this particle. | +| `acks` | `AckInfo[]` | Acknowledgments from users. | +| `updated_at` | `string` | ISO 8601 timestamp. | +| `created_at` | `string` | ISO 8601 timestamp. | + +### Particle + +| Field | Type | Description | +|-------|------|-------------| +| `id` | `string` | Unique identifier. | +| `type` | `string` | One of: `stream`, `folder`, `media`, `file`, `text`, `quest`, `paper`. | +| `network_id` | `string` | The network this particle belongs to. | +| `parent_id` | `string \| null` | Parent particle ID, if nested. | +| `created_by_email` | `string` | Email of the creator. | +| `visibility` | `string` | `"network_all"`, `"custom"`, or `"inherited"`. | +| `stream_status` | `string \| null` | Only on `stream` type: `"open"` or `"closed"`. | +| `data` | `object` | Type-specific payload (see [Particle Data by Type](#particle-data-by-type)). | +| `download_url` | `string \| null` | Signed download URL. Only on `media`/`file` particles. | +| `seen` | `boolean \| null` | Whether the requester has seen this particle. Only in list responses. | +| `acks` | `AckInfo[]` | Acknowledgments. Only in list responses. | +| `unseen_count` | `integer \| null` | Unseen child count. Only on `stream` particles in list responses. | +| `updated_at` | `string` | ISO 8601 timestamp. | +| `created_at` | `string` | ISO 8601 timestamp. | + +### AckInfo + +| Field | Type | Description | +|-------|------|-------------| +| `email` | `string` | Email of the user who acknowledged. | +| `acked_at` | `string` | ISO 8601 timestamp of the acknowledgment. | + +### ParticleList + +Returned by `GET /networks/{network_id}/particles`. + +| Field | Type | Description | +|-------|------|-------------| +| `particles` | `Particle[]` | Array of enriched particle objects. | +| `has_more` | `boolean` | Whether more results exist beyond this page. | +| `next_cursor` | `string \| null` | Cursor to fetch the next page. | +| `prev_cursor` | `string \| null` | Cursor to fetch the previous page. | + +### DepotObject + +Returned by `POST /depot/objects/{id}/confirm`. + +| Field | Type | Description | +|-------|------|-------------| +| `id` | `string` | Unique object identifier. | +| `name` | `string` | Original filename. | +| `content_type` | `string` | MIME type (e.g. `image/png`). | +| `content_length` | `integer` | Size in bytes. | +| `contains_content` | `boolean` | Whether the object has been uploaded successfully. | +| `created_at` | `string` | ISO 8601 timestamp. | + +--- + +## Particle Data by Type + +The `data` field on a Particle is a JSON object whose schema depends on the particle's `type`. + +### `stream` + +| Field | Type | Description | +|-------|------|-------------| +| `name` | `string` | Stream name (required). | +| `status` | `string` | `"open"` or `"closed"` (required). | +| `description` | `string \| null` | Stream description (optional). | + +```json +{ "name": "Sprint Planning", "status": "open", "description": "Weekly sync" } +``` + +### `folder` + +| Field | Type | Description | +|-------|------|-------------| +| `name` | `string` | Folder name (required). | +| `color` | `string \| null` | Display color (optional). | + +```json +{ "name": "Design Assets", "color": "#FF5733" } +``` + +### `media` + +| Field | Type | Description | +|-------|------|-------------| +| `object_id` | `string` | Reference to depot storage object (required). | +| `mime_type` | `string` | MIME type of the media (required). | +| `duration_ms` | `integer` | Duration in milliseconds, must be > 0 (required). | + +```json +{ "object_id": "obj-123", "mime_type": "image/jpeg", "duration_ms": 5000 } +``` + +### `file` + +| Field | Type | Description | +|-------|------|-------------| +| `object_id` | `string` | Reference to depot storage object (required). | +| `filename` | `string` | Original filename (required). | +| `mime_type` | `string` | MIME type (required). | +| `size` | `integer` | File size in bytes, must be > 0 (required). | + +```json +{ "object_id": "obj-456", "filename": "report.pdf", "mime_type": "application/pdf", "size": 204800 } +``` + +### `text` + +| Field | Type | Description | +|-------|------|-------------| +| `content` | `string` | Text content (required). | + +```json +{ "content": "Hello world" } +``` + +### `quest` + +| Field | Type | Description | +|-------|------|-------------| +| `title` | `string` | Quest/task title (required). | +| `description` | `string` | Details about the quest (required). | +| `status` | `string \| null` | Current status (optional, e.g. `"todo"`, `"in_progress"`, `"done"`). | +| `assigned_to` | `string \| null` | Email of the assigned user (optional). | +| `due_date` | `string \| null` | ISO date string (optional, e.g. `"2025-03-01"`). | + +```json +{ "title": "Fix login bug", "description": "Login fails on Safari", "status": "todo", "assigned_to": "bob@example.com" } +``` + +### `paper` + +| Field | Type | Description | +|-------|------|-------------| +| `title` | `string` | Document title (required). | +| `content` | `string` | Document body in markdown (required). | + +```json +{ "title": "Architecture RFC", "content": "## Overview\n..." } +``` + +--- + +## Visibility + +Particles support three visibility modes: + +| Mode | Description | +|------|-------------| +| `network_all` | Visible to all network members. | +| `custom` | Visible only to specified members (requires `members` list). | +| `inherited` | Inherits visibility from parent particle. Used for child particles in streams. | + +Root-level particles (streams, folders) use `network_all` or `custom`. Child particles created via `POST /streams/{id}/particles` automatically use `inherited`. + +--- + +## Error Responses + +All endpoints return standard HTTP status codes with plain text error bodies: + +- **400** Bad Request — invalid input or missing required fields +- **401** Unauthorized — missing or invalid auth token +- **403** Forbidden — user lacks permission (not a member, not creator, not admin) +- **404** Not Found — resource doesn't exist +- **409** Conflict — state conflict (stream already open/closed, capacity exceeded) +- **500** Internal Server Error diff --git a/go/docs/design-decisions.md b/go/docs/design-decisions.md new file mode 100644 index 0000000..577aded --- /dev/null +++ b/go/docs/design-decisions.md @@ -0,0 +1,39 @@ +# Design Decisions + +## Email as Identifier + +Email is used as the stable identifier across services (auth, human, network). + +**Trade-off:** Email changes are not supported. Users who want a different email create a new account. + +**Rationale:** +- Keeps services decoupled (no foreign keys between domains) +- Simpler queries - no joins needed +- Consistent across all services + +This is a product decision, not a technical limitation. + +## Domain Packages + +Each domain (`internal/human/`, `internal/network/`) is isolated. Implementation details (data access, internal errors) are private to the package. Only the service interface, domain types, and exported errors are public. + +## Handler Orchestration for Cross-Domain Concerns + +The particle service stores `object_id` references for media/file types, not URLs. Object storage (upload URLs, signed download URLs) is handled by a separate depot service. + +**Pattern:** Handlers orchestrate multiple services; domain services stay pure. + +``` +Client -> Handler -> [Depot Service, Particle Service] +``` + +- **Create media/file:** Handler calls depot for upload URL, client uploads directly to storage, then handler creates particle with `object_id` +- **Fetch media/file:** Handler gets particle, then enriches response with signed URL from depot + +**Rationale:** +- Particle service focuses on hierarchy, access control, metadata +- Depot service focuses on blob storage, signing, lifecycle +- Handlers are already the coordination layer +- Services remain independently testable and evolvable + +**Same pattern applies to:** Drafts (auto-save state), real-time presence, or other concerns that don't belong in the core particle model. diff --git a/go/docs/particle-hierarchy-storage.md b/go/docs/particle-hierarchy-storage.md new file mode 100644 index 0000000..24c30e2 --- /dev/null +++ b/go/docs/particle-hierarchy-storage.md @@ -0,0 +1,110 @@ +# Particle Hierarchy & Storage Organization + +## The Question + +Particles form a recursive file-system-like hierarchy (streams contain folders, folders contain files, etc.). Should we align the logical hierarchy with physical storage paths? + +``` +Logical: stream_123 -> folder_456 -> file_789 +Storage: gs://bucket/stream_123/folder_456/file_789/document.pdf +``` + +## Two Approaches + +### Adjacency List (Current) + +Each particle stores a reference to its parent: + +```sql +CREATE TABLE particles ( + id TEXT PRIMARY KEY, + parent_id TEXT REFERENCES particles(id), + ... +); +``` + +**To get ancestors:** Recursive CTE query +**To move a particle:** Update one `parent_id` +**Storage path:** Independent, based on `object_id` + +### Materialized Path + +Each particle stores its full path: + +```sql +CREATE TABLE particles ( + id TEXT PRIMARY KEY, + path TEXT UNIQUE, -- '/net_abc/stream_123/folder_456' + ... +); +``` + +**To get ancestors:** Parse the path string +**To get descendants:** `WHERE path LIKE '/net_abc/stream_123/%'` +**To move a particle:** Update paths of particle AND all descendants + +## Why Materialized Path is Tempting + +If `path` doubles as the storage URI: + +``` +Particle path: /net_abc/stream_123/folder_456/file_789 +Storage URI: gs://bucket/net_abc/stream_123/folder_456/file_789/video.mp4 +``` + +- Single source of truth for "where things live" +- No recursive queries for hierarchy +- Elegant alignment between logical and physical structure + +## Why It Breaks Down + +**Moves are expensive:** + +Moving `folder_456` under a different stream requires: +1. Update `folder_456.path` +2. Update paths of ALL descendants (could be thousands) +3. Move ALL storage objects to new GCS paths + +GCS "moves" are copy + delete operations: +- Slow and costs money +- Links/references break during move +- Concurrent access during move is undefined +- Failure mid-move leaves inconsistent state + +**Storage should be immutable:** + +Once a file is uploaded to `gs://bucket/obj_abc123`, that path should never change. This enables: +- Stable URLs (even if signed) +- CDN caching +- No coordination during particle reorganization + +## Decision: Keep Them Decoupled + +``` +Logical hierarchy: parent_id references (mutable, cheap to change) +Physical storage: object_id (immutable, never moves) +``` + +| Operation | Adjacency List | Materialized Path | +|-----------|---------------|-------------------| +| Move particle | O(1) - update parent_id | O(n) - update all descendant paths + move storage | +| Get ancestors | O(depth) recursive query | O(1) parse path | +| Get descendants | O(n) recursive query | O(1) prefix match | +| Storage move | Not needed | Required on every move | + +The read optimization of materialized paths doesn't justify the write complexity, especially when writes involve physical storage operations. + +## Storage Organization + +Objects are stored with stable IDs, optionally prefixed by network for operational convenience: + +``` +gs://bucket/{network_id}/{object_id}/{original_filename} +``` + +This enables: +- Bulk operations per network (audit, delete, lifecycle policies) +- Preserved original filename for downloads +- No coupling to particle hierarchy + +The particle stores `object_id` in its data. The depot service handles signed URL generation. The particle's logical position in the hierarchy is independent of where its assets physically live. diff --git a/go/docs/particle-system-plan.md b/go/docs/particle-system-plan.md new file mode 100644 index 0000000..7fbfb8d --- /dev/null +++ b/go/docs/particle-system-plan.md @@ -0,0 +1,694 @@ +# Particle System & Network Capacity Implementation Plan + +## Summary + +Implement a unified particle system where all content types (streams, folders, media, files, text, quests, papers, AI chats) are particles with a common structure but type-specific data. Add network capacity management for billing/limiting open streams. + +--- + +## Key Design Decisions + +| Decision | Choice | +|----------|--------| +| Data model | Unified particle with `type` field + JSONB `data` | +| Hierarchy | Arbitrary nesting (parent_id references another particle) | +| Access control | Split: Handler checks network membership, Particle service checks particle visibility | +| Stream membership | Auto-visible to all network members OR custom member list | +| Open streams | Only "open" streams count against capacity | +| Substream counting | All stream particles count (including nested) | +| Service coupling | **Loose** - no FK constraints, particle service is independent | +| Listing API | Unified `ListParticles(networkID, parentID, ...)` - file explorer style | +| Sorting | Streams: `updated_at DESC` (activity), Folders: `created_at` (client sorts by type) | +| Pagination | Bidirectional cursor for streams (chat-like); folders return all | +| Network capacity | Stored on networks table (`open_stream_capacity`), updated via admin API | +| Data validation | Start simple with required field validation in service code | + +--- + +## Architecture: Access Control Split + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ HANDLER LAYER │ +│ 1. Extract user email from auth context │ +│ 2. Check network membership (via network service) │ +│ 3. Call particle service with (networkID, email) │ +│ 4. Transform Particle structs → Response DTOs │ +└─────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ PARTICLE SERVICE │ +│ - Trusts that handler verified network membership │ +│ - Checks particle-level visibility (network_all vs custom) │ +│ - Filters results to only particles user can see │ +│ - Returns Particle domain structs │ +│ - NO dependency on network service │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +**Why this split?** +- Particle service stays decoupled from network service +- Network membership is a cross-cutting concern (handler already knows user context) +- Particle visibility is domain-specific (belongs in particle service) + +--- + +## UI Data Flow Examples + +### Mental Model: File Explorer + +The API follows a file explorer pattern: +- `parentID = nil` → root items of network +- `parentID = "p_123"` → children of that particle +- Same method works at every level +- Response includes parent for breadcrumbs/context + +### Example 1: User Opens App → Network Sidebar + +``` +┌─────────────────────────────────────────────────────┐ +│ Streams in Acme Corp │ +│ ├─ 📂 Projects (folder) │ +│ │ ├─ 💬 Website Redesign (stream, open) │ +│ │ └─ 💬 Mobile App (stream, closed) │ +│ ├─ 💬 General Chat (stream, open) │ +│ └─ 💬 Support Tickets (stream, open) │ +└─────────────────────────────────────────────────────┘ +``` + +**API Calls:** + +```go +// 1. Get root particles for selected network +resp := particleService.ListParticles(ctx, "net_abc", nil, email, ListFilter{}, nil) +// Returns: +// { +// Parent: nil, // No parent at root +// Particles: [ +// {ID: "p_1", Type: "folder", Data: {"name": "Projects"}, ...}, +// {ID: "p_2", Type: "stream", Data: {"title": "General Chat"}, StreamStatus: "open"}, +// {ID: "p_3", Type: "stream", Data: {"title": "Support Tickets"}, StreamStatus: "open"}, +// ] +// } + +// 2. User clicks "Projects" folder → fetch children +resp := particleService.ListParticles(ctx, "net_abc", ptr("p_1"), email, ListFilter{}, nil) +// Returns: +// { +// Parent: {ID: "p_1", Type: "folder", Data: {"name": "Projects"}}, // For breadcrumbs +// Particles: [ +// {ID: "p_4", Type: "stream", Data: {"title": "Website Redesign"}, StreamStatus: "open"}, +// {ID: "p_5", Type: "stream", Data: {"title": "Mobile App"}, StreamStatus: "closed"}, +// ] +// } +``` + +### Example 2: User Opens Stream → Chat View + +``` +┌─────────────────────────────────────────────────────┐ +│ 💬 Website Redesign [Members] │ +├─────────────────────────────────────────────────────┤ +│ ↑ Load older │ +│ ───────────────────────────────────────────────── │ +│ [Alice] Here's the new mockup │ +│ 📎 mockup-v2.png (media particle) │ +│ ───────────────────────────────────────────────── │ +│ [Bob] Looks great! Question about nav │ +│ ───────────────────────────────────────────────── │ +│ 📋 Update navigation colors (quest) │ +│ ───────────────────────────────────────────────── │ +│ [Type a message...] [Send] │ +└─────────────────────────────────────────────────────┘ +``` + +**API Calls:** + +```go +// 1. Initial load - most recent particles (sorted by updated_at DESC) +resp := particleService.ListParticles(ctx, networkID, ptr("stream_123"), email, ListFilter{}, nil) +// Returns: +// { +// Parent: {ID: "stream_123", Type: "stream", Data: {"title": "Website Redesign"}}, +// Particles: [newest...oldest], // Sorted by updated_at DESC +// HasMore: true, +// PrevCursor: {Position: "p_oldest_in_batch", Direction: "before"}, +// NextCursor: nil // At newest +// } + +// 2. User scrolls UP → load older messages +resp := particleService.ListParticles(ctx, networkID, ptr("stream_123"), email, ListFilter{}, + &Cursor{Position: "p_oldest_in_batch", Direction: "before"}) + +// 3. User scrolls DOWN → load newer (after scrolling up) +resp := particleService.ListParticles(ctx, networkID, ptr("stream_123"), email, ListFilter{}, + &Cursor{Position: "some_id", Direction: "after"}) + +// 4. User sends message +newParticle := particleService.Create(ctx, CreateInput{ + Type: TypeText, + NetworkID: networkID, + ParentID: ptr("stream_123"), + Data: json.RawMessage(`{"content": "My message"}`), +}, email) +// UI inserts at bottom +``` + +### Handler Implementation + +```go +// Handler pseudocode +func (h *Handler) ListParticles(w http.ResponseWriter, r *http.Request) { + email := getAuthEmail(r.Context()) + networkID := r.URL.Query().Get("network_id") + parentID := r.URL.Query().Get("parent_id") // Optional + + // 1. Check network membership (handler responsibility) + network, err := h.networkService.GetByID(ctx, networkID) + if err != nil { return NotFound } + + if !network.HasMember(email) && network.AdminEmail != email { + return Forbidden("not a network member") + } + + // 2. Parse cursor if provided + var cursor *particle.Cursor + if r.URL.Query().Has("cursor") { + cursor = parseCursor(r.URL.Query().Get("cursor")) + } + + // 3. Call particle service + var parentPtr *string + if parentID != "" { + parentPtr = &parentID + } + + result, err := h.particleService.ListParticles(ctx, networkID, parentPtr, email, filter, cursor) + if err != nil { return err } + + // 4. Transform to response + json.NewEncoder(w).Encode(toParticleListResponse(result)) +} +``` + +### Response DTO structure + +```go +// Handler layer DTOs (in handler.go) +type ParticleResponse struct { + ID string `json:"id"` + Type string `json:"type"` + NetworkID string `json:"network_id"` + ParentID *string `json:"parent_id,omitempty"` + Visibility string `json:"visibility"` + StreamStatus *string `json:"stream_status,omitempty"` // Only for streams + Data json.RawMessage `json:"data"` + CreatedBy string `json:"created_by"` + UpdatedAt string `json:"updated_at"` + CreatedAt string `json:"created_at"` +} + +// Transform function +func toParticleResponse(p *particle.Particle) ParticleResponse { + return ParticleResponse{ + ID: p.ID, + Type: string(p.Type), + NetworkID: p.NetworkID, + ParentID: p.ParentID, + Visibility: string(p.Visibility), + StreamStatus: (*string)(p.StreamStatus), + Data: p.Data, + CreatedBy: p.CreatedByEmail, + UpdatedAt: p.UpdatedAt.Format(time.RFC3339), + CreatedAt: p.CreatedAt.Format(time.RFC3339), + } +} +``` + +--- + +## Particle Types + +| Type | Purpose | Required Data Fields | +|------|---------|---------------------| +| `stream` | Temporal container (chat-like) | `title` | +| `folder` | Structural container | `name` | +| `media` | Images, video, audio, clips | `url`, `mime_type` | +| `file` | Documents, PDFs, attachments | `url`, `filename` | +| `text` | Quick text messages | `content` | +| `quest` | Tasks/requests | `title` | +| `paper` | Rich documents | `title` | +| `think` | AI chat container | `title` | + +**Note:** Quest with `assigned_to = current_user` is presented as a "request" in UI. + +--- + +## Database Schema + +### Migration 1: Network Capacity + +```sql +-- migrations/000003_network_capacity.up.sql +ALTER TABLE networks + ADD COLUMN open_stream_capacity INTEGER NOT NULL DEFAULT 5, + ADD COLUMN open_stream_count INTEGER NOT NULL DEFAULT 0; +``` + +```sql +-- migrations/000003_network_capacity.down.sql +ALTER TABLE networks + DROP COLUMN open_stream_capacity, + DROP COLUMN open_stream_count; +``` + +### Migration 2: Particles + +```sql +-- migrations/000004_particles.up.sql + +CREATE TYPE particle_type AS ENUM ( + 'stream', 'folder', 'media', 'file', 'text', 'quest', 'paper', 'think' +); + +CREATE TYPE visibility_mode AS ENUM ('network_all', 'custom'); + +CREATE TABLE particles ( + id TEXT PRIMARY KEY, + type particle_type NOT NULL, + network_id TEXT NOT NULL, -- NO FK constraint, loose coupling + parent_id TEXT, -- NO FK constraint, loose coupling + created_by_email VARCHAR(255) NOT NULL, + visibility visibility_mode NOT NULL DEFAULT 'network_all', + + -- Stream-specific (NULL for non-streams) + stream_status VARCHAR(20) CHECK (stream_status IN ('open', 'closed')), + + -- Type-specific data + data JSONB NOT NULL DEFAULT '{}', + + -- Timestamps + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + + CONSTRAINT stream_status_check CHECK ( + (type = 'stream' AND stream_status IS NOT NULL) OR + (type != 'stream' AND stream_status IS NULL) + ) +); + +CREATE TABLE particle_members ( + particle_id TEXT NOT NULL, -- NO FK constraint + email VARCHAR(255) NOT NULL, + added_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (particle_id, email) +); + +-- Indexes for query performance +CREATE INDEX idx_particles_parent_updated ON particles(parent_id, updated_at DESC); +CREATE INDEX idx_particles_network_root ON particles(network_id, updated_at DESC) WHERE parent_id IS NULL; +CREATE INDEX idx_particles_open_streams ON particles(network_id) WHERE type = 'stream' AND stream_status = 'open'; +CREATE INDEX idx_particle_members_email ON particle_members(email, particle_id); +CREATE INDEX idx_particles_network_id ON particles(network_id); +``` + +```sql +-- migrations/000004_particles.down.sql +DROP TABLE IF EXISTS particle_members; +DROP TABLE IF EXISTS particles; +DROP TYPE IF EXISTS visibility_mode; +DROP TYPE IF EXISTS particle_type; +``` + +--- + +## Service Layer Design + +### Package Structure + +``` +internal/particle/ +├── models.go # Particle struct, type constants, data structs +├── errors.go # ErrNotFound, ErrCapacityExceeded, ErrAccessDenied +├── repository.go # Database operations (internal) +├── service.go # Public Service interface + implementation +├── validation.go # Type-specific validation (simple required fields) +└── service_test.go # Integration tests +``` + +### Domain Models + +```go +// internal/particle/models.go + +type ParticleType string + +const ( + TypeStream ParticleType = "stream" + TypeFolder ParticleType = "folder" + TypeMedia ParticleType = "media" + TypeFile ParticleType = "file" + TypeText ParticleType = "text" + TypeQuest ParticleType = "quest" + TypePaper ParticleType = "paper" + TypeThink ParticleType = "think" +) + +type VisibilityMode string + +const ( + VisibilityNetworkAll VisibilityMode = "network_all" + VisibilityCustom VisibilityMode = "custom" +) + +type StreamStatus string + +const ( + StreamOpen StreamStatus = "open" + StreamClosed StreamStatus = "closed" +) + +type Particle struct { + ID string + Type ParticleType + NetworkID string + ParentID *string + CreatedByEmail string + Visibility VisibilityMode + StreamStatus *StreamStatus // Only for type=stream + Data json.RawMessage + UpdatedAt time.Time + CreatedAt time.Time +} + +type CreateInput struct { + Type ParticleType + NetworkID string + ParentID *string + Visibility VisibilityMode + Data json.RawMessage + MemberEmails []string // For custom visibility +} + +type ListFilter struct { + Types []ParticleType + StreamStatus *StreamStatus +} + +type Cursor struct { + Position string // particle ID or timestamp + Direction string // "before" | "after" +} + +type ParticleList struct { + Parent *Particle // The parent particle (nil if root level) + Particles []*Particle + HasMore bool + NextCursor *Cursor // For loading more in same direction + PrevCursor *Cursor // For bidirectional (streams) +} +``` + +### Service Interface + +```go +// internal/particle/service.go + +type Service interface { + // Core CRUD + // Note: Caller (handler) is responsible for verifying network membership + // Service handles particle-level visibility filtering + + Create(ctx context.Context, input CreateInput, creatorEmail string) (*Particle, error) + GetByID(ctx context.Context, id, requesterEmail string) (*Particle, error) + Update(ctx context.Context, id string, data json.RawMessage, requesterEmail string) (*Particle, error) + Delete(ctx context.Context, id, requesterEmail string) error + + // Unified listing - file explorer style + // - parentID = nil → root particles of network + // - parentID = "p_123" → children of that particle + // - Automatically filters by visibility + // - Streams: sorted by updated_at DESC (activity-based) + // - Folders: sorted by created_at (client can re-sort by type) + ListParticles(ctx context.Context, networkID string, parentID *string, requesterEmail string, filter ListFilter, cursor *Cursor) (*ParticleList, error) + + // Stream lifecycle + OpenStream(ctx context.Context, id, requesterEmail string) error + CloseStream(ctx context.Context, id, requesterEmail string) error + + // Returns current open stream count for a network (for capacity check) + GetOpenStreamCount(ctx context.Context, networkID string) (int, error) + + // Membership (for custom visibility) + SetVisibility(ctx context.Context, id string, mode VisibilityMode, requesterEmail string) error + AddMembers(ctx context.Context, id string, emails []string, requesterEmail string) error + RemoveMembers(ctx context.Context, id string, emails []string, requesterEmail string) error + GetMembers(ctx context.Context, id string) ([]string, error) +} +``` + +### ListParticles Implementation Logic + +```go +func (s *service) ListParticles(ctx context.Context, networkID string, parentID *string, email string, filter ListFilter, cursor *Cursor) (*ParticleList, error) { + var parent *Particle + var sortBy string + + // 1. Determine parent and sort strategy + if parentID != nil { + var err error + parent, err = s.repo.getByID(ctx, *parentID) + if err != nil { + return nil, ErrNotFound + } + + // Check visibility access to parent + if !s.canAccess(ctx, *parentID, email) { + return nil, ErrAccessDenied + } + + // Sort based on parent type + if parent.Type == TypeStream { + sortBy = "updated_at DESC" // Activity-based for streams + } else { + sortBy = "created_at DESC" // Chronological for folders + } + } else { + sortBy = "updated_at DESC" // Root level: activity-based + } + + // 2. Fetch particles with visibility filtering + particles, hasMore, nextCursor, prevCursor := s.repo.listChildren(ctx, networkID, parentID, email, sortBy, filter, cursor) + + return &ParticleList{ + Parent: parent, + Particles: particles, + HasMore: hasMore, + NextCursor: nextCursor, + PrevCursor: prevCursor, + }, nil +} +``` + +### Simple Validation (Start Simple) + +```go +// internal/particle/validation.go + +func validateData(t ParticleType, data json.RawMessage) error { + switch t { + case TypeStream, TypeQuest, TypePaper, TypeThink: + return requireField(data, "title") + case TypeFolder: + return requireField(data, "name") + case TypeMedia, TypeFile: + return requireFields(data, "url", "mime_type") + case TypeText: + return requireField(data, "content") + default: + return ErrInvalidParticleType + } +} + +func requireField(data json.RawMessage, field string) error { + var m map[string]interface{} + if err := json.Unmarshal(data, &m); err != nil { + return fmt.Errorf("invalid data JSON: %w", err) + } + if _, ok := m[field]; !ok { + return fmt.Errorf("missing required field: %s", field) + } + return nil +} +``` + +--- + +## Particle Visibility Logic + +The particle service handles visibility filtering. It does **not** check network membership (handler does that). + +### For `visibility = 'network_all'` +- All network members can see it +- Since handler already verified network membership, service returns it + +### For `visibility = 'custom'` +- Only users in `particle_members` table can see it +- Service checks `particle_members` table + +### Inheritance Rule +- Children can only **restrict** access, not expand +- If parent has `custom` visibility, child must also be `custom` (or more restrictive) +- Creating a child with `network_all` under a `custom` parent → error + +### Access Check Query + +```sql +-- Check if user can access a specific particle +-- Walks up the ancestor chain, verifies access at each level +WITH RECURSIVE ancestors AS ( + SELECT id, parent_id, visibility + FROM particles + WHERE id = $1 + + UNION ALL + + SELECT p.id, p.parent_id, p.visibility + FROM particles p + JOIN ancestors a ON p.id = a.parent_id +) +SELECT bool_and( + CASE + WHEN visibility = 'network_all' THEN true -- Handler already verified network membership + WHEN visibility = 'custom' THEN ( + EXISTS (SELECT 1 FROM particle_members pm + WHERE pm.particle_id = ancestors.id AND pm.email = $2) + ) + END +) AS has_access +FROM ancestors; +``` + +--- + +## Network Service Updates + +### New Methods (no changes to coupling) + +```go +// In internal/network/service.go +type Service interface { + // ... existing methods ... + + // Admin capacity management + SetOpenStreamCapacity(ctx context.Context, networkID string, capacity int) error + GetCapacityInfo(ctx context.Context, networkID string) (capacity int, current int, err error) + + // Stream count updates (called by handler, not particle service) + IncrementOpenStreamCount(ctx context.Context, networkID string) error + DecrementOpenStreamCount(ctx context.Context, networkID string) error +} +``` + +### Capacity Enforcement (in Handler) + +```go +// Handler: Opening a stream +func (h *Handler) OpenStream(w http.ResponseWriter, r *http.Request) { + // ... auth and validation ... + + // 1. Get particle to find its network + particle, err := h.particleService.GetByID(ctx, particleID, email) + + // 2. Check capacity + capacity, current, err := h.networkService.GetCapacityInfo(ctx, particle.NetworkID) + if current >= capacity { + return Error("stream capacity exceeded") + } + + // 3. Open the stream + err = h.particleService.OpenStream(ctx, particleID, email) + + // 4. Increment counter + err = h.networkService.IncrementOpenStreamCount(ctx, particle.NetworkID) +} +``` + +--- + +## Files to Modify + +| File | Changes | +|------|---------| +| `internal/network/models.go` | Add `OpenStreamCapacity`, `OpenStreamCount` fields | +| `internal/network/repository.go` | Add capacity CRUD methods | +| `internal/network/service.go` | Add `SetOpenStreamCapacity`, `GetCapacityInfo`, counter methods | +| `internal/handler/handler.go` | Wire up particle endpoints, add admin capacity endpoint | +| `migrations/` | Add 000003 and 000004 migration files | + +## Files to Create + +| File | Purpose | +|------|---------| +| `internal/particle/models.go` | Particle struct, type constants | +| `internal/particle/errors.go` | Domain errors | +| `internal/particle/repository.go` | Database operations | +| `internal/particle/service.go` | Business logic + visibility filtering | +| `internal/particle/validation.go` | Simple required field validation | +| `internal/particle/service_test.go` | Integration tests | + +--- + +## Implementation Phases + +### Phase 1: Network Capacity +1. Create migration `000003_network_capacity` +2. Update network models with capacity fields +3. Update network repository with capacity methods +4. Update network service with `SetOpenStreamCapacity`, `GetCapacityInfo` +5. Add admin endpoint in handler + +### Phase 2: Core Particle CRUD +1. Create migration `000004_particles` +2. Create particle package with models, errors +3. Implement repository with basic CRUD +4. Implement simple validation +5. Write integration tests + +### Phase 3: Particle Visibility +1. Implement visibility filtering in list queries +2. Implement access check for GetByID +3. Implement membership management (AddMembers, RemoveMembers) +4. Test visibility scenarios + +### Phase 4: Stream Lifecycle +1. Implement `OpenStream`/`CloseStream` in particle service +2. Wire up capacity checks in handler +3. Test capacity enforcement + +### Phase 5: Unified ListParticles +1. Implement unified `ListParticles` method +2. Add parent-type-aware sorting (streams: updated_at, folders: created_at) +3. Implement bidirectional cursor pagination +4. Include parent in response for breadcrumbs + +### Phase 6: Handler Integration +1. Wire particle service to handler +2. Implement all particle endpoints +3. Add DTO transformations +4. End-to-end testing + +--- + +## Verification Plan + +1. **Integration tests:** Full flow with test database (following existing pattern in `network/service_test.go`) +2. **Manual testing:** + - Create network with capacity 2 + - Open 2 streams → succeeds + - Open 3rd stream → fails with capacity error + - Close a stream → can open new one + - Create nested particles, verify visibility inheritance + - Add custom members, verify restricted access + - Test handler data flow end-to-end diff --git a/go/docs/realtime-architecture.md b/go/docs/realtime-architecture.md new file mode 100644 index 0000000..3e7bf32 --- /dev/null +++ b/go/docs/realtime-architecture.md @@ -0,0 +1,117 @@ +# Real-Time Architecture + +## Overview + +The system layers real-time delivery on top of the REST API without coupling domain logic to UI concerns. The REST API remains the source of truth; real-time events are hints that trigger client-side cache invalidation or refetches. + +## Architecture + +``` +┌─────────────────┐ +│ Service Layer │ Domain logic, publishes events +└────────┬────────┘ + │ publishes + ▼ +┌─────────────────┐ +│ Event Bus │ In-process or external queue +└────────┬────────┘ + │ subscribes + ▼ +┌─────────────────┐ +│ RealtimeService │ Routes events to connected clients +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Pusher/Ably │ Delivery to clients +└─────────────────┘ +``` + +**Key principle**: Services emit *what happened* in the domain. Consumers decide what to do with it. + +**Why decouple?** Domain events have multiple consumers beyond real-time delivery—analytics, audit logs, webhooks, background workers. The service layer doesn't know or care who's listening. + +**Naming**: We call it `RealtimeService` (not "NotificationService") because it handles real-time message delivery to connected clients, not human-facing notifications like alerts or emails. + +**Why not broadcast from handlers?** If handlers called Pusher directly after calling domain services, every handler that mutates state must remember to broadcast. This leads to duplication, inconsistency, and missed broadcasts when mutations happen outside handlers (background jobs, CLI). Events from the service layer ensure broadcasts happen automatically for any code path. + +## Channel Strategy + +Channels map to visibility boundaries: + +| Channel | Audience | Use Case | +|---------|----------|----------| +| `network:{id}` | All network members | Particles with `network_all` visibility | +| `particle:{id}` | Particle members | Particles with `custom` visibility | +| `human:{email}` | Single human | Private state (seen counts, mentions) | + +## Event Payloads + +Keep websocket messages minimal—just enough to identify what changed: + +```json +{ + "type": "particle.created", + "particle_id": "particle_abc", + "parent_id": "stream_xyz", + "network_id": "network_123" +} +``` + +The client decides relevance ("Am I viewing this stream?") and fetches full data via REST if needed. This avoids payload duplication and staleness. + +## Client Behavior + +On receiving an event: + +1. **Viewing affected context** → Fetch the new/updated particle, merge into local state +2. **Not viewing** → Update counts (e.g., increment unseen), no fetch needed + +This is simpler than full client-side sync and keeps REST as the authority. + +## Event Types + +| Event | Trigger | Broadcast To | +|-------|---------|--------------| +| `particle.created` | Particle created | Network or particle members | +| `particle.updated` | Data changed | Network or particle members | +| `particle.deleted` | Particle removed | Network or particle members | +| `particle.acked` | Human acknowledged | Network or particle members | +| `stream.opened` | Stream reopened | Network or particle members | +| `stream.closed` | Stream closed | Network or particle members | + +Note: `particle.seen` is private—no broadcast needed, client updates local state on API success. + +## Decoupling Benefits + +- **Service layer** stays focused on domain logic, testable without Pusher mocks +- **Realtime service** owns routing policy, testable in isolation +- **Adding events** doesn't require core domain changes if the action already exists +- **Additional listeners** (analytics, audit, webhooks) attach without modifying services + +## Adding New Real-Time Experiences + +When UI needs a new real-time message: + +1. Check if the domain event already exists +2. If yes → update realtime routing only +3. If no → add the domain event (often reveals a missing abstraction) + +The UI informs what events matter, but implementation remains decoupled. + +## Migration Path + +Start in-process with a simple event bus: + +```go +func (s *serviceImpl) Create(...) (*Particle, error) { + created, err := s.repo.create(ctx, p) + if err != nil { + return nil, err + } + s.events.Publish(ctx, ParticleCreated{Particle: created}) + return created, nil +} +``` + +The realtime service subscribes to `ParticleCreated` events. Other consumers (analytics, audit) subscribe independently. Later, swap the in-process event bus for a durable queue—subscribers don't change. diff --git a/go/genproto.sh b/go/genproto.sh new file mode 100755 index 0000000..07721b3 --- /dev/null +++ b/go/genproto.sh @@ -0,0 +1,36 @@ +#!/bin/bash -eu + +PATH=$PATH:$(go env GOPATH)/bin + +# Default values +protodir="./protocol" +outdir="./genproto" + +# Parse command-line options +while getopts "p:o:" opt; do + case $opt in + p) protodir="$OPTARG" ;; + o) outdir="$OPTARG" ;; + \?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;; + esac +done + +# Print the directories for verification +echo "Proto directory: $protodir" +echo "Output directory: $outdir" + +rm -rf $outdir +mkdir -p $outdir + +# use the public image from dockerhub which contains tools for protoc & golang/grpc +docker run --rm \ + -v "$protodir/":/protocol \ + -v "$outdir":/genproto \ + --workdir / \ + talksik/golang-protoc:latest \ + protoc --proto_path=./protocol \ + --go_out=./genproto \ + --go_opt=paths=source_relative \ + --go-grpc_out=./genproto \ + --go-grpc_opt=paths=source_relative \ + $(find ./protocol -name "*.proto") diff --git a/go/genproto/aero/main.pb.go b/go/genproto/aero/main.pb.go new file mode 100644 index 0000000..9a59030 --- /dev/null +++ b/go/genproto/aero/main.pb.go @@ -0,0 +1,554 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: aero/main.proto + +package pbaero + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + _ "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 MagicLinkEmailData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MagicLink string `protobuf:"bytes,1,opt,name=magic_link,json=magicLink,proto3" json:"magic_link,omitempty"` +} + +func (x *MagicLinkEmailData) Reset() { + *x = MagicLinkEmailData{} + mi := &file_aero_main_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MagicLinkEmailData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MagicLinkEmailData) ProtoMessage() {} + +func (x *MagicLinkEmailData) ProtoReflect() protoreflect.Message { + mi := &file_aero_main_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MagicLinkEmailData.ProtoReflect.Descriptor instead. +func (*MagicLinkEmailData) Descriptor() ([]byte, []int) { + return file_aero_main_proto_rawDescGZIP(), []int{0} +} + +func (x *MagicLinkEmailData) GetMagicLink() string { + if x != nil { + return x.MagicLink + } + return "" +} + +type GenericFlowyAdminAlertData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *GenericFlowyAdminAlertData) Reset() { + *x = GenericFlowyAdminAlertData{} + mi := &file_aero_main_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenericFlowyAdminAlertData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenericFlowyAdminAlertData) ProtoMessage() {} + +func (x *GenericFlowyAdminAlertData) ProtoReflect() protoreflect.Message { + mi := &file_aero_main_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenericFlowyAdminAlertData.ProtoReflect.Descriptor instead. +func (*GenericFlowyAdminAlertData) Descriptor() ([]byte, []int) { + return file_aero_main_proto_rawDescGZIP(), []int{1} +} + +func (x *GenericFlowyAdminAlertData) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type KeypadConnectCodeData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` +} + +func (x *KeypadConnectCodeData) Reset() { + *x = KeypadConnectCodeData{} + mi := &file_aero_main_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *KeypadConnectCodeData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KeypadConnectCodeData) ProtoMessage() {} + +func (x *KeypadConnectCodeData) ProtoReflect() protoreflect.Message { + mi := &file_aero_main_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KeypadConnectCodeData.ProtoReflect.Descriptor instead. +func (*KeypadConnectCodeData) Descriptor() ([]byte, []int) { + return file_aero_main_proto_rawDescGZIP(), []int{2} +} + +func (x *KeypadConnectCodeData) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +type SimpleTextData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Send raw text-only emails + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *SimpleTextData) Reset() { + *x = SimpleTextData{} + mi := &file_aero_main_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SimpleTextData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SimpleTextData) ProtoMessage() {} + +func (x *SimpleTextData) ProtoReflect() protoreflect.Message { + mi := &file_aero_main_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SimpleTextData.ProtoReflect.Descriptor instead. +func (*SimpleTextData) Descriptor() ([]byte, []int) { + return file_aero_main_proto_rawDescGZIP(), []int{3} +} + +func (x *SimpleTextData) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type SimpleHtmlData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Html string `protobuf:"bytes,1,opt,name=html,proto3" json:"html,omitempty"` +} + +func (x *SimpleHtmlData) Reset() { + *x = SimpleHtmlData{} + mi := &file_aero_main_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SimpleHtmlData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SimpleHtmlData) ProtoMessage() {} + +func (x *SimpleHtmlData) ProtoReflect() protoreflect.Message { + mi := &file_aero_main_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SimpleHtmlData.ProtoReflect.Descriptor instead. +func (*SimpleHtmlData) Descriptor() ([]byte, []int) { + return file_aero_main_proto_rawDescGZIP(), []int{4} +} + +func (x *SimpleHtmlData) GetHtml() string { + if x != nil { + return x.Html + } + return "" +} + +type ShootEmailRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ToEmails []string `protobuf:"bytes,1,rep,name=to_emails,json=toEmails,proto3" json:"to_emails,omitempty"` + Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` + // Types that are assignable to TemplateData: + // + // *ShootEmailRequest_MagicLinkData + // *ShootEmailRequest_GenericFlowyAdminAlertData + // *ShootEmailRequest_KeypadConnectCodeData + // *ShootEmailRequest_SimpleTextData + // *ShootEmailRequest_SimpleHtmlData + TemplateData isShootEmailRequest_TemplateData `protobuf_oneof:"template_data"` +} + +func (x *ShootEmailRequest) Reset() { + *x = ShootEmailRequest{} + mi := &file_aero_main_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ShootEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShootEmailRequest) ProtoMessage() {} + +func (x *ShootEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_aero_main_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShootEmailRequest.ProtoReflect.Descriptor instead. +func (*ShootEmailRequest) Descriptor() ([]byte, []int) { + return file_aero_main_proto_rawDescGZIP(), []int{5} +} + +func (x *ShootEmailRequest) GetToEmails() []string { + if x != nil { + return x.ToEmails + } + return nil +} + +func (x *ShootEmailRequest) GetSubject() string { + if x != nil { + return x.Subject + } + return "" +} + +func (m *ShootEmailRequest) GetTemplateData() isShootEmailRequest_TemplateData { + if m != nil { + return m.TemplateData + } + return nil +} + +func (x *ShootEmailRequest) GetMagicLinkData() *MagicLinkEmailData { + if x, ok := x.GetTemplateData().(*ShootEmailRequest_MagicLinkData); ok { + return x.MagicLinkData + } + return nil +} + +func (x *ShootEmailRequest) GetGenericFlowyAdminAlertData() *GenericFlowyAdminAlertData { + if x, ok := x.GetTemplateData().(*ShootEmailRequest_GenericFlowyAdminAlertData); ok { + return x.GenericFlowyAdminAlertData + } + return nil +} + +func (x *ShootEmailRequest) GetKeypadConnectCodeData() *KeypadConnectCodeData { + if x, ok := x.GetTemplateData().(*ShootEmailRequest_KeypadConnectCodeData); ok { + return x.KeypadConnectCodeData + } + return nil +} + +func (x *ShootEmailRequest) GetSimpleTextData() *SimpleTextData { + if x, ok := x.GetTemplateData().(*ShootEmailRequest_SimpleTextData); ok { + return x.SimpleTextData + } + return nil +} + +func (x *ShootEmailRequest) GetSimpleHtmlData() *SimpleHtmlData { + if x, ok := x.GetTemplateData().(*ShootEmailRequest_SimpleHtmlData); ok { + return x.SimpleHtmlData + } + return nil +} + +type isShootEmailRequest_TemplateData interface { + isShootEmailRequest_TemplateData() +} + +type ShootEmailRequest_MagicLinkData struct { + MagicLinkData *MagicLinkEmailData `protobuf:"bytes,3,opt,name=magic_link_data,json=magicLinkData,proto3,oneof"` +} + +type ShootEmailRequest_GenericFlowyAdminAlertData struct { + GenericFlowyAdminAlertData *GenericFlowyAdminAlertData `protobuf:"bytes,4,opt,name=generic_flowy_admin_alert_data,json=genericFlowyAdminAlertData,proto3,oneof"` +} + +type ShootEmailRequest_KeypadConnectCodeData struct { + KeypadConnectCodeData *KeypadConnectCodeData `protobuf:"bytes,5,opt,name=keypad_connect_code_data,json=keypadConnectCodeData,proto3,oneof"` +} + +type ShootEmailRequest_SimpleTextData struct { + SimpleTextData *SimpleTextData `protobuf:"bytes,6,opt,name=simple_text_data,json=simpleTextData,proto3,oneof"` +} + +type ShootEmailRequest_SimpleHtmlData struct { + SimpleHtmlData *SimpleHtmlData `protobuf:"bytes,7,opt,name=simple_html_data,json=simpleHtmlData,proto3,oneof"` +} + +func (*ShootEmailRequest_MagicLinkData) isShootEmailRequest_TemplateData() {} + +func (*ShootEmailRequest_GenericFlowyAdminAlertData) isShootEmailRequest_TemplateData() {} + +func (*ShootEmailRequest_KeypadConnectCodeData) isShootEmailRequest_TemplateData() {} + +func (*ShootEmailRequest_SimpleTextData) isShootEmailRequest_TemplateData() {} + +func (*ShootEmailRequest_SimpleHtmlData) isShootEmailRequest_TemplateData() {} + +type ShootEmailResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ShootEmailResponse) Reset() { + *x = ShootEmailResponse{} + mi := &file_aero_main_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ShootEmailResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShootEmailResponse) ProtoMessage() {} + +func (x *ShootEmailResponse) ProtoReflect() protoreflect.Message { + mi := &file_aero_main_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShootEmailResponse.ProtoReflect.Descriptor instead. +func (*ShootEmailResponse) Descriptor() ([]byte, []int) { + return file_aero_main_proto_rawDescGZIP(), []int{6} +} + +var File_aero_main_proto protoreflect.FileDescriptor + +var file_aero_main_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x61, 0x65, 0x72, 0x6f, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x04, 0x61, 0x65, 0x72, 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, 0x33, 0x0a, 0x12, 0x4d, 0x61, 0x67, 0x69, + 0x63, 0x4c, 0x69, 0x6e, 0x6b, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, + 0x0a, 0x0a, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4c, 0x69, 0x6e, 0x6b, 0x22, 0x36, 0x0a, + 0x1a, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x46, 0x6c, 0x6f, 0x77, 0x79, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2b, 0x0a, 0x15, 0x4b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, + 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, + 0x64, 0x65, 0x22, 0x2a, 0x0a, 0x0e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x65, 0x78, 0x74, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, + 0x0a, 0x0e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x48, 0x74, 0x6d, 0x6c, 0x44, 0x61, 0x74, 0x61, + 0x12, 0x12, 0x0a, 0x04, 0x68, 0x74, 0x6d, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0xe3, 0x03, 0x0a, 0x11, 0x53, 0x68, 0x6f, 0x6f, 0x74, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, + 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x74, + 0x6f, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x12, 0x42, 0x0a, 0x0f, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x65, 0x72, + 0x6f, 0x2e, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x4c, 0x69, 0x6e, 0x6b, 0x45, 0x6d, 0x61, 0x69, 0x6c, + 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4c, 0x69, 0x6e, + 0x6b, 0x44, 0x61, 0x74, 0x61, 0x12, 0x66, 0x0a, 0x1e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, + 0x5f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x6c, 0x65, + 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x61, 0x65, 0x72, 0x6f, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x46, 0x6c, 0x6f, 0x77, + 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, + 0x00, 0x52, 0x1a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x46, 0x6c, 0x6f, 0x77, 0x79, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x56, 0x0a, + 0x18, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, + 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x61, 0x65, 0x72, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x15, + 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x64, + 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x10, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x5f, + 0x74, 0x65, 0x78, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x61, 0x65, 0x72, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x65, 0x78, + 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0e, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, + 0x65, 0x78, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x10, 0x73, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x5f, 0x68, 0x74, 0x6d, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x65, 0x72, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x48, + 0x74, 0x6d, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0e, 0x73, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x48, 0x74, 0x6d, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x42, 0x0f, 0x0a, 0x0d, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, 0x14, 0x0a, 0x12, 0x53, 0x68, + 0x6f, 0x6f, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x32, 0x4c, 0x0a, 0x07, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x0a, 0x53, + 0x68, 0x6f, 0x6f, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x17, 0x2e, 0x61, 0x65, 0x72, 0x6f, + 0x2e, 0x53, 0x68, 0x6f, 0x6f, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x65, 0x72, 0x6f, 0x2e, 0x53, 0x68, 0x6f, 0x6f, 0x74, 0x45, + 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x30, + 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, + 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x61, 0x65, 0x72, 0x6f, 0x3b, 0x70, 0x62, 0x61, 0x65, 0x72, 0x6f, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_aero_main_proto_rawDescOnce sync.Once + file_aero_main_proto_rawDescData = file_aero_main_proto_rawDesc +) + +func file_aero_main_proto_rawDescGZIP() []byte { + file_aero_main_proto_rawDescOnce.Do(func() { + file_aero_main_proto_rawDescData = protoimpl.X.CompressGZIP(file_aero_main_proto_rawDescData) + }) + return file_aero_main_proto_rawDescData +} + +var file_aero_main_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_aero_main_proto_goTypes = []any{ + (*MagicLinkEmailData)(nil), // 0: aero.MagicLinkEmailData + (*GenericFlowyAdminAlertData)(nil), // 1: aero.GenericFlowyAdminAlertData + (*KeypadConnectCodeData)(nil), // 2: aero.KeypadConnectCodeData + (*SimpleTextData)(nil), // 3: aero.SimpleTextData + (*SimpleHtmlData)(nil), // 4: aero.SimpleHtmlData + (*ShootEmailRequest)(nil), // 5: aero.ShootEmailRequest + (*ShootEmailResponse)(nil), // 6: aero.ShootEmailResponse +} +var file_aero_main_proto_depIdxs = []int32{ + 0, // 0: aero.ShootEmailRequest.magic_link_data:type_name -> aero.MagicLinkEmailData + 1, // 1: aero.ShootEmailRequest.generic_flowy_admin_alert_data:type_name -> aero.GenericFlowyAdminAlertData + 2, // 2: aero.ShootEmailRequest.keypad_connect_code_data:type_name -> aero.KeypadConnectCodeData + 3, // 3: aero.ShootEmailRequest.simple_text_data:type_name -> aero.SimpleTextData + 4, // 4: aero.ShootEmailRequest.simple_html_data:type_name -> aero.SimpleHtmlData + 5, // 5: aero.Primary.ShootEmail:input_type -> aero.ShootEmailRequest + 6, // 6: aero.Primary.ShootEmail:output_type -> aero.ShootEmailResponse + 6, // [6:7] is the sub-list for method output_type + 5, // [5:6] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_aero_main_proto_init() } +func file_aero_main_proto_init() { + if File_aero_main_proto != nil { + return + } + file_aero_main_proto_msgTypes[5].OneofWrappers = []any{ + (*ShootEmailRequest_MagicLinkData)(nil), + (*ShootEmailRequest_GenericFlowyAdminAlertData)(nil), + (*ShootEmailRequest_KeypadConnectCodeData)(nil), + (*ShootEmailRequest_SimpleTextData)(nil), + (*ShootEmailRequest_SimpleHtmlData)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_aero_main_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_aero_main_proto_goTypes, + DependencyIndexes: file_aero_main_proto_depIdxs, + MessageInfos: file_aero_main_proto_msgTypes, + }.Build() + File_aero_main_proto = out.File + file_aero_main_proto_rawDesc = nil + file_aero_main_proto_goTypes = nil + file_aero_main_proto_depIdxs = nil +} diff --git a/go/genproto/aero/main_grpc.pb.go b/go/genproto/aero/main_grpc.pb.go new file mode 100644 index 0000000..35ce374 --- /dev/null +++ b/go/genproto/aero/main_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: aero/main.proto + +package pbaero + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Primary_ShootEmail_FullMethodName = "/aero.Primary/ShootEmail" +) + +// PrimaryClient is the client API for Primary 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 PrimaryClient interface { + ShootEmail(ctx context.Context, in *ShootEmailRequest, opts ...grpc.CallOption) (*ShootEmailResponse, error) +} + +type primaryClient struct { + cc grpc.ClientConnInterface +} + +func NewPrimaryClient(cc grpc.ClientConnInterface) PrimaryClient { + return &primaryClient{cc} +} + +func (c *primaryClient) ShootEmail(ctx context.Context, in *ShootEmailRequest, opts ...grpc.CallOption) (*ShootEmailResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ShootEmailResponse) + err := c.cc.Invoke(ctx, Primary_ShootEmail_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PrimaryServer is the server API for Primary service. +// All implementations must embed UnimplementedPrimaryServer +// for forward compatibility. +type PrimaryServer interface { + ShootEmail(context.Context, *ShootEmailRequest) (*ShootEmailResponse, error) + mustEmbedUnimplementedPrimaryServer() +} + +// UnimplementedPrimaryServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedPrimaryServer struct{} + +func (UnimplementedPrimaryServer) ShootEmail(context.Context, *ShootEmailRequest) (*ShootEmailResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ShootEmail not implemented") +} +func (UnimplementedPrimaryServer) mustEmbedUnimplementedPrimaryServer() {} +func (UnimplementedPrimaryServer) testEmbeddedByValue() {} + +// UnsafePrimaryServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PrimaryServer will +// result in compilation errors. +type UnsafePrimaryServer interface { + mustEmbedUnimplementedPrimaryServer() +} + +func RegisterPrimaryServer(s grpc.ServiceRegistrar, srv PrimaryServer) { + // If the following call pancis, it indicates UnimplementedPrimaryServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Primary_ServiceDesc, srv) +} + +func _Primary_ShootEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ShootEmailRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PrimaryServer).ShootEmail(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Primary_ShootEmail_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PrimaryServer).ShootEmail(ctx, req.(*ShootEmailRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Primary_ServiceDesc is the grpc.ServiceDesc for Primary service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Primary_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "aero.Primary", + HandlerType: (*PrimaryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ShootEmail", + Handler: _Primary_ShootEmail_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "aero/main.proto", +} diff --git a/go/genproto/greeter/service.pb.go b/go/genproto/greeter/service.pb.go new file mode 100644 index 0000000..98c4be7 --- /dev/null +++ b/go/genproto/greeter/service.pb.go @@ -0,0 +1,185 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: greeter/service.proto + +package pbgreeter + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 SayHelloRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *SayHelloRequest) Reset() { + *x = SayHelloRequest{} + mi := &file_greeter_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SayHelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayHelloRequest) ProtoMessage() {} + +func (x *SayHelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_greeter_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayHelloRequest.ProtoReflect.Descriptor instead. +func (*SayHelloRequest) Descriptor() ([]byte, []int) { + return file_greeter_service_proto_rawDescGZIP(), []int{0} +} + +func (x *SayHelloRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type SayHelloResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *SayHelloResponse) Reset() { + *x = SayHelloResponse{} + mi := &file_greeter_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SayHelloResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayHelloResponse) ProtoMessage() {} + +func (x *SayHelloResponse) ProtoReflect() protoreflect.Message { + mi := &file_greeter_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayHelloResponse.ProtoReflect.Descriptor instead. +func (*SayHelloResponse) Descriptor() ([]byte, []int) { + return file_greeter_service_proto_rawDescGZIP(), []int{1} +} + +func (x *SayHelloResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_greeter_service_proto protoreflect.FileDescriptor + +var file_greeter_service_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x67, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x67, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, + 0x22, 0x25, 0x0a, 0x0f, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 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, 0x2c, 0x0a, 0x10, 0x53, 0x61, 0x79, 0x48, 0x65, + 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x53, 0x0a, 0x0e, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, + 0x6c, 0x6c, 0x6f, 0x12, 0x18, 0x2e, 0x67, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x61, + 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, + 0x67, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, + 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x2f, 0x67, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x3b, 0x70, 0x62, 0x67, 0x72, 0x65, 0x65, 0x74, + 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_greeter_service_proto_rawDescOnce sync.Once + file_greeter_service_proto_rawDescData = file_greeter_service_proto_rawDesc +) + +func file_greeter_service_proto_rawDescGZIP() []byte { + file_greeter_service_proto_rawDescOnce.Do(func() { + file_greeter_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_greeter_service_proto_rawDescData) + }) + return file_greeter_service_proto_rawDescData +} + +var file_greeter_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_greeter_service_proto_goTypes = []any{ + (*SayHelloRequest)(nil), // 0: greeter.SayHelloRequest + (*SayHelloResponse)(nil), // 1: greeter.SayHelloResponse +} +var file_greeter_service_proto_depIdxs = []int32{ + 0, // 0: greeter.GreeterService.SayHello:input_type -> greeter.SayHelloRequest + 1, // 1: greeter.GreeterService.SayHello:output_type -> greeter.SayHelloResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_greeter_service_proto_init() } +func file_greeter_service_proto_init() { + if File_greeter_service_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_greeter_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_greeter_service_proto_goTypes, + DependencyIndexes: file_greeter_service_proto_depIdxs, + MessageInfos: file_greeter_service_proto_msgTypes, + }.Build() + File_greeter_service_proto = out.File + file_greeter_service_proto_rawDesc = nil + file_greeter_service_proto_goTypes = nil + file_greeter_service_proto_depIdxs = nil +} diff --git a/go/genproto/greeter/service_grpc.pb.go b/go/genproto/greeter/service_grpc.pb.go new file mode 100644 index 0000000..49512a2 --- /dev/null +++ b/go/genproto/greeter/service_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: greeter/service.proto + +package pbgreeter + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + GreeterService_SayHello_FullMethodName = "/greeter.GreeterService/SayHello" +) + +// GreeterServiceClient is the client API for GreeterService 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 GreeterServiceClient interface { + SayHello(ctx context.Context, in *SayHelloRequest, opts ...grpc.CallOption) (*SayHelloResponse, error) +} + +type greeterServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewGreeterServiceClient(cc grpc.ClientConnInterface) GreeterServiceClient { + return &greeterServiceClient{cc} +} + +func (c *greeterServiceClient) SayHello(ctx context.Context, in *SayHelloRequest, opts ...grpc.CallOption) (*SayHelloResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SayHelloResponse) + err := c.cc.Invoke(ctx, GreeterService_SayHello_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GreeterServiceServer is the server API for GreeterService service. +// All implementations must embed UnimplementedGreeterServiceServer +// for forward compatibility. +type GreeterServiceServer interface { + SayHello(context.Context, *SayHelloRequest) (*SayHelloResponse, error) + mustEmbedUnimplementedGreeterServiceServer() +} + +// UnimplementedGreeterServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedGreeterServiceServer struct{} + +func (UnimplementedGreeterServiceServer) SayHello(context.Context, *SayHelloRequest) (*SayHelloResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") +} +func (UnimplementedGreeterServiceServer) mustEmbedUnimplementedGreeterServiceServer() {} +func (UnimplementedGreeterServiceServer) testEmbeddedByValue() {} + +// UnsafeGreeterServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GreeterServiceServer will +// result in compilation errors. +type UnsafeGreeterServiceServer interface { + mustEmbedUnimplementedGreeterServiceServer() +} + +func RegisterGreeterServiceServer(s grpc.ServiceRegistrar, srv GreeterServiceServer) { + // If the following call pancis, it indicates UnimplementedGreeterServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&GreeterService_ServiceDesc, srv) +} + +func _GreeterService_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SayHelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GreeterServiceServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: GreeterService_SayHello_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GreeterServiceServer).SayHello(ctx, req.(*SayHelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// GreeterService_ServiceDesc is the grpc.ServiceDesc for GreeterService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var GreeterService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "greeter.GreeterService", + HandlerType: (*GreeterServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _GreeterService_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "greeter/service.proto", +} diff --git a/go/genproto/helios/auth/auth.pb.go b/go/genproto/helios/auth/auth.pb.go new file mode 100644 index 0000000..4970656 --- /dev/null +++ b/go/genproto/helios/auth/auth.pb.go @@ -0,0 +1,918 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/auth/auth.proto + +package pbauth + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 AuthRole int32 + +const ( + AuthRole_AUTH_ROLE_UNSPECIFIED AuthRole = 0 + AuthRole_AUTH_ROLE_HUMAN AuthRole = 1 + AuthRole_AUTH_ROLE_ADMIN AuthRole = 2 +) + +// Enum value maps for AuthRole. +var ( + AuthRole_name = map[int32]string{ + 0: "AUTH_ROLE_UNSPECIFIED", + 1: "AUTH_ROLE_HUMAN", + 2: "AUTH_ROLE_ADMIN", + } + AuthRole_value = map[string]int32{ + "AUTH_ROLE_UNSPECIFIED": 0, + "AUTH_ROLE_HUMAN": 1, + "AUTH_ROLE_ADMIN": 2, + } +) + +func (x AuthRole) Enum() *AuthRole { + p := new(AuthRole) + *p = x + return p +} + +func (x AuthRole) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AuthRole) Descriptor() protoreflect.EnumDescriptor { + return file_helios_auth_auth_proto_enumTypes[0].Descriptor() +} + +func (AuthRole) Type() protoreflect.EnumType { + return &file_helios_auth_auth_proto_enumTypes[0] +} + +func (x AuthRole) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AuthRole.Descriptor instead. +func (AuthRole) EnumDescriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{0} +} + +type ClientType int32 + +const ( + ClientType_CLIENT_TYPE_UNSPECIFIED ClientType = 0 + ClientType_CLIENT_TYPE_KEYPAD ClientType = 1 + ClientType_CLIENT_TYPE_COMPUTER_DAEMON ClientType = 2 +) + +// Enum value maps for ClientType. +var ( + ClientType_name = map[int32]string{ + 0: "CLIENT_TYPE_UNSPECIFIED", + 1: "CLIENT_TYPE_KEYPAD", + 2: "CLIENT_TYPE_COMPUTER_DAEMON", + } + ClientType_value = map[string]int32{ + "CLIENT_TYPE_UNSPECIFIED": 0, + "CLIENT_TYPE_KEYPAD": 1, + "CLIENT_TYPE_COMPUTER_DAEMON": 2, + } +) + +func (x ClientType) Enum() *ClientType { + p := new(ClientType) + *p = x + return p +} + +func (x ClientType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClientType) Descriptor() protoreflect.EnumDescriptor { + return file_helios_auth_auth_proto_enumTypes[1].Descriptor() +} + +func (ClientType) Type() protoreflect.EnumType { + return &file_helios_auth_auth_proto_enumTypes[1] +} + +func (x ClientType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClientType.Descriptor instead. +func (ClientType) EnumDescriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{1} +} + +type ErrorDetail struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ErrorCode string `protobuf:"bytes,1,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"` // Custom error code (e.g., "USER_NOT_FOUND") + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` // Human-readable message + Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Optional extra info +} + +func (x *ErrorDetail) Reset() { + *x = ErrorDetail{} + mi := &file_helios_auth_auth_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ErrorDetail) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ErrorDetail) ProtoMessage() {} + +func (x *ErrorDetail) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ErrorDetail.ProtoReflect.Descriptor instead. +func (*ErrorDetail) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{0} +} + +func (x *ErrorDetail) GetErrorCode() string { + if x != nil { + return x.ErrorCode + } + return "" +} + +func (x *ErrorDetail) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *ErrorDetail) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +type AuthedHuman struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + AuthRole AuthRole `protobuf:"varint,4,opt,name=auth_role,json=authRole,proto3,enum=helios.auth.AuthRole" json:"auth_role,omitempty"` + // Whether or not this authed human is invited to use flowy (from the waitlist) + IsInvited bool `protobuf:"varint,5,opt,name=is_invited,json=isInvited,proto3" json:"is_invited,omitempty"` + ClientType ClientType `protobuf:"varint,6,opt,name=client_type,json=clientType,proto3,enum=helios.auth.ClientType" json:"client_type,omitempty"` +} + +func (x *AuthedHuman) Reset() { + *x = AuthedHuman{} + mi := &file_helios_auth_auth_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthedHuman) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthedHuman) ProtoMessage() {} + +func (x *AuthedHuman) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthedHuman.ProtoReflect.Descriptor instead. +func (*AuthedHuman) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{1} +} + +func (x *AuthedHuman) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AuthedHuman) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *AuthedHuman) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *AuthedHuman) GetAuthRole() AuthRole { + if x != nil { + return x.AuthRole + } + return AuthRole_AUTH_ROLE_UNSPECIFIED +} + +func (x *AuthedHuman) GetIsInvited() bool { + if x != nil { + return x.IsInvited + } + return false +} + +func (x *AuthedHuman) GetClientType() ClientType { + if x != nil { + return x.ClientType + } + return ClientType_CLIENT_TYPE_UNSPECIFIED +} + +type RegisterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` +} + +func (x *RegisterRequest) Reset() { + *x = RegisterRequest{} + mi := &file_helios_auth_auth_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRequest) ProtoMessage() {} + +func (x *RegisterRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. +func (*RegisterRequest) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{2} +} + +func (x *RegisterRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *RegisterRequest) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +type RegisterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RegisterResponse) Reset() { + *x = RegisterResponse{} + mi := &file_helios_auth_auth_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterResponse) ProtoMessage() {} + +func (x *RegisterResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead. +func (*RegisterResponse) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{3} +} + +type SignInRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + ClientType ClientType `protobuf:"varint,2,opt,name=client_type,json=clientType,proto3,enum=helios.auth.ClientType" json:"client_type,omitempty"` +} + +func (x *SignInRequest) Reset() { + *x = SignInRequest{} + mi := &file_helios_auth_auth_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignInRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignInRequest) ProtoMessage() {} + +func (x *SignInRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignInRequest.ProtoReflect.Descriptor instead. +func (*SignInRequest) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{4} +} + +func (x *SignInRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *SignInRequest) GetClientType() ClientType { + if x != nil { + return x.ClientType + } + return ClientType_CLIENT_TYPE_UNSPECIFIED +} + +type SignInResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SignInResponse) Reset() { + *x = SignInResponse{} + mi := &file_helios_auth_auth_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignInResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignInResponse) ProtoMessage() {} + +func (x *SignInResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignInResponse.ProtoReflect.Descriptor instead. +func (*SignInResponse) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{5} +} + +type SignInVerifyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` + ClientType ClientType `protobuf:"varint,3,opt,name=client_type,json=clientType,proto3,enum=helios.auth.ClientType" json:"client_type,omitempty"` +} + +func (x *SignInVerifyRequest) Reset() { + *x = SignInVerifyRequest{} + mi := &file_helios_auth_auth_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignInVerifyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignInVerifyRequest) ProtoMessage() {} + +func (x *SignInVerifyRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignInVerifyRequest.ProtoReflect.Descriptor instead. +func (*SignInVerifyRequest) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{6} +} + +func (x *SignInVerifyRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *SignInVerifyRequest) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *SignInVerifyRequest) GetClientType() ClientType { + if x != nil { + return x.ClientType + } + return ClientType_CLIENT_TYPE_UNSPECIFIED +} + +type SignInVerifyResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Please add this to metadata of future requests under the key "authorization" + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + Role AuthRole `protobuf:"varint,2,opt,name=role,proto3,enum=helios.auth.AuthRole" json:"role,omitempty"` + ClientType ClientType `protobuf:"varint,3,opt,name=client_type,json=clientType,proto3,enum=helios.auth.ClientType" json:"client_type,omitempty"` +} + +func (x *SignInVerifyResponse) Reset() { + *x = SignInVerifyResponse{} + mi := &file_helios_auth_auth_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignInVerifyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignInVerifyResponse) ProtoMessage() {} + +func (x *SignInVerifyResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignInVerifyResponse.ProtoReflect.Descriptor instead. +func (*SignInVerifyResponse) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{7} +} + +func (x *SignInVerifyResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *SignInVerifyResponse) GetRole() AuthRole { + if x != nil { + return x.Role + } + return AuthRole_AUTH_ROLE_UNSPECIFIED +} + +func (x *SignInVerifyResponse) GetClientType() ClientType { + if x != nil { + return x.ClientType + } + return ClientType_CLIENT_TYPE_UNSPECIFIED +} + +type SignOutRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SignOutRequest) Reset() { + *x = SignOutRequest{} + mi := &file_helios_auth_auth_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignOutRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignOutRequest) ProtoMessage() {} + +func (x *SignOutRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignOutRequest.ProtoReflect.Descriptor instead. +func (*SignOutRequest) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{8} +} + +type SignOutResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SignOutResponse) Reset() { + *x = SignOutResponse{} + mi := &file_helios_auth_auth_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignOutResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignOutResponse) ProtoMessage() {} + +func (x *SignOutResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignOutResponse.ProtoReflect.Descriptor instead. +func (*SignOutResponse) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{9} +} + +type AuthedHumanRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AuthedHumanRequest) Reset() { + *x = AuthedHumanRequest{} + mi := &file_helios_auth_auth_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthedHumanRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthedHumanRequest) ProtoMessage() {} + +func (x *AuthedHumanRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthedHumanRequest.ProtoReflect.Descriptor instead. +func (*AuthedHumanRequest) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{10} +} + +type AuthedHumanResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AuthedHuman *AuthedHuman `protobuf:"bytes,1,opt,name=authed_human,json=authedHuman,proto3" json:"authed_human,omitempty"` +} + +func (x *AuthedHumanResponse) Reset() { + *x = AuthedHumanResponse{} + mi := &file_helios_auth_auth_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthedHumanResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthedHumanResponse) ProtoMessage() {} + +func (x *AuthedHumanResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_auth_auth_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthedHumanResponse.ProtoReflect.Descriptor instead. +func (*AuthedHumanResponse) Descriptor() ([]byte, []int) { + return file_helios_auth_auth_proto_rawDescGZIP(), []int{11} +} + +func (x *AuthedHumanResponse) GetAuthedHuman() *AuthedHuman { + if x != nil { + return x.AuthedHuman + } + return nil +} + +var File_helios_auth_auth_proto protoreflect.FileDescriptor + +var file_helios_auth_auth_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x22, 0xc7, 0x01, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x42, + 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xe3, 0x01, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x65, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x32, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x6f, + 0x6c, 0x65, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x69, 0x73, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0b, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x17, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x4a, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x21, + 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x38, 0x0a, 0x0b, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x17, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x79, 0x0a, 0x13, 0x53, 0x69, 0x67, 0x6e, + 0x49, 0x6e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, + 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x14, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x15, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x41, + 0x75, 0x74, 0x68, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x38, 0x0a, + 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x4f, + 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x69, 0x67, + 0x6e, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x0a, 0x12, + 0x41, 0x75, 0x74, 0x68, 0x65, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x52, 0x0a, 0x13, 0x41, 0x75, 0x74, 0x68, 0x65, 0x64, 0x48, 0x75, 0x6d, 0x61, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x61, 0x75, 0x74, + 0x68, 0x65, 0x64, 0x5f, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x41, 0x75, + 0x74, 0x68, 0x65, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x65, + 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x2a, 0x4f, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x52, 0x6f, + 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, + 0x0f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x48, 0x55, 0x4d, 0x41, 0x4e, + 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, + 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x2a, 0x62, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x50, 0x41, 0x44, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x4c, + 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, + 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x02, 0x32, 0x90, 0x03, 0x0a, 0x0b, + 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, + 0x12, 0x1a, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x53, + 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x0c, 0x53, + 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x20, 0x2e, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, + 0x49, 0x6e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x46, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x12, 0x1b, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, + 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0b, 0x41, 0x75, + 0x74, 0x68, 0x65, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x64, 0x48, 0x75, + 0x6d, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x64, 0x48, + 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, + 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, + 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x67, + 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x61, + 0x75, 0x74, 0x68, 0x3b, 0x70, 0x62, 0x61, 0x75, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_helios_auth_auth_proto_rawDescOnce sync.Once + file_helios_auth_auth_proto_rawDescData = file_helios_auth_auth_proto_rawDesc +) + +func file_helios_auth_auth_proto_rawDescGZIP() []byte { + file_helios_auth_auth_proto_rawDescOnce.Do(func() { + file_helios_auth_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_auth_auth_proto_rawDescData) + }) + return file_helios_auth_auth_proto_rawDescData +} + +var file_helios_auth_auth_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_helios_auth_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_helios_auth_auth_proto_goTypes = []any{ + (AuthRole)(0), // 0: helios.auth.AuthRole + (ClientType)(0), // 1: helios.auth.ClientType + (*ErrorDetail)(nil), // 2: helios.auth.ErrorDetail + (*AuthedHuman)(nil), // 3: helios.auth.AuthedHuman + (*RegisterRequest)(nil), // 4: helios.auth.RegisterRequest + (*RegisterResponse)(nil), // 5: helios.auth.RegisterResponse + (*SignInRequest)(nil), // 6: helios.auth.SignInRequest + (*SignInResponse)(nil), // 7: helios.auth.SignInResponse + (*SignInVerifyRequest)(nil), // 8: helios.auth.SignInVerifyRequest + (*SignInVerifyResponse)(nil), // 9: helios.auth.SignInVerifyResponse + (*SignOutRequest)(nil), // 10: helios.auth.SignOutRequest + (*SignOutResponse)(nil), // 11: helios.auth.SignOutResponse + (*AuthedHumanRequest)(nil), // 12: helios.auth.AuthedHumanRequest + (*AuthedHumanResponse)(nil), // 13: helios.auth.AuthedHumanResponse + nil, // 14: helios.auth.ErrorDetail.MetadataEntry +} +var file_helios_auth_auth_proto_depIdxs = []int32{ + 14, // 0: helios.auth.ErrorDetail.metadata:type_name -> helios.auth.ErrorDetail.MetadataEntry + 0, // 1: helios.auth.AuthedHuman.auth_role:type_name -> helios.auth.AuthRole + 1, // 2: helios.auth.AuthedHuman.client_type:type_name -> helios.auth.ClientType + 1, // 3: helios.auth.SignInRequest.client_type:type_name -> helios.auth.ClientType + 1, // 4: helios.auth.SignInVerifyRequest.client_type:type_name -> helios.auth.ClientType + 0, // 5: helios.auth.SignInVerifyResponse.role:type_name -> helios.auth.AuthRole + 1, // 6: helios.auth.SignInVerifyResponse.client_type:type_name -> helios.auth.ClientType + 3, // 7: helios.auth.AuthedHumanResponse.authed_human:type_name -> helios.auth.AuthedHuman + 4, // 8: helios.auth.AuthService.Register:input_type -> helios.auth.RegisterRequest + 6, // 9: helios.auth.AuthService.SignIn:input_type -> helios.auth.SignInRequest + 8, // 10: helios.auth.AuthService.SignInVerify:input_type -> helios.auth.SignInVerifyRequest + 10, // 11: helios.auth.AuthService.SignOut:input_type -> helios.auth.SignOutRequest + 12, // 12: helios.auth.AuthService.AuthedHuman:input_type -> helios.auth.AuthedHumanRequest + 5, // 13: helios.auth.AuthService.Register:output_type -> helios.auth.RegisterResponse + 7, // 14: helios.auth.AuthService.SignIn:output_type -> helios.auth.SignInResponse + 9, // 15: helios.auth.AuthService.SignInVerify:output_type -> helios.auth.SignInVerifyResponse + 11, // 16: helios.auth.AuthService.SignOut:output_type -> helios.auth.SignOutResponse + 13, // 17: helios.auth.AuthService.AuthedHuman:output_type -> helios.auth.AuthedHumanResponse + 13, // [13:18] is the sub-list for method output_type + 8, // [8:13] 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_helios_auth_auth_proto_init() } +func file_helios_auth_auth_proto_init() { + if File_helios_auth_auth_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_auth_auth_proto_rawDesc, + NumEnums: 2, + NumMessages: 13, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_auth_auth_proto_goTypes, + DependencyIndexes: file_helios_auth_auth_proto_depIdxs, + EnumInfos: file_helios_auth_auth_proto_enumTypes, + MessageInfos: file_helios_auth_auth_proto_msgTypes, + }.Build() + File_helios_auth_auth_proto = out.File + file_helios_auth_auth_proto_rawDesc = nil + file_helios_auth_auth_proto_goTypes = nil + file_helios_auth_auth_proto_depIdxs = nil +} diff --git a/go/genproto/helios/auth/auth_grpc.pb.go b/go/genproto/helios/auth/auth_grpc.pb.go new file mode 100644 index 0000000..b237b59 --- /dev/null +++ b/go/genproto/helios/auth/auth_grpc.pb.go @@ -0,0 +1,285 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/auth/auth.proto + +package pbauth + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + AuthService_Register_FullMethodName = "/helios.auth.AuthService/Register" + AuthService_SignIn_FullMethodName = "/helios.auth.AuthService/SignIn" + AuthService_SignInVerify_FullMethodName = "/helios.auth.AuthService/SignInVerify" + AuthService_SignOut_FullMethodName = "/helios.auth.AuthService/SignOut" + AuthService_AuthedHuman_FullMethodName = "/helios.auth.AuthService/AuthedHuman" +) + +// AuthServiceClient is the client API for AuthService 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 AuthServiceClient interface { + // Returns "ALREADY_EXISTS" if the email is already registered. + Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) + // Sends email with a code. + SignIn(ctx context.Context, in *SignInRequest, opts ...grpc.CallOption) (*SignInResponse, error) + // Verifies the code and returns a token. + SignInVerify(ctx context.Context, in *SignInVerifyRequest, opts ...grpc.CallOption) (*SignInVerifyResponse, error) + // Expires the session, if have one with provided token in "authorization" metadata + SignOut(ctx context.Context, in *SignOutRequest, opts ...grpc.CallOption) (*SignOutResponse, error) + // Returns the authed human based on session_token in metadata. Returns unauthenticated otherwise. + // Requires session token in "authorization" metadata. + AuthedHuman(ctx context.Context, in *AuthedHumanRequest, opts ...grpc.CallOption) (*AuthedHumanResponse, error) +} + +type authServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient { + return &authServiceClient{cc} +} + +func (c *authServiceClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RegisterResponse) + err := c.cc.Invoke(ctx, AuthService_Register_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) SignIn(ctx context.Context, in *SignInRequest, opts ...grpc.CallOption) (*SignInResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SignInResponse) + err := c.cc.Invoke(ctx, AuthService_SignIn_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) SignInVerify(ctx context.Context, in *SignInVerifyRequest, opts ...grpc.CallOption) (*SignInVerifyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SignInVerifyResponse) + err := c.cc.Invoke(ctx, AuthService_SignInVerify_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) SignOut(ctx context.Context, in *SignOutRequest, opts ...grpc.CallOption) (*SignOutResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SignOutResponse) + err := c.cc.Invoke(ctx, AuthService_SignOut_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) AuthedHuman(ctx context.Context, in *AuthedHumanRequest, opts ...grpc.CallOption) (*AuthedHumanResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AuthedHumanResponse) + err := c.cc.Invoke(ctx, AuthService_AuthedHuman_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AuthServiceServer is the server API for AuthService service. +// All implementations must embed UnimplementedAuthServiceServer +// for forward compatibility. +type AuthServiceServer interface { + // Returns "ALREADY_EXISTS" if the email is already registered. + Register(context.Context, *RegisterRequest) (*RegisterResponse, error) + // Sends email with a code. + SignIn(context.Context, *SignInRequest) (*SignInResponse, error) + // Verifies the code and returns a token. + SignInVerify(context.Context, *SignInVerifyRequest) (*SignInVerifyResponse, error) + // Expires the session, if have one with provided token in "authorization" metadata + SignOut(context.Context, *SignOutRequest) (*SignOutResponse, error) + // Returns the authed human based on session_token in metadata. Returns unauthenticated otherwise. + // Requires session token in "authorization" metadata. + AuthedHuman(context.Context, *AuthedHumanRequest) (*AuthedHumanResponse, error) + mustEmbedUnimplementedAuthServiceServer() +} + +// UnimplementedAuthServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAuthServiceServer struct{} + +func (UnimplementedAuthServiceServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") +} +func (UnimplementedAuthServiceServer) SignIn(context.Context, *SignInRequest) (*SignInResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SignIn not implemented") +} +func (UnimplementedAuthServiceServer) SignInVerify(context.Context, *SignInVerifyRequest) (*SignInVerifyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SignInVerify not implemented") +} +func (UnimplementedAuthServiceServer) SignOut(context.Context, *SignOutRequest) (*SignOutResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SignOut not implemented") +} +func (UnimplementedAuthServiceServer) AuthedHuman(context.Context, *AuthedHumanRequest) (*AuthedHumanResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AuthedHuman not implemented") +} +func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} +func (UnimplementedAuthServiceServer) testEmbeddedByValue() {} + +// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AuthServiceServer will +// result in compilation errors. +type UnsafeAuthServiceServer interface { + mustEmbedUnimplementedAuthServiceServer() +} + +func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) { + // If the following call pancis, it indicates UnimplementedAuthServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&AuthService_ServiceDesc, srv) +} + +func _AuthService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).Register(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthService_Register_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).Register(ctx, req.(*RegisterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_SignIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SignInRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).SignIn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthService_SignIn_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).SignIn(ctx, req.(*SignInRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_SignInVerify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SignInVerifyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).SignInVerify(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthService_SignInVerify_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).SignInVerify(ctx, req.(*SignInVerifyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_SignOut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SignOutRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).SignOut(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthService_SignOut_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).SignOut(ctx, req.(*SignOutRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_AuthedHuman_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AuthedHumanRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).AuthedHuman(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthService_AuthedHuman_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).AuthedHuman(ctx, req.(*AuthedHumanRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AuthService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.auth.AuthService", + HandlerType: (*AuthServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Register", + Handler: _AuthService_Register_Handler, + }, + { + MethodName: "SignIn", + Handler: _AuthService_SignIn_Handler, + }, + { + MethodName: "SignInVerify", + Handler: _AuthService_SignInVerify_Handler, + }, + { + MethodName: "SignOut", + Handler: _AuthService_SignOut_Handler, + }, + { + MethodName: "AuthedHuman", + Handler: _AuthService_AuthedHuman_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/auth/auth.proto", +} diff --git a/go/genproto/helios/compass/compass.pb.go b/go/genproto/helios/compass/compass.pb.go new file mode 100644 index 0000000..e28cd4f --- /dev/null +++ b/go/genproto/helios/compass/compass.pb.go @@ -0,0 +1,643 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/compass/compass.proto + +package pbcompass + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 SearchPlacesRequest_SearchType int32 + +const ( + SearchPlacesRequest_SEARCH_TYPE_UNSPECIFIED SearchPlacesRequest_SearchType = 0 + // When we strictly want to search for a city, state, country + SearchPlacesRequest_SEARCH_TYPE_CITY SearchPlacesRequest_SearchType = 1 + // When we want a full address like for a shipping address + SearchPlacesRequest_SEARCH_TYPE_ADDRESS SearchPlacesRequest_SearchType = 2 +) + +// Enum value maps for SearchPlacesRequest_SearchType. +var ( + SearchPlacesRequest_SearchType_name = map[int32]string{ + 0: "SEARCH_TYPE_UNSPECIFIED", + 1: "SEARCH_TYPE_CITY", + 2: "SEARCH_TYPE_ADDRESS", + } + SearchPlacesRequest_SearchType_value = map[string]int32{ + "SEARCH_TYPE_UNSPECIFIED": 0, + "SEARCH_TYPE_CITY": 1, + "SEARCH_TYPE_ADDRESS": 2, + } +) + +func (x SearchPlacesRequest_SearchType) Enum() *SearchPlacesRequest_SearchType { + p := new(SearchPlacesRequest_SearchType) + *p = x + return p +} + +func (x SearchPlacesRequest_SearchType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SearchPlacesRequest_SearchType) Descriptor() protoreflect.EnumDescriptor { + return file_helios_compass_compass_proto_enumTypes[0].Descriptor() +} + +func (SearchPlacesRequest_SearchType) Type() protoreflect.EnumType { + return &file_helios_compass_compass_proto_enumTypes[0] +} + +func (x SearchPlacesRequest_SearchType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SearchPlacesRequest_SearchType.Descriptor instead. +func (SearchPlacesRequest_SearchType) EnumDescriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{1, 0} +} + +type Coordinate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Latitude float64 `protobuf:"fixed64,1,opt,name=latitude,proto3" json:"latitude,omitempty"` + Longitude float64 `protobuf:"fixed64,2,opt,name=longitude,proto3" json:"longitude,omitempty"` +} + +func (x *Coordinate) Reset() { + *x = Coordinate{} + mi := &file_helios_compass_compass_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Coordinate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Coordinate) ProtoMessage() {} + +func (x *Coordinate) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Coordinate.ProtoReflect.Descriptor instead. +func (*Coordinate) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{0} +} + +func (x *Coordinate) GetLatitude() float64 { + if x != nil { + return x.Latitude + } + return 0 +} + +func (x *Coordinate) GetLongitude() float64 { + if x != nil { + return x.Longitude + } + return 0 +} + +type SearchPlacesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + SearchType SearchPlacesRequest_SearchType `protobuf:"varint,2,opt,name=search_type,json=searchType,proto3,enum=helios.compass.SearchPlacesRequest_SearchType" json:"search_type,omitempty"` +} + +func (x *SearchPlacesRequest) Reset() { + *x = SearchPlacesRequest{} + mi := &file_helios_compass_compass_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SearchPlacesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchPlacesRequest) ProtoMessage() {} + +func (x *SearchPlacesRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchPlacesRequest.ProtoReflect.Descriptor instead. +func (*SearchPlacesRequest) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{1} +} + +func (x *SearchPlacesRequest) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *SearchPlacesRequest) GetSearchType() SearchPlacesRequest_SearchType { + if x != nil { + return x.SearchType + } + return SearchPlacesRequest_SEARCH_TYPE_UNSPECIFIED +} + +type SearchPlacesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Places []*SearchPlacesResponse_AutocompletePrediction `protobuf:"bytes,1,rep,name=places,proto3" json:"places,omitempty"` +} + +func (x *SearchPlacesResponse) Reset() { + *x = SearchPlacesResponse{} + mi := &file_helios_compass_compass_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SearchPlacesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchPlacesResponse) ProtoMessage() {} + +func (x *SearchPlacesResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchPlacesResponse.ProtoReflect.Descriptor instead. +func (*SearchPlacesResponse) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{2} +} + +func (x *SearchPlacesResponse) GetPlaces() []*SearchPlacesResponse_AutocompletePrediction { + if x != nil { + return x.Places + } + return nil +} + +type GetPlaceByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PlaceId string `protobuf:"bytes,1,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` +} + +func (x *GetPlaceByIdRequest) Reset() { + *x = GetPlaceByIdRequest{} + mi := &file_helios_compass_compass_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPlaceByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPlaceByIdRequest) ProtoMessage() {} + +func (x *GetPlaceByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPlaceByIdRequest.ProtoReflect.Descriptor instead. +func (*GetPlaceByIdRequest) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{3} +} + +func (x *GetPlaceByIdRequest) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +type GetPlaceByIdResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PlaceId string `protobuf:"bytes,1,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + Coordinate *Coordinate `protobuf:"bytes,3,opt,name=coordinate,proto3" json:"coordinate,omitempty"` +} + +func (x *GetPlaceByIdResponse) Reset() { + *x = GetPlaceByIdResponse{} + mi := &file_helios_compass_compass_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPlaceByIdResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPlaceByIdResponse) ProtoMessage() {} + +func (x *GetPlaceByIdResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPlaceByIdResponse.ProtoReflect.Descriptor instead. +func (*GetPlaceByIdResponse) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{4} +} + +func (x *GetPlaceByIdResponse) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *GetPlaceByIdResponse) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *GetPlaceByIdResponse) GetCoordinate() *Coordinate { + if x != nil { + return x.Coordinate + } + return nil +} + +type GetPlaceByIpRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` +} + +func (x *GetPlaceByIpRequest) Reset() { + *x = GetPlaceByIpRequest{} + mi := &file_helios_compass_compass_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPlaceByIpRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPlaceByIpRequest) ProtoMessage() {} + +func (x *GetPlaceByIpRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPlaceByIpRequest.ProtoReflect.Descriptor instead. +func (*GetPlaceByIpRequest) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{5} +} + +func (x *GetPlaceByIpRequest) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +type GetPlaceByIpResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PlaceId string `protobuf:"bytes,1,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + Coordinate *Coordinate `protobuf:"bytes,3,opt,name=coordinate,proto3" json:"coordinate,omitempty"` +} + +func (x *GetPlaceByIpResponse) Reset() { + *x = GetPlaceByIpResponse{} + mi := &file_helios_compass_compass_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPlaceByIpResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPlaceByIpResponse) ProtoMessage() {} + +func (x *GetPlaceByIpResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPlaceByIpResponse.ProtoReflect.Descriptor instead. +func (*GetPlaceByIpResponse) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{6} +} + +func (x *GetPlaceByIpResponse) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *GetPlaceByIpResponse) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *GetPlaceByIpResponse) GetCoordinate() *Coordinate { + if x != nil { + return x.Coordinate + } + return nil +} + +type SearchPlacesResponse_AutocompletePrediction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PlaceId string `protobuf:"bytes,1,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` +} + +func (x *SearchPlacesResponse_AutocompletePrediction) Reset() { + *x = SearchPlacesResponse_AutocompletePrediction{} + mi := &file_helios_compass_compass_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SearchPlacesResponse_AutocompletePrediction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchPlacesResponse_AutocompletePrediction) ProtoMessage() {} + +func (x *SearchPlacesResponse_AutocompletePrediction) ProtoReflect() protoreflect.Message { + mi := &file_helios_compass_compass_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchPlacesResponse_AutocompletePrediction.ProtoReflect.Descriptor instead. +func (*SearchPlacesResponse_AutocompletePrediction) Descriptor() ([]byte, []int) { + return file_helios_compass_compass_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *SearchPlacesResponse_AutocompletePrediction) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *SearchPlacesResponse_AutocompletePrediction) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +var File_helios_compass_compass_proto protoreflect.FileDescriptor + +var file_helios_compass_compass_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, + 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x22, 0x46, + 0x0a, 0x0a, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, + 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, + 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, + 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0xd6, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x12, 0x4f, 0x0a, 0x0b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0x58, 0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x14, 0x0a, 0x10, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x43, 0x49, 0x54, 0x59, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x22, + 0xc3, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x06, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, + 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, + 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x65, 0x64, 0x69, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x1a, 0x56, 0x0a, + 0x16, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x65, + 0x64, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x30, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, + 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, + 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x70, 0x6c, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x90, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, + 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3a, + 0x0a, 0x0a, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x73, 0x73, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x0a, + 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, + 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x70, 0x22, 0x90, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, + 0x49, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6f, 0x6f, 0x72, + 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x2e, 0x43, 0x6f, + 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, + 0x6e, 0x61, 0x74, 0x65, 0x32, 0xa0, 0x02, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, + 0x12, 0x5b, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, + 0x12, 0x23, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, + 0x73, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, + 0x0c, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x23, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x2e, 0x47, + 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x73, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0c, 0x47, 0x65, + 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x70, 0x12, 0x23, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x24, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, + 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x70, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, + 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x3b, + 0x70, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x73, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_helios_compass_compass_proto_rawDescOnce sync.Once + file_helios_compass_compass_proto_rawDescData = file_helios_compass_compass_proto_rawDesc +) + +func file_helios_compass_compass_proto_rawDescGZIP() []byte { + file_helios_compass_compass_proto_rawDescOnce.Do(func() { + file_helios_compass_compass_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_compass_compass_proto_rawDescData) + }) + return file_helios_compass_compass_proto_rawDescData +} + +var file_helios_compass_compass_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_helios_compass_compass_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_helios_compass_compass_proto_goTypes = []any{ + (SearchPlacesRequest_SearchType)(0), // 0: helios.compass.SearchPlacesRequest.SearchType + (*Coordinate)(nil), // 1: helios.compass.Coordinate + (*SearchPlacesRequest)(nil), // 2: helios.compass.SearchPlacesRequest + (*SearchPlacesResponse)(nil), // 3: helios.compass.SearchPlacesResponse + (*GetPlaceByIdRequest)(nil), // 4: helios.compass.GetPlaceByIdRequest + (*GetPlaceByIdResponse)(nil), // 5: helios.compass.GetPlaceByIdResponse + (*GetPlaceByIpRequest)(nil), // 6: helios.compass.GetPlaceByIpRequest + (*GetPlaceByIpResponse)(nil), // 7: helios.compass.GetPlaceByIpResponse + (*SearchPlacesResponse_AutocompletePrediction)(nil), // 8: helios.compass.SearchPlacesResponse.AutocompletePrediction +} +var file_helios_compass_compass_proto_depIdxs = []int32{ + 0, // 0: helios.compass.SearchPlacesRequest.search_type:type_name -> helios.compass.SearchPlacesRequest.SearchType + 8, // 1: helios.compass.SearchPlacesResponse.places:type_name -> helios.compass.SearchPlacesResponse.AutocompletePrediction + 1, // 2: helios.compass.GetPlaceByIdResponse.coordinate:type_name -> helios.compass.Coordinate + 1, // 3: helios.compass.GetPlaceByIpResponse.coordinate:type_name -> helios.compass.Coordinate + 2, // 4: helios.compass.Compass.SearchPlaces:input_type -> helios.compass.SearchPlacesRequest + 4, // 5: helios.compass.Compass.GetPlaceById:input_type -> helios.compass.GetPlaceByIdRequest + 6, // 6: helios.compass.Compass.GetPlaceByIp:input_type -> helios.compass.GetPlaceByIpRequest + 3, // 7: helios.compass.Compass.SearchPlaces:output_type -> helios.compass.SearchPlacesResponse + 5, // 8: helios.compass.Compass.GetPlaceById:output_type -> helios.compass.GetPlaceByIdResponse + 7, // 9: helios.compass.Compass.GetPlaceByIp:output_type -> helios.compass.GetPlaceByIpResponse + 7, // [7:10] is the sub-list for method output_type + 4, // [4:7] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_helios_compass_compass_proto_init() } +func file_helios_compass_compass_proto_init() { + if File_helios_compass_compass_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_compass_compass_proto_rawDesc, + NumEnums: 1, + NumMessages: 8, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_compass_compass_proto_goTypes, + DependencyIndexes: file_helios_compass_compass_proto_depIdxs, + EnumInfos: file_helios_compass_compass_proto_enumTypes, + MessageInfos: file_helios_compass_compass_proto_msgTypes, + }.Build() + File_helios_compass_compass_proto = out.File + file_helios_compass_compass_proto_rawDesc = nil + file_helios_compass_compass_proto_goTypes = nil + file_helios_compass_compass_proto_depIdxs = nil +} diff --git a/go/genproto/helios/compass/compass_grpc.pb.go b/go/genproto/helios/compass/compass_grpc.pb.go new file mode 100644 index 0000000..2322aaf --- /dev/null +++ b/go/genproto/helios/compass/compass_grpc.pb.go @@ -0,0 +1,207 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/compass/compass.proto + +package pbcompass + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Compass_SearchPlaces_FullMethodName = "/helios.compass.Compass/SearchPlaces" + Compass_GetPlaceById_FullMethodName = "/helios.compass.Compass/GetPlaceById" + Compass_GetPlaceByIp_FullMethodName = "/helios.compass.Compass/GetPlaceByIp" +) + +// CompassClient is the client API for Compass 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. +// +// compass knows a lot about where we are in the world and universe we live in, how it's connected, and more. +type CompassClient interface { + // SearchPlaces returns a list of places based on the given query. + SearchPlaces(ctx context.Context, in *SearchPlacesRequest, opts ...grpc.CallOption) (*SearchPlacesResponse, error) + // GetPlaceById returns a place and it's details by its place_id which is google place id. + // if it's not found, it returns an error + GetPlaceById(ctx context.Context, in *GetPlaceByIdRequest, opts ...grpc.CallOption) (*GetPlaceByIdResponse, error) + GetPlaceByIp(ctx context.Context, in *GetPlaceByIpRequest, opts ...grpc.CallOption) (*GetPlaceByIpResponse, error) +} + +type compassClient struct { + cc grpc.ClientConnInterface +} + +func NewCompassClient(cc grpc.ClientConnInterface) CompassClient { + return &compassClient{cc} +} + +func (c *compassClient) SearchPlaces(ctx context.Context, in *SearchPlacesRequest, opts ...grpc.CallOption) (*SearchPlacesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchPlacesResponse) + err := c.cc.Invoke(ctx, Compass_SearchPlaces_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *compassClient) GetPlaceById(ctx context.Context, in *GetPlaceByIdRequest, opts ...grpc.CallOption) (*GetPlaceByIdResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetPlaceByIdResponse) + err := c.cc.Invoke(ctx, Compass_GetPlaceById_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *compassClient) GetPlaceByIp(ctx context.Context, in *GetPlaceByIpRequest, opts ...grpc.CallOption) (*GetPlaceByIpResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetPlaceByIpResponse) + err := c.cc.Invoke(ctx, Compass_GetPlaceByIp_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CompassServer is the server API for Compass service. +// All implementations must embed UnimplementedCompassServer +// for forward compatibility. +// +// compass knows a lot about where we are in the world and universe we live in, how it's connected, and more. +type CompassServer interface { + // SearchPlaces returns a list of places based on the given query. + SearchPlaces(context.Context, *SearchPlacesRequest) (*SearchPlacesResponse, error) + // GetPlaceById returns a place and it's details by its place_id which is google place id. + // if it's not found, it returns an error + GetPlaceById(context.Context, *GetPlaceByIdRequest) (*GetPlaceByIdResponse, error) + GetPlaceByIp(context.Context, *GetPlaceByIpRequest) (*GetPlaceByIpResponse, error) + mustEmbedUnimplementedCompassServer() +} + +// UnimplementedCompassServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCompassServer struct{} + +func (UnimplementedCompassServer) SearchPlaces(context.Context, *SearchPlacesRequest) (*SearchPlacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchPlaces not implemented") +} +func (UnimplementedCompassServer) GetPlaceById(context.Context, *GetPlaceByIdRequest) (*GetPlaceByIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPlaceById not implemented") +} +func (UnimplementedCompassServer) GetPlaceByIp(context.Context, *GetPlaceByIpRequest) (*GetPlaceByIpResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPlaceByIp not implemented") +} +func (UnimplementedCompassServer) mustEmbedUnimplementedCompassServer() {} +func (UnimplementedCompassServer) testEmbeddedByValue() {} + +// UnsafeCompassServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CompassServer will +// result in compilation errors. +type UnsafeCompassServer interface { + mustEmbedUnimplementedCompassServer() +} + +func RegisterCompassServer(s grpc.ServiceRegistrar, srv CompassServer) { + // If the following call pancis, it indicates UnimplementedCompassServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Compass_ServiceDesc, srv) +} + +func _Compass_SearchPlaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchPlacesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CompassServer).SearchPlaces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Compass_SearchPlaces_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CompassServer).SearchPlaces(ctx, req.(*SearchPlacesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Compass_GetPlaceById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPlaceByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CompassServer).GetPlaceById(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Compass_GetPlaceById_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CompassServer).GetPlaceById(ctx, req.(*GetPlaceByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Compass_GetPlaceByIp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPlaceByIpRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CompassServer).GetPlaceByIp(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Compass_GetPlaceByIp_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CompassServer).GetPlaceByIp(ctx, req.(*GetPlaceByIpRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Compass_ServiceDesc is the grpc.ServiceDesc for Compass service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Compass_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.compass.Compass", + HandlerType: (*CompassServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SearchPlaces", + Handler: _Compass_SearchPlaces_Handler, + }, + { + MethodName: "GetPlaceById", + Handler: _Compass_GetPlaceById_Handler, + }, + { + MethodName: "GetPlaceByIp", + Handler: _Compass_GetPlaceByIp_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/compass/compass.proto", +} diff --git a/go/genproto/helios/depot/depot.pb.go b/go/genproto/helios/depot/depot.pb.go new file mode 100644 index 0000000..0dc62b3 --- /dev/null +++ b/go/genproto/helios/depot/depot.pb.go @@ -0,0 +1,871 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/depot/depot.proto + +package pbdepot + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 Object struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ObjectId string `protobuf:"bytes,1,opt,name=object_id,json=objectId,proto3" json:"object_id,omitempty"` + // Presigned url to download the object + ObjectUrl string `protobuf:"bytes,2,opt,name=object_url,json=objectUrl,proto3" json:"object_url,omitempty"` + // Whether or not this object is publicly accessible. + PublicInternet bool `protobuf:"varint,3,opt,name=public_internet,json=publicInternet,proto3" json:"public_internet,omitempty"` + // Arbitrary name that you can associate with this object. + // NOTE: This will NOT have problems with collisions. The depot system can have as many objects with the same name as desired. + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + ContentType string `protobuf:"bytes,5,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + ContentLength int32 `protobuf:"varint,7,opt,name=content_length,json=contentLength,proto3" json:"content_length,omitempty"` + StorageInformation *Object_StorageInformation `protobuf:"bytes,8,opt,name=storage_information,json=storageInformation,proto3" json:"storage_information,omitempty"` + // Whether or not this object contains content, yet (use to check whether upload urls were used). + ContainsContent bool `protobuf:"varint,9,opt,name=contains_content,json=containsContent,proto3" json:"contains_content,omitempty"` +} + +func (x *Object) Reset() { + *x = Object{} + mi := &file_helios_depot_depot_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Object) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Object) ProtoMessage() {} + +func (x *Object) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Object.ProtoReflect.Descriptor instead. +func (*Object) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{0} +} + +func (x *Object) GetObjectId() string { + if x != nil { + return x.ObjectId + } + return "" +} + +func (x *Object) GetObjectUrl() string { + if x != nil { + return x.ObjectUrl + } + return "" +} + +func (x *Object) GetPublicInternet() bool { + if x != nil { + return x.PublicInternet + } + return false +} + +func (x *Object) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Object) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *Object) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Object) GetContentLength() int32 { + if x != nil { + return x.ContentLength + } + return 0 +} + +func (x *Object) GetStorageInformation() *Object_StorageInformation { + if x != nil { + return x.StorageInformation + } + return nil +} + +func (x *Object) GetContainsContent() bool { + if x != nil { + return x.ContainsContent + } + return false +} + +type GetObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ObjectId string `protobuf:"bytes,1,opt,name=object_id,json=objectId,proto3" json:"object_id,omitempty"` +} + +func (x *GetObjectRequest) Reset() { + *x = GetObjectRequest{} + mi := &file_helios_depot_depot_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetObjectRequest) ProtoMessage() {} + +func (x *GetObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetObjectRequest.ProtoReflect.Descriptor instead. +func (*GetObjectRequest) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{1} +} + +func (x *GetObjectRequest) GetObjectId() string { + if x != nil { + return x.ObjectId + } + return "" +} + +type GetObjectResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Object *Object `protobuf:"bytes,1,opt,name=object,proto3" json:"object,omitempty"` +} + +func (x *GetObjectResponse) Reset() { + *x = GetObjectResponse{} + mi := &file_helios_depot_depot_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetObjectResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetObjectResponse) ProtoMessage() {} + +func (x *GetObjectResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetObjectResponse.ProtoReflect.Descriptor instead. +func (*GetObjectResponse) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{2} +} + +func (x *GetObjectResponse) GetObject() *Object { + if x != nil { + return x.Object + } + return nil +} + +type GetObjectsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ObjectIds []string `protobuf:"bytes,1,rep,name=object_ids,json=objectIds,proto3" json:"object_ids,omitempty"` +} + +func (x *GetObjectsRequest) Reset() { + *x = GetObjectsRequest{} + mi := &file_helios_depot_depot_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetObjectsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetObjectsRequest) ProtoMessage() {} + +func (x *GetObjectsRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetObjectsRequest.ProtoReflect.Descriptor instead. +func (*GetObjectsRequest) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{3} +} + +func (x *GetObjectsRequest) GetObjectIds() []string { + if x != nil { + return x.ObjectIds + } + return nil +} + +type GetObjectsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Objects []*Object `protobuf:"bytes,1,rep,name=objects,proto3" json:"objects,omitempty"` +} + +func (x *GetObjectsResponse) Reset() { + *x = GetObjectsResponse{} + mi := &file_helios_depot_depot_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetObjectsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetObjectsResponse) ProtoMessage() {} + +func (x *GetObjectsResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetObjectsResponse.ProtoReflect.Descriptor instead. +func (*GetObjectsResponse) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{4} +} + +func (x *GetObjectsResponse) GetObjects() []*Object { + if x != nil { + return x.Objects + } + return nil +} + +type ListObjectsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListObjectsRequest) Reset() { + *x = ListObjectsRequest{} + mi := &file_helios_depot_depot_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListObjectsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListObjectsRequest) ProtoMessage() {} + +func (x *ListObjectsRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListObjectsRequest.ProtoReflect.Descriptor instead. +func (*ListObjectsRequest) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{5} +} + +type ListObjectsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Objects []*Object `protobuf:"bytes,1,rep,name=objects,proto3" json:"objects,omitempty"` +} + +func (x *ListObjectsResponse) Reset() { + *x = ListObjectsResponse{} + mi := &file_helios_depot_depot_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListObjectsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListObjectsResponse) ProtoMessage() {} + +func (x *ListObjectsResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListObjectsResponse.ProtoReflect.Descriptor instead. +func (*ListObjectsResponse) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{6} +} + +func (x *ListObjectsResponse) GetObjects() []*Object { + if x != nil { + return x.Objects + } + return nil +} + +type UploadNewObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required...anything for example: "image.jpg" + // we don't really care about the extension as the object that is stored in the bucket is based on a generated object_id + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Required + ContentType string `protobuf:"bytes,2,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + // Required + ContentLength int64 `protobuf:"varint,3,opt,name=content_length,json=contentLength,proto3" json:"content_length,omitempty"` + // Required. Whether or not to make this publicly accessible to the internet. + PublicInternet bool `protobuf:"varint,4,opt,name=public_internet,json=publicInternet,proto3" json:"public_internet,omitempty"` +} + +func (x *UploadNewObjectRequest) Reset() { + *x = UploadNewObjectRequest{} + mi := &file_helios_depot_depot_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadNewObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadNewObjectRequest) ProtoMessage() {} + +func (x *UploadNewObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadNewObjectRequest.ProtoReflect.Descriptor instead. +func (*UploadNewObjectRequest) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{7} +} + +func (x *UploadNewObjectRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UploadNewObjectRequest) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *UploadNewObjectRequest) GetContentLength() int64 { + if x != nil { + return x.ContentLength + } + return 0 +} + +func (x *UploadNewObjectRequest) GetPublicInternet() bool { + if x != nil { + return x.PublicInternet + } + return false +} + +type UploadNewObjectResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ObjectId string `protobuf:"bytes,1,opt,name=object_id,json=objectId,proto3" json:"object_id,omitempty"` + // make a PUT request to this URL + UploadUrl string `protobuf:"bytes,2,opt,name=upload_url,json=uploadUrl,proto3" json:"upload_url,omitempty"` + // headers to include in the PUT request + UploadHeaders map[string]string `protobuf:"bytes,3,rep,name=upload_headers,json=uploadHeaders,proto3" json:"upload_headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *UploadNewObjectResponse) Reset() { + *x = UploadNewObjectResponse{} + mi := &file_helios_depot_depot_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadNewObjectResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadNewObjectResponse) ProtoMessage() {} + +func (x *UploadNewObjectResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadNewObjectResponse.ProtoReflect.Descriptor instead. +func (*UploadNewObjectResponse) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{8} +} + +func (x *UploadNewObjectResponse) GetObjectId() string { + if x != nil { + return x.ObjectId + } + return "" +} + +func (x *UploadNewObjectResponse) GetUploadUrl() string { + if x != nil { + return x.UploadUrl + } + return "" +} + +func (x *UploadNewObjectResponse) GetUploadHeaders() map[string]string { + if x != nil { + return x.UploadHeaders + } + return nil +} + +type DeleteObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ObjectId string `protobuf:"bytes,1,opt,name=object_id,json=objectId,proto3" json:"object_id,omitempty"` +} + +func (x *DeleteObjectRequest) Reset() { + *x = DeleteObjectRequest{} + mi := &file_helios_depot_depot_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteObjectRequest) ProtoMessage() {} + +func (x *DeleteObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteObjectRequest.ProtoReflect.Descriptor instead. +func (*DeleteObjectRequest) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{9} +} + +func (x *DeleteObjectRequest) GetObjectId() string { + if x != nil { + return x.ObjectId + } + return "" +} + +type DeleteObjectResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteObjectResponse) Reset() { + *x = DeleteObjectResponse{} + mi := &file_helios_depot_depot_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteObjectResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteObjectResponse) ProtoMessage() {} + +func (x *DeleteObjectResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteObjectResponse.ProtoReflect.Descriptor instead. +func (*DeleteObjectResponse) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{10} +} + +type Object_StorageInformation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bucket string `protobuf:"bytes,1,opt,name=bucket,proto3" json:"bucket,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + GsUtilUri string `protobuf:"bytes,3,opt,name=gs_util_uri,json=gsUtilUri,proto3" json:"gs_util_uri,omitempty"` +} + +func (x *Object_StorageInformation) Reset() { + *x = Object_StorageInformation{} + mi := &file_helios_depot_depot_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Object_StorageInformation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Object_StorageInformation) ProtoMessage() {} + +func (x *Object_StorageInformation) ProtoReflect() protoreflect.Message { + mi := &file_helios_depot_depot_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Object_StorageInformation.ProtoReflect.Descriptor instead. +func (*Object_StorageInformation) Descriptor() ([]byte, []int) { + return file_helios_depot_depot_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *Object_StorageInformation) GetBucket() string { + if x != nil { + return x.Bucket + } + return "" +} + +func (x *Object_StorageInformation) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Object_StorageInformation) GetGsUtilUri() string { + if x != nil { + return x.GsUtilUri + } + return "" +} + +var File_helios_depot_depot_proto protoreflect.FileDescriptor + +var file_helios_depot_depot_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x64, 0x65, 0x70, 0x6f, 0x74, 0x2f, 0x64, + 0x65, 0x70, 0x6f, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, 0x74, 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, 0xeb, 0x03, 0x0a, 0x06, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, + 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, + 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, + 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, 0x25, 0x0a, 0x0e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x12, 0x58, 0x0a, 0x13, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, 0x74, 0x2e, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x1a, 0x5e, 0x0a, 0x12, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0b, 0x67, 0x73, 0x5f, 0x75, 0x74, + 0x69, 0x6c, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x73, + 0x55, 0x74, 0x69, 0x6c, 0x55, 0x72, 0x69, 0x22, 0x2f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x22, 0x41, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, + 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, 0x74, 0x2e, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x32, 0x0a, 0x11, 0x47, + 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x73, 0x22, + 0x44, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, + 0x64, 0x65, 0x70, 0x6f, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x45, 0x0a, 0x13, 0x4c, + 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, + 0x6f, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x22, 0x9f, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x65, 0x77, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 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, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x22, 0xf8, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, + 0x65, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x12, 0x5f, 0x0a, 0x0e, + 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, + 0x70, 0x6f, 0x74, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x65, 0x77, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, + 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x40, 0x0a, + 0x12, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x32, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x49, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe5, 0x02, 0x0a, 0x05, + 0x44, 0x65, 0x70, 0x6f, 0x74, 0x12, 0x4e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x12, 0x1e, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, + 0x6f, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, + 0x70, 0x6f, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x0f, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x4e, 0x65, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x24, 0x2e, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, 0x74, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x4e, 0x65, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, 0x74, + 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x65, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x0c, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x70, 0x6f, 0x74, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2f, 0x64, 0x65, 0x70, 0x6f, 0x74, 0x3b, 0x70, 0x62, 0x64, 0x65, 0x70, 0x6f, + 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_helios_depot_depot_proto_rawDescOnce sync.Once + file_helios_depot_depot_proto_rawDescData = file_helios_depot_depot_proto_rawDesc +) + +func file_helios_depot_depot_proto_rawDescGZIP() []byte { + file_helios_depot_depot_proto_rawDescOnce.Do(func() { + file_helios_depot_depot_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_depot_depot_proto_rawDescData) + }) + return file_helios_depot_depot_proto_rawDescData +} + +var file_helios_depot_depot_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_helios_depot_depot_proto_goTypes = []any{ + (*Object)(nil), // 0: helios.depot.Object + (*GetObjectRequest)(nil), // 1: helios.depot.GetObjectRequest + (*GetObjectResponse)(nil), // 2: helios.depot.GetObjectResponse + (*GetObjectsRequest)(nil), // 3: helios.depot.GetObjectsRequest + (*GetObjectsResponse)(nil), // 4: helios.depot.GetObjectsResponse + (*ListObjectsRequest)(nil), // 5: helios.depot.ListObjectsRequest + (*ListObjectsResponse)(nil), // 6: helios.depot.ListObjectsResponse + (*UploadNewObjectRequest)(nil), // 7: helios.depot.UploadNewObjectRequest + (*UploadNewObjectResponse)(nil), // 8: helios.depot.UploadNewObjectResponse + (*DeleteObjectRequest)(nil), // 9: helios.depot.DeleteObjectRequest + (*DeleteObjectResponse)(nil), // 10: helios.depot.DeleteObjectResponse + (*Object_StorageInformation)(nil), // 11: helios.depot.Object.StorageInformation + nil, // 12: helios.depot.UploadNewObjectResponse.UploadHeadersEntry + (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp +} +var file_helios_depot_depot_proto_depIdxs = []int32{ + 13, // 0: helios.depot.Object.created_at:type_name -> google.protobuf.Timestamp + 11, // 1: helios.depot.Object.storage_information:type_name -> helios.depot.Object.StorageInformation + 0, // 2: helios.depot.GetObjectResponse.object:type_name -> helios.depot.Object + 0, // 3: helios.depot.GetObjectsResponse.objects:type_name -> helios.depot.Object + 0, // 4: helios.depot.ListObjectsResponse.objects:type_name -> helios.depot.Object + 12, // 5: helios.depot.UploadNewObjectResponse.upload_headers:type_name -> helios.depot.UploadNewObjectResponse.UploadHeadersEntry + 1, // 6: helios.depot.Depot.GetObject:input_type -> helios.depot.GetObjectRequest + 3, // 7: helios.depot.Depot.GetObjects:input_type -> helios.depot.GetObjectsRequest + 7, // 8: helios.depot.Depot.UploadNewObject:input_type -> helios.depot.UploadNewObjectRequest + 9, // 9: helios.depot.Depot.DeleteObject:input_type -> helios.depot.DeleteObjectRequest + 2, // 10: helios.depot.Depot.GetObject:output_type -> helios.depot.GetObjectResponse + 4, // 11: helios.depot.Depot.GetObjects:output_type -> helios.depot.GetObjectsResponse + 8, // 12: helios.depot.Depot.UploadNewObject:output_type -> helios.depot.UploadNewObjectResponse + 10, // 13: helios.depot.Depot.DeleteObject:output_type -> helios.depot.DeleteObjectResponse + 10, // [10:14] is the sub-list for method output_type + 6, // [6:10] 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_helios_depot_depot_proto_init() } +func file_helios_depot_depot_proto_init() { + if File_helios_depot_depot_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_depot_depot_proto_rawDesc, + NumEnums: 0, + NumMessages: 13, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_depot_depot_proto_goTypes, + DependencyIndexes: file_helios_depot_depot_proto_depIdxs, + MessageInfos: file_helios_depot_depot_proto_msgTypes, + }.Build() + File_helios_depot_depot_proto = out.File + file_helios_depot_depot_proto_rawDesc = nil + file_helios_depot_depot_proto_goTypes = nil + file_helios_depot_depot_proto_depIdxs = nil +} diff --git a/go/genproto/helios/depot/depot_grpc.pb.go b/go/genproto/helios/depot/depot_grpc.pb.go new file mode 100644 index 0000000..7813eba --- /dev/null +++ b/go/genproto/helios/depot/depot_grpc.pb.go @@ -0,0 +1,241 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/depot/depot.proto + +package pbdepot + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Depot_GetObject_FullMethodName = "/helios.depot.Depot/GetObject" + Depot_GetObjects_FullMethodName = "/helios.depot.Depot/GetObjects" + Depot_UploadNewObject_FullMethodName = "/helios.depot.Depot/UploadNewObject" + Depot_DeleteObject_FullMethodName = "/helios.depot.Depot/DeleteObject" +) + +// DepotClient is the client API for Depot 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. +// +// Depot stores assets as objects and has other features of handling media. +type DepotClient interface { + // Returns NOT_FOUND if the object does not exist. + GetObject(ctx context.Context, in *GetObjectRequest, opts ...grpc.CallOption) (*GetObjectResponse, error) + GetObjects(ctx context.Context, in *GetObjectsRequest, opts ...grpc.CallOption) (*GetObjectsResponse, error) + UploadNewObject(ctx context.Context, in *UploadNewObjectRequest, opts ...grpc.CallOption) (*UploadNewObjectResponse, error) + DeleteObject(ctx context.Context, in *DeleteObjectRequest, opts ...grpc.CallOption) (*DeleteObjectResponse, error) +} + +type depotClient struct { + cc grpc.ClientConnInterface +} + +func NewDepotClient(cc grpc.ClientConnInterface) DepotClient { + return &depotClient{cc} +} + +func (c *depotClient) GetObject(ctx context.Context, in *GetObjectRequest, opts ...grpc.CallOption) (*GetObjectResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetObjectResponse) + err := c.cc.Invoke(ctx, Depot_GetObject_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *depotClient) GetObjects(ctx context.Context, in *GetObjectsRequest, opts ...grpc.CallOption) (*GetObjectsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetObjectsResponse) + err := c.cc.Invoke(ctx, Depot_GetObjects_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *depotClient) UploadNewObject(ctx context.Context, in *UploadNewObjectRequest, opts ...grpc.CallOption) (*UploadNewObjectResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UploadNewObjectResponse) + err := c.cc.Invoke(ctx, Depot_UploadNewObject_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *depotClient) DeleteObject(ctx context.Context, in *DeleteObjectRequest, opts ...grpc.CallOption) (*DeleteObjectResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteObjectResponse) + err := c.cc.Invoke(ctx, Depot_DeleteObject_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DepotServer is the server API for Depot service. +// All implementations must embed UnimplementedDepotServer +// for forward compatibility. +// +// Depot stores assets as objects and has other features of handling media. +type DepotServer interface { + // Returns NOT_FOUND if the object does not exist. + GetObject(context.Context, *GetObjectRequest) (*GetObjectResponse, error) + GetObjects(context.Context, *GetObjectsRequest) (*GetObjectsResponse, error) + UploadNewObject(context.Context, *UploadNewObjectRequest) (*UploadNewObjectResponse, error) + DeleteObject(context.Context, *DeleteObjectRequest) (*DeleteObjectResponse, error) + mustEmbedUnimplementedDepotServer() +} + +// UnimplementedDepotServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedDepotServer struct{} + +func (UnimplementedDepotServer) GetObject(context.Context, *GetObjectRequest) (*GetObjectResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetObject not implemented") +} +func (UnimplementedDepotServer) GetObjects(context.Context, *GetObjectsRequest) (*GetObjectsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetObjects not implemented") +} +func (UnimplementedDepotServer) UploadNewObject(context.Context, *UploadNewObjectRequest) (*UploadNewObjectResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UploadNewObject not implemented") +} +func (UnimplementedDepotServer) DeleteObject(context.Context, *DeleteObjectRequest) (*DeleteObjectResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteObject not implemented") +} +func (UnimplementedDepotServer) mustEmbedUnimplementedDepotServer() {} +func (UnimplementedDepotServer) testEmbeddedByValue() {} + +// UnsafeDepotServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to DepotServer will +// result in compilation errors. +type UnsafeDepotServer interface { + mustEmbedUnimplementedDepotServer() +} + +func RegisterDepotServer(s grpc.ServiceRegistrar, srv DepotServer) { + // If the following call pancis, it indicates UnimplementedDepotServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Depot_ServiceDesc, srv) +} + +func _Depot_GetObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DepotServer).GetObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Depot_GetObject_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DepotServer).GetObject(ctx, req.(*GetObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Depot_GetObjects_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetObjectsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DepotServer).GetObjects(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Depot_GetObjects_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DepotServer).GetObjects(ctx, req.(*GetObjectsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Depot_UploadNewObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadNewObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DepotServer).UploadNewObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Depot_UploadNewObject_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DepotServer).UploadNewObject(ctx, req.(*UploadNewObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Depot_DeleteObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DepotServer).DeleteObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Depot_DeleteObject_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DepotServer).DeleteObject(ctx, req.(*DeleteObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Depot_ServiceDesc is the grpc.ServiceDesc for Depot service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Depot_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.depot.Depot", + HandlerType: (*DepotServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetObject", + Handler: _Depot_GetObject_Handler, + }, + { + MethodName: "GetObjects", + Handler: _Depot_GetObjects_Handler, + }, + { + MethodName: "UploadNewObject", + Handler: _Depot_UploadNewObject_Handler, + }, + { + MethodName: "DeleteObject", + Handler: _Depot_DeleteObject_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/depot/depot.proto", +} diff --git a/go/genproto/helios/human/human.pb.go b/go/genproto/helios/human/human.pb.go new file mode 100644 index 0000000..4c4c9cc --- /dev/null +++ b/go/genproto/helios/human/human.pb.go @@ -0,0 +1,955 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/human/human.proto + +package pbhuman + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 Human struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Public url for the profile picture/headshot + ProfilePictureUrl string `protobuf:"bytes,2,opt,name=profile_picture_url,json=profilePictureUrl,proto3" json:"profile_picture_url,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + DisplayName string `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + IsFlowyAdmin bool `protobuf:"varint,5,opt,name=is_flowy_admin,json=isFlowyAdmin,proto3" json:"is_flowy_admin,omitempty"` + JoinedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=joined_at,json=joinedAt,proto3" json:"joined_at,omitempty"` +} + +func (x *Human) Reset() { + *x = Human{} + mi := &file_helios_human_human_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Human) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Human) ProtoMessage() {} + +func (x *Human) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Human.ProtoReflect.Descriptor instead. +func (*Human) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{0} +} + +func (x *Human) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Human) GetProfilePictureUrl() string { + if x != nil { + return x.ProfilePictureUrl + } + return "" +} + +func (x *Human) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *Human) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *Human) GetIsFlowyAdmin() bool { + if x != nil { + return x.IsFlowyAdmin + } + return false +} + +func (x *Human) GetJoinedAt() *timestamppb.Timestamp { + if x != nil { + return x.JoinedAt + } + return nil +} + +type AddHumanRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + ProfilePictureUrl string `protobuf:"bytes,3,opt,name=profile_picture_url,json=profilePictureUrl,proto3" json:"profile_picture_url,omitempty"` +} + +func (x *AddHumanRequest) Reset() { + *x = AddHumanRequest{} + mi := &file_helios_human_human_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddHumanRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddHumanRequest) ProtoMessage() {} + +func (x *AddHumanRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddHumanRequest.ProtoReflect.Descriptor instead. +func (*AddHumanRequest) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{1} +} + +func (x *AddHumanRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *AddHumanRequest) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *AddHumanRequest) GetProfilePictureUrl() string { + if x != nil { + return x.ProfilePictureUrl + } + return "" +} + +type AddHumanResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Human *Human `protobuf:"bytes,1,opt,name=human,proto3" json:"human,omitempty"` +} + +func (x *AddHumanResponse) Reset() { + *x = AddHumanResponse{} + mi := &file_helios_human_human_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddHumanResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddHumanResponse) ProtoMessage() {} + +func (x *AddHumanResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddHumanResponse.ProtoReflect.Descriptor instead. +func (*AddHumanResponse) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{2} +} + +func (x *AddHumanResponse) GetHuman() *Human { + if x != nil { + return x.Human + } + return nil +} + +type GetHumanByEmailRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *GetHumanByEmailRequest) Reset() { + *x = GetHumanByEmailRequest{} + mi := &file_helios_human_human_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetHumanByEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHumanByEmailRequest) ProtoMessage() {} + +func (x *GetHumanByEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHumanByEmailRequest.ProtoReflect.Descriptor instead. +func (*GetHumanByEmailRequest) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{3} +} + +func (x *GetHumanByEmailRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type GetHumanByEmailResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Human *Human `protobuf:"bytes,1,opt,name=human,proto3" json:"human,omitempty"` +} + +func (x *GetHumanByEmailResponse) Reset() { + *x = GetHumanByEmailResponse{} + mi := &file_helios_human_human_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetHumanByEmailResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHumanByEmailResponse) ProtoMessage() {} + +func (x *GetHumanByEmailResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHumanByEmailResponse.ProtoReflect.Descriptor instead. +func (*GetHumanByEmailResponse) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{4} +} + +func (x *GetHumanByEmailResponse) GetHuman() *Human { + if x != nil { + return x.Human + } + return nil +} + +type GetHumanByIdRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *GetHumanByIdRequest) Reset() { + *x = GetHumanByIdRequest{} + mi := &file_helios_human_human_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetHumanByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHumanByIdRequest) ProtoMessage() {} + +func (x *GetHumanByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHumanByIdRequest.ProtoReflect.Descriptor instead. +func (*GetHumanByIdRequest) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{5} +} + +func (x *GetHumanByIdRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetHumanByIdResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Human *Human `protobuf:"bytes,1,opt,name=human,proto3" json:"human,omitempty"` +} + +func (x *GetHumanByIdResponse) Reset() { + *x = GetHumanByIdResponse{} + mi := &file_helios_human_human_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetHumanByIdResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHumanByIdResponse) ProtoMessage() {} + +func (x *GetHumanByIdResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHumanByIdResponse.ProtoReflect.Descriptor instead. +func (*GetHumanByIdResponse) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{6} +} + +func (x *GetHumanByIdResponse) GetHuman() *Human { + if x != nil { + return x.Human + } + return nil +} + +type UpdateHumanProfilePictureRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HumanId string `protobuf:"bytes,1,opt,name=human_id,json=humanId,proto3" json:"human_id,omitempty"` + // Ensure that this profile picture is public + NewProfilePictureUrl string `protobuf:"bytes,2,opt,name=new_profile_picture_url,json=newProfilePictureUrl,proto3" json:"new_profile_picture_url,omitempty"` +} + +func (x *UpdateHumanProfilePictureRequest) Reset() { + *x = UpdateHumanProfilePictureRequest{} + mi := &file_helios_human_human_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateHumanProfilePictureRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateHumanProfilePictureRequest) ProtoMessage() {} + +func (x *UpdateHumanProfilePictureRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateHumanProfilePictureRequest.ProtoReflect.Descriptor instead. +func (*UpdateHumanProfilePictureRequest) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateHumanProfilePictureRequest) GetHumanId() string { + if x != nil { + return x.HumanId + } + return "" +} + +func (x *UpdateHumanProfilePictureRequest) GetNewProfilePictureUrl() string { + if x != nil { + return x.NewProfilePictureUrl + } + return "" +} + +type UpdateHumanProfilePictureResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateHumanProfilePictureResponse) Reset() { + *x = UpdateHumanProfilePictureResponse{} + mi := &file_helios_human_human_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateHumanProfilePictureResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateHumanProfilePictureResponse) ProtoMessage() {} + +func (x *UpdateHumanProfilePictureResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateHumanProfilePictureResponse.ProtoReflect.Descriptor instead. +func (*UpdateHumanProfilePictureResponse) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{8} +} + +type UpdateHumanDisplayNameRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HumanId string `protobuf:"bytes,1,opt,name=human_id,json=humanId,proto3" json:"human_id,omitempty"` + NewDisplayName string `protobuf:"bytes,2,opt,name=new_display_name,json=newDisplayName,proto3" json:"new_display_name,omitempty"` +} + +func (x *UpdateHumanDisplayNameRequest) Reset() { + *x = UpdateHumanDisplayNameRequest{} + mi := &file_helios_human_human_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateHumanDisplayNameRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateHumanDisplayNameRequest) ProtoMessage() {} + +func (x *UpdateHumanDisplayNameRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateHumanDisplayNameRequest.ProtoReflect.Descriptor instead. +func (*UpdateHumanDisplayNameRequest) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{9} +} + +func (x *UpdateHumanDisplayNameRequest) GetHumanId() string { + if x != nil { + return x.HumanId + } + return "" +} + +func (x *UpdateHumanDisplayNameRequest) GetNewDisplayName() string { + if x != nil { + return x.NewDisplayName + } + return "" +} + +type UpdateHumanDisplayNameResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateHumanDisplayNameResponse) Reset() { + *x = UpdateHumanDisplayNameResponse{} + mi := &file_helios_human_human_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateHumanDisplayNameResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateHumanDisplayNameResponse) ProtoMessage() {} + +func (x *UpdateHumanDisplayNameResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateHumanDisplayNameResponse.ProtoReflect.Descriptor instead. +func (*UpdateHumanDisplayNameResponse) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{10} +} + +type ListHumansRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListHumansRequest) Reset() { + *x = ListHumansRequest{} + mi := &file_helios_human_human_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListHumansRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListHumansRequest) ProtoMessage() {} + +func (x *ListHumansRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListHumansRequest.ProtoReflect.Descriptor instead. +func (*ListHumansRequest) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{11} +} + +type ListHumansResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Humans []*Human `protobuf:"bytes,1,rep,name=humans,proto3" json:"humans,omitempty"` +} + +func (x *ListHumansResponse) Reset() { + *x = ListHumansResponse{} + mi := &file_helios_human_human_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListHumansResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListHumansResponse) ProtoMessage() {} + +func (x *ListHumansResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListHumansResponse.ProtoReflect.Descriptor instead. +func (*ListHumansResponse) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{12} +} + +func (x *ListHumansResponse) GetHumans() []*Human { + if x != nil { + return x.Humans + } + return nil +} + +type SetFlowyAdminRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HumanId string `protobuf:"bytes,1,opt,name=human_id,json=humanId,proto3" json:"human_id,omitempty"` + IsFlowyAdmin bool `protobuf:"varint,2,opt,name=is_flowy_admin,json=isFlowyAdmin,proto3" json:"is_flowy_admin,omitempty"` +} + +func (x *SetFlowyAdminRequest) Reset() { + *x = SetFlowyAdminRequest{} + mi := &file_helios_human_human_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetFlowyAdminRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetFlowyAdminRequest) ProtoMessage() {} + +func (x *SetFlowyAdminRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetFlowyAdminRequest.ProtoReflect.Descriptor instead. +func (*SetFlowyAdminRequest) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{13} +} + +func (x *SetFlowyAdminRequest) GetHumanId() string { + if x != nil { + return x.HumanId + } + return "" +} + +func (x *SetFlowyAdminRequest) GetIsFlowyAdmin() bool { + if x != nil { + return x.IsFlowyAdmin + } + return false +} + +type SetFlowyAdminResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetFlowyAdminResponse) Reset() { + *x = SetFlowyAdminResponse{} + mi := &file_helios_human_human_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetFlowyAdminResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetFlowyAdminResponse) ProtoMessage() {} + +func (x *SetFlowyAdminResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_human_human_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetFlowyAdminResponse.ProtoReflect.Descriptor instead. +func (*SetFlowyAdminResponse) Descriptor() ([]byte, []int) { + return file_helios_human_human_proto_rawDescGZIP(), []int{14} +} + +var File_helios_human_human_proto protoreflect.FileDescriptor + +var file_helios_human_human_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2f, 0x68, + 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 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, 0xdf, 0x01, 0x0a, 0x05, 0x48, 0x75, + 0x6d, 0x61, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, + 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, + 0x69, 0x73, 0x5f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x46, 0x6c, 0x6f, 0x77, 0x79, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x12, 0x37, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 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, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x41, 0x74, 0x22, 0x7a, 0x0a, 0x0f, 0x41, + 0x64, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x3d, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x48, 0x75, + 0x6d, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x68, + 0x75, 0x6d, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, + 0x05, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x22, 0x2e, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, + 0x61, 0x6e, 0x42, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x44, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, + 0x61, 0x6e, 0x42, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x29, 0x0a, 0x05, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, + 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x05, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x22, 0x25, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 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, 0x41, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x42, + 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x68, + 0x75, 0x6d, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, + 0x05, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, + 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, + 0x6d, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, + 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x17, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x6e, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x23, 0x0a, 0x21, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x64, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6d, 0x61, 0x6e, + 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x28, 0x0a, + 0x10, 0x6e, 0x65, 0x77, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x0a, 0x11, 0x4c, 0x69, 0x73, + 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x41, + 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, + 0x6d, 0x61, 0x6e, 0x2e, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x06, 0x68, 0x75, 0x6d, 0x61, 0x6e, + 0x73, 0x22, 0x57, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x79, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, 0x6d, + 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, 0x6d, + 0x61, 0x6e, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x73, 0x5f, 0x66, 0x6c, 0x6f, 0x77, 0x79, + 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, + 0x46, 0x6c, 0x6f, 0x77, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x53, 0x65, + 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x32, 0xbc, 0x05, 0x0a, 0x0c, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, + 0x12, 0x1d, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, + 0x41, 0x64, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x41, + 0x64, 0x64, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x60, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x42, 0x79, 0x45, + 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, + 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x42, 0x79, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, + 0x61, 0x6e, 0x42, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x42, + 0x79, 0x49, 0x64, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, + 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x42, 0x79, 0x49, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, + 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x42, 0x79, + 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x19, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x2e, 0x2e, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, + 0x75, 0x6d, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, + 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, + 0x75, 0x6d, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, + 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x75, 0x0a, 0x16, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x44, 0x69, 0x73, 0x70, 0x6c, + 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, + 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6d, 0x61, + 0x6e, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, + 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x44, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, + 0x73, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, + 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x46, 0x6c, 0x6f, + 0x77, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x79, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x46, 0x6c, + 0x6f, 0x77, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2f, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x3b, 0x70, 0x62, 0x68, 0x75, 0x6d, 0x61, 0x6e, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_helios_human_human_proto_rawDescOnce sync.Once + file_helios_human_human_proto_rawDescData = file_helios_human_human_proto_rawDesc +) + +func file_helios_human_human_proto_rawDescGZIP() []byte { + file_helios_human_human_proto_rawDescOnce.Do(func() { + file_helios_human_human_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_human_human_proto_rawDescData) + }) + return file_helios_human_human_proto_rawDescData +} + +var file_helios_human_human_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_helios_human_human_proto_goTypes = []any{ + (*Human)(nil), // 0: helios.human.Human + (*AddHumanRequest)(nil), // 1: helios.human.AddHumanRequest + (*AddHumanResponse)(nil), // 2: helios.human.AddHumanResponse + (*GetHumanByEmailRequest)(nil), // 3: helios.human.GetHumanByEmailRequest + (*GetHumanByEmailResponse)(nil), // 4: helios.human.GetHumanByEmailResponse + (*GetHumanByIdRequest)(nil), // 5: helios.human.GetHumanByIdRequest + (*GetHumanByIdResponse)(nil), // 6: helios.human.GetHumanByIdResponse + (*UpdateHumanProfilePictureRequest)(nil), // 7: helios.human.UpdateHumanProfilePictureRequest + (*UpdateHumanProfilePictureResponse)(nil), // 8: helios.human.UpdateHumanProfilePictureResponse + (*UpdateHumanDisplayNameRequest)(nil), // 9: helios.human.UpdateHumanDisplayNameRequest + (*UpdateHumanDisplayNameResponse)(nil), // 10: helios.human.UpdateHumanDisplayNameResponse + (*ListHumansRequest)(nil), // 11: helios.human.ListHumansRequest + (*ListHumansResponse)(nil), // 12: helios.human.ListHumansResponse + (*SetFlowyAdminRequest)(nil), // 13: helios.human.SetFlowyAdminRequest + (*SetFlowyAdminResponse)(nil), // 14: helios.human.SetFlowyAdminResponse + (*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp +} +var file_helios_human_human_proto_depIdxs = []int32{ + 15, // 0: helios.human.Human.joined_at:type_name -> google.protobuf.Timestamp + 0, // 1: helios.human.AddHumanResponse.human:type_name -> helios.human.Human + 0, // 2: helios.human.GetHumanByEmailResponse.human:type_name -> helios.human.Human + 0, // 3: helios.human.GetHumanByIdResponse.human:type_name -> helios.human.Human + 0, // 4: helios.human.ListHumansResponse.humans:type_name -> helios.human.Human + 1, // 5: helios.human.HumanService.AddHuman:input_type -> helios.human.AddHumanRequest + 3, // 6: helios.human.HumanService.GetHumanByEmail:input_type -> helios.human.GetHumanByEmailRequest + 5, // 7: helios.human.HumanService.GetHumanById:input_type -> helios.human.GetHumanByIdRequest + 7, // 8: helios.human.HumanService.UpdateHumanProfilePicture:input_type -> helios.human.UpdateHumanProfilePictureRequest + 9, // 9: helios.human.HumanService.UpdateHumanDisplayName:input_type -> helios.human.UpdateHumanDisplayNameRequest + 11, // 10: helios.human.HumanService.ListHumans:input_type -> helios.human.ListHumansRequest + 13, // 11: helios.human.HumanService.SetFlowyAdmin:input_type -> helios.human.SetFlowyAdminRequest + 2, // 12: helios.human.HumanService.AddHuman:output_type -> helios.human.AddHumanResponse + 4, // 13: helios.human.HumanService.GetHumanByEmail:output_type -> helios.human.GetHumanByEmailResponse + 6, // 14: helios.human.HumanService.GetHumanById:output_type -> helios.human.GetHumanByIdResponse + 8, // 15: helios.human.HumanService.UpdateHumanProfilePicture:output_type -> helios.human.UpdateHumanProfilePictureResponse + 10, // 16: helios.human.HumanService.UpdateHumanDisplayName:output_type -> helios.human.UpdateHumanDisplayNameResponse + 12, // 17: helios.human.HumanService.ListHumans:output_type -> helios.human.ListHumansResponse + 14, // 18: helios.human.HumanService.SetFlowyAdmin:output_type -> helios.human.SetFlowyAdminResponse + 12, // [12:19] is the sub-list for method output_type + 5, // [5:12] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_helios_human_human_proto_init() } +func file_helios_human_human_proto_init() { + if File_helios_human_human_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_human_human_proto_rawDesc, + NumEnums: 0, + NumMessages: 15, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_human_human_proto_goTypes, + DependencyIndexes: file_helios_human_human_proto_depIdxs, + MessageInfos: file_helios_human_human_proto_msgTypes, + }.Build() + File_helios_human_human_proto = out.File + file_helios_human_human_proto_rawDesc = nil + file_helios_human_human_proto_goTypes = nil + file_helios_human_human_proto_depIdxs = nil +} diff --git a/go/genproto/helios/human/human_grpc.pb.go b/go/genproto/helios/human/human_grpc.pb.go new file mode 100644 index 0000000..a3f3355 --- /dev/null +++ b/go/genproto/helios/human/human_grpc.pb.go @@ -0,0 +1,359 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/human/human.proto + +package pbhuman + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + HumanService_AddHuman_FullMethodName = "/helios.human.HumanService/AddHuman" + HumanService_GetHumanByEmail_FullMethodName = "/helios.human.HumanService/GetHumanByEmail" + HumanService_GetHumanById_FullMethodName = "/helios.human.HumanService/GetHumanById" + HumanService_UpdateHumanProfilePicture_FullMethodName = "/helios.human.HumanService/UpdateHumanProfilePicture" + HumanService_UpdateHumanDisplayName_FullMethodName = "/helios.human.HumanService/UpdateHumanDisplayName" + HumanService_ListHumans_FullMethodName = "/helios.human.HumanService/ListHumans" + HumanService_SetFlowyAdmin_FullMethodName = "/helios.human.HumanService/SetFlowyAdmin" +) + +// HumanServiceClient is the client API for HumanService 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 HumanServiceClient interface { + // Returns ALREADY_EXISTS if the human is already added. + AddHuman(ctx context.Context, in *AddHumanRequest, opts ...grpc.CallOption) (*AddHumanResponse, error) + // Returns NOT_FOUND if the human is not found. + GetHumanByEmail(ctx context.Context, in *GetHumanByEmailRequest, opts ...grpc.CallOption) (*GetHumanByEmailResponse, error) + // Returns NOT_FOUND if the human is not found. + GetHumanById(ctx context.Context, in *GetHumanByIdRequest, opts ...grpc.CallOption) (*GetHumanByIdResponse, error) + UpdateHumanProfilePicture(ctx context.Context, in *UpdateHumanProfilePictureRequest, opts ...grpc.CallOption) (*UpdateHumanProfilePictureResponse, error) + UpdateHumanDisplayName(ctx context.Context, in *UpdateHumanDisplayNameRequest, opts ...grpc.CallOption) (*UpdateHumanDisplayNameResponse, error) + // Lists all humans. + ListHumans(ctx context.Context, in *ListHumansRequest, opts ...grpc.CallOption) (*ListHumansResponse, error) + // Returns NOT_FOUND if the human is not found. + SetFlowyAdmin(ctx context.Context, in *SetFlowyAdminRequest, opts ...grpc.CallOption) (*SetFlowyAdminResponse, error) +} + +type humanServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewHumanServiceClient(cc grpc.ClientConnInterface) HumanServiceClient { + return &humanServiceClient{cc} +} + +func (c *humanServiceClient) AddHuman(ctx context.Context, in *AddHumanRequest, opts ...grpc.CallOption) (*AddHumanResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddHumanResponse) + err := c.cc.Invoke(ctx, HumanService_AddHuman_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *humanServiceClient) GetHumanByEmail(ctx context.Context, in *GetHumanByEmailRequest, opts ...grpc.CallOption) (*GetHumanByEmailResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetHumanByEmailResponse) + err := c.cc.Invoke(ctx, HumanService_GetHumanByEmail_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *humanServiceClient) GetHumanById(ctx context.Context, in *GetHumanByIdRequest, opts ...grpc.CallOption) (*GetHumanByIdResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetHumanByIdResponse) + err := c.cc.Invoke(ctx, HumanService_GetHumanById_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *humanServiceClient) UpdateHumanProfilePicture(ctx context.Context, in *UpdateHumanProfilePictureRequest, opts ...grpc.CallOption) (*UpdateHumanProfilePictureResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateHumanProfilePictureResponse) + err := c.cc.Invoke(ctx, HumanService_UpdateHumanProfilePicture_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *humanServiceClient) UpdateHumanDisplayName(ctx context.Context, in *UpdateHumanDisplayNameRequest, opts ...grpc.CallOption) (*UpdateHumanDisplayNameResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateHumanDisplayNameResponse) + err := c.cc.Invoke(ctx, HumanService_UpdateHumanDisplayName_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *humanServiceClient) ListHumans(ctx context.Context, in *ListHumansRequest, opts ...grpc.CallOption) (*ListHumansResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListHumansResponse) + err := c.cc.Invoke(ctx, HumanService_ListHumans_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *humanServiceClient) SetFlowyAdmin(ctx context.Context, in *SetFlowyAdminRequest, opts ...grpc.CallOption) (*SetFlowyAdminResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetFlowyAdminResponse) + err := c.cc.Invoke(ctx, HumanService_SetFlowyAdmin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// HumanServiceServer is the server API for HumanService service. +// All implementations must embed UnimplementedHumanServiceServer +// for forward compatibility. +type HumanServiceServer interface { + // Returns ALREADY_EXISTS if the human is already added. + AddHuman(context.Context, *AddHumanRequest) (*AddHumanResponse, error) + // Returns NOT_FOUND if the human is not found. + GetHumanByEmail(context.Context, *GetHumanByEmailRequest) (*GetHumanByEmailResponse, error) + // Returns NOT_FOUND if the human is not found. + GetHumanById(context.Context, *GetHumanByIdRequest) (*GetHumanByIdResponse, error) + UpdateHumanProfilePicture(context.Context, *UpdateHumanProfilePictureRequest) (*UpdateHumanProfilePictureResponse, error) + UpdateHumanDisplayName(context.Context, *UpdateHumanDisplayNameRequest) (*UpdateHumanDisplayNameResponse, error) + // Lists all humans. + ListHumans(context.Context, *ListHumansRequest) (*ListHumansResponse, error) + // Returns NOT_FOUND if the human is not found. + SetFlowyAdmin(context.Context, *SetFlowyAdminRequest) (*SetFlowyAdminResponse, error) + mustEmbedUnimplementedHumanServiceServer() +} + +// UnimplementedHumanServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHumanServiceServer struct{} + +func (UnimplementedHumanServiceServer) AddHuman(context.Context, *AddHumanRequest) (*AddHumanResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddHuman not implemented") +} +func (UnimplementedHumanServiceServer) GetHumanByEmail(context.Context, *GetHumanByEmailRequest) (*GetHumanByEmailResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetHumanByEmail not implemented") +} +func (UnimplementedHumanServiceServer) GetHumanById(context.Context, *GetHumanByIdRequest) (*GetHumanByIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetHumanById not implemented") +} +func (UnimplementedHumanServiceServer) UpdateHumanProfilePicture(context.Context, *UpdateHumanProfilePictureRequest) (*UpdateHumanProfilePictureResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateHumanProfilePicture not implemented") +} +func (UnimplementedHumanServiceServer) UpdateHumanDisplayName(context.Context, *UpdateHumanDisplayNameRequest) (*UpdateHumanDisplayNameResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateHumanDisplayName not implemented") +} +func (UnimplementedHumanServiceServer) ListHumans(context.Context, *ListHumansRequest) (*ListHumansResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListHumans not implemented") +} +func (UnimplementedHumanServiceServer) SetFlowyAdmin(context.Context, *SetFlowyAdminRequest) (*SetFlowyAdminResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetFlowyAdmin not implemented") +} +func (UnimplementedHumanServiceServer) mustEmbedUnimplementedHumanServiceServer() {} +func (UnimplementedHumanServiceServer) testEmbeddedByValue() {} + +// UnsafeHumanServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to HumanServiceServer will +// result in compilation errors. +type UnsafeHumanServiceServer interface { + mustEmbedUnimplementedHumanServiceServer() +} + +func RegisterHumanServiceServer(s grpc.ServiceRegistrar, srv HumanServiceServer) { + // If the following call pancis, it indicates UnimplementedHumanServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&HumanService_ServiceDesc, srv) +} + +func _HumanService_AddHuman_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddHumanRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HumanServiceServer).AddHuman(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HumanService_AddHuman_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HumanServiceServer).AddHuman(ctx, req.(*AddHumanRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _HumanService_GetHumanByEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetHumanByEmailRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HumanServiceServer).GetHumanByEmail(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HumanService_GetHumanByEmail_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HumanServiceServer).GetHumanByEmail(ctx, req.(*GetHumanByEmailRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _HumanService_GetHumanById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetHumanByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HumanServiceServer).GetHumanById(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HumanService_GetHumanById_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HumanServiceServer).GetHumanById(ctx, req.(*GetHumanByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _HumanService_UpdateHumanProfilePicture_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateHumanProfilePictureRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HumanServiceServer).UpdateHumanProfilePicture(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HumanService_UpdateHumanProfilePicture_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HumanServiceServer).UpdateHumanProfilePicture(ctx, req.(*UpdateHumanProfilePictureRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _HumanService_UpdateHumanDisplayName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateHumanDisplayNameRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HumanServiceServer).UpdateHumanDisplayName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HumanService_UpdateHumanDisplayName_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HumanServiceServer).UpdateHumanDisplayName(ctx, req.(*UpdateHumanDisplayNameRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _HumanService_ListHumans_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListHumansRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HumanServiceServer).ListHumans(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HumanService_ListHumans_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HumanServiceServer).ListHumans(ctx, req.(*ListHumansRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _HumanService_SetFlowyAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetFlowyAdminRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HumanServiceServer).SetFlowyAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HumanService_SetFlowyAdmin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HumanServiceServer).SetFlowyAdmin(ctx, req.(*SetFlowyAdminRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// HumanService_ServiceDesc is the grpc.ServiceDesc for HumanService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var HumanService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.human.HumanService", + HandlerType: (*HumanServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddHuman", + Handler: _HumanService_AddHuman_Handler, + }, + { + MethodName: "GetHumanByEmail", + Handler: _HumanService_GetHumanByEmail_Handler, + }, + { + MethodName: "GetHumanById", + Handler: _HumanService_GetHumanById_Handler, + }, + { + MethodName: "UpdateHumanProfilePicture", + Handler: _HumanService_UpdateHumanProfilePicture_Handler, + }, + { + MethodName: "UpdateHumanDisplayName", + Handler: _HumanService_UpdateHumanDisplayName_Handler, + }, + { + MethodName: "ListHumans", + Handler: _HumanService_ListHumans_Handler, + }, + { + MethodName: "SetFlowyAdmin", + Handler: _HumanService_SetFlowyAdmin_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/human/human.proto", +} diff --git a/go/genproto/helios/intelligence/intelligence.pb.go b/go/genproto/helios/intelligence/intelligence.pb.go new file mode 100644 index 0000000..f0732e2 --- /dev/null +++ b/go/genproto/helios/intelligence/intelligence.pb.go @@ -0,0 +1,196 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/intelligence/intelligence.proto + +package pbintelligence + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + _ "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 GeneralQuestionRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Question string `protobuf:"bytes,1,opt,name=question,proto3" json:"question,omitempty"` +} + +func (x *GeneralQuestionRequest) Reset() { + *x = GeneralQuestionRequest{} + mi := &file_helios_intelligence_intelligence_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeneralQuestionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeneralQuestionRequest) ProtoMessage() {} + +func (x *GeneralQuestionRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_intelligence_intelligence_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeneralQuestionRequest.ProtoReflect.Descriptor instead. +func (*GeneralQuestionRequest) Descriptor() ([]byte, []int) { + return file_helios_intelligence_intelligence_proto_rawDescGZIP(), []int{0} +} + +func (x *GeneralQuestionRequest) GetQuestion() string { + if x != nil { + return x.Question + } + return "" +} + +type GeneralQuestionResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Answer string `protobuf:"bytes,1,opt,name=answer,proto3" json:"answer,omitempty"` +} + +func (x *GeneralQuestionResponse) Reset() { + *x = GeneralQuestionResponse{} + mi := &file_helios_intelligence_intelligence_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeneralQuestionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeneralQuestionResponse) ProtoMessage() {} + +func (x *GeneralQuestionResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_intelligence_intelligence_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeneralQuestionResponse.ProtoReflect.Descriptor instead. +func (*GeneralQuestionResponse) Descriptor() ([]byte, []int) { + return file_helios_intelligence_intelligence_proto_rawDescGZIP(), []int{1} +} + +func (x *GeneralQuestionResponse) GetAnswer() string { + if x != nil { + return x.Answer + } + return "" +} + +var File_helios_intelligence_intelligence_proto protoreflect.FileDescriptor + +var file_helios_intelligence_intelligence_proto_rawDesc = []byte{ + 0x0a, 0x26, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x6c, 0x69, + 0x67, 0x65, 0x6e, 0x63, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, + 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x63, 0x65, 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, 0x34, + 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x31, 0x0a, 0x17, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x51, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x61, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x32, 0x83, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x74, 0x65, + 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x6c, 0x0a, 0x0f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, + 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2c, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x6c, 0x69, + 0x67, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x51, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4a, 0x5a, + 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, + 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x67, 0x65, + 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x3b, 0x70, 0x62, 0x69, 0x6e, 0x74, + 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_helios_intelligence_intelligence_proto_rawDescOnce sync.Once + file_helios_intelligence_intelligence_proto_rawDescData = file_helios_intelligence_intelligence_proto_rawDesc +) + +func file_helios_intelligence_intelligence_proto_rawDescGZIP() []byte { + file_helios_intelligence_intelligence_proto_rawDescOnce.Do(func() { + file_helios_intelligence_intelligence_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_intelligence_intelligence_proto_rawDescData) + }) + return file_helios_intelligence_intelligence_proto_rawDescData +} + +var file_helios_intelligence_intelligence_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_helios_intelligence_intelligence_proto_goTypes = []any{ + (*GeneralQuestionRequest)(nil), // 0: helios.intelligence.GeneralQuestionRequest + (*GeneralQuestionResponse)(nil), // 1: helios.intelligence.GeneralQuestionResponse +} +var file_helios_intelligence_intelligence_proto_depIdxs = []int32{ + 0, // 0: helios.intelligence.IntelligenceService.GeneralQuestion:input_type -> helios.intelligence.GeneralQuestionRequest + 1, // 1: helios.intelligence.IntelligenceService.GeneralQuestion:output_type -> helios.intelligence.GeneralQuestionResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_helios_intelligence_intelligence_proto_init() } +func file_helios_intelligence_intelligence_proto_init() { + if File_helios_intelligence_intelligence_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_intelligence_intelligence_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_intelligence_intelligence_proto_goTypes, + DependencyIndexes: file_helios_intelligence_intelligence_proto_depIdxs, + MessageInfos: file_helios_intelligence_intelligence_proto_msgTypes, + }.Build() + File_helios_intelligence_intelligence_proto = out.File + file_helios_intelligence_intelligence_proto_rawDesc = nil + file_helios_intelligence_intelligence_proto_goTypes = nil + file_helios_intelligence_intelligence_proto_depIdxs = nil +} diff --git a/go/genproto/helios/intelligence/intelligence_grpc.pb.go b/go/genproto/helios/intelligence/intelligence_grpc.pb.go new file mode 100644 index 0000000..ba03816 --- /dev/null +++ b/go/genproto/helios/intelligence/intelligence_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/intelligence/intelligence.proto + +package pbintelligence + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + IntelligenceService_GeneralQuestion_FullMethodName = "/helios.intelligence.IntelligenceService/GeneralQuestion" +) + +// IntelligenceServiceClient is the client API for IntelligenceService 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 IntelligenceServiceClient interface { + GeneralQuestion(ctx context.Context, in *GeneralQuestionRequest, opts ...grpc.CallOption) (*GeneralQuestionResponse, error) +} + +type intelligenceServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewIntelligenceServiceClient(cc grpc.ClientConnInterface) IntelligenceServiceClient { + return &intelligenceServiceClient{cc} +} + +func (c *intelligenceServiceClient) GeneralQuestion(ctx context.Context, in *GeneralQuestionRequest, opts ...grpc.CallOption) (*GeneralQuestionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GeneralQuestionResponse) + err := c.cc.Invoke(ctx, IntelligenceService_GeneralQuestion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// IntelligenceServiceServer is the server API for IntelligenceService service. +// All implementations must embed UnimplementedIntelligenceServiceServer +// for forward compatibility. +type IntelligenceServiceServer interface { + GeneralQuestion(context.Context, *GeneralQuestionRequest) (*GeneralQuestionResponse, error) + mustEmbedUnimplementedIntelligenceServiceServer() +} + +// UnimplementedIntelligenceServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedIntelligenceServiceServer struct{} + +func (UnimplementedIntelligenceServiceServer) GeneralQuestion(context.Context, *GeneralQuestionRequest) (*GeneralQuestionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GeneralQuestion not implemented") +} +func (UnimplementedIntelligenceServiceServer) mustEmbedUnimplementedIntelligenceServiceServer() {} +func (UnimplementedIntelligenceServiceServer) testEmbeddedByValue() {} + +// UnsafeIntelligenceServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to IntelligenceServiceServer will +// result in compilation errors. +type UnsafeIntelligenceServiceServer interface { + mustEmbedUnimplementedIntelligenceServiceServer() +} + +func RegisterIntelligenceServiceServer(s grpc.ServiceRegistrar, srv IntelligenceServiceServer) { + // If the following call pancis, it indicates UnimplementedIntelligenceServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&IntelligenceService_ServiceDesc, srv) +} + +func _IntelligenceService_GeneralQuestion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeneralQuestionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IntelligenceServiceServer).GeneralQuestion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: IntelligenceService_GeneralQuestion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IntelligenceServiceServer).GeneralQuestion(ctx, req.(*GeneralQuestionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// IntelligenceService_ServiceDesc is the grpc.ServiceDesc for IntelligenceService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var IntelligenceService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.intelligence.IntelligenceService", + HandlerType: (*IntelligenceServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GeneralQuestion", + Handler: _IntelligenceService_GeneralQuestion_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/intelligence/intelligence.proto", +} diff --git a/go/genproto/helios/keypad/keypad.pb.go b/go/genproto/helios/keypad/keypad.pb.go new file mode 100644 index 0000000..fc9142e --- /dev/null +++ b/go/genproto/helios/keypad/keypad.pb.go @@ -0,0 +1,431 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/keypad/keypad.proto + +package pbkeypad + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 GetConfigRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetConfigRequest) Reset() { + *x = GetConfigRequest{} + mi := &file_helios_keypad_keypad_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConfigRequest) ProtoMessage() {} + +func (x *GetConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_keypad_keypad_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConfigRequest.ProtoReflect.Descriptor instead. +func (*GetConfigRequest) Descriptor() ([]byte, []int) { + return file_helios_keypad_keypad_proto_rawDescGZIP(), []int{0} +} + +type GetConfigResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + YamlConfig string `protobuf:"bytes,1,opt,name=yaml_config,json=yamlConfig,proto3" json:"yaml_config,omitempty"` +} + +func (x *GetConfigResponse) Reset() { + *x = GetConfigResponse{} + mi := &file_helios_keypad_keypad_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConfigResponse) ProtoMessage() {} + +func (x *GetConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_keypad_keypad_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConfigResponse.ProtoReflect.Descriptor instead. +func (*GetConfigResponse) Descriptor() ([]byte, []int) { + return file_helios_keypad_keypad_proto_rawDescGZIP(), []int{1} +} + +func (x *GetConfigResponse) GetYamlConfig() string { + if x != nil { + return x.YamlConfig + } + return "" +} + +type SaveConfigRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + YamlConfig string `protobuf:"bytes,1,opt,name=yaml_config,json=yamlConfig,proto3" json:"yaml_config,omitempty"` +} + +func (x *SaveConfigRequest) Reset() { + *x = SaveConfigRequest{} + mi := &file_helios_keypad_keypad_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SaveConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SaveConfigRequest) ProtoMessage() {} + +func (x *SaveConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_keypad_keypad_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SaveConfigRequest.ProtoReflect.Descriptor instead. +func (*SaveConfigRequest) Descriptor() ([]byte, []int) { + return file_helios_keypad_keypad_proto_rawDescGZIP(), []int{2} +} + +func (x *SaveConfigRequest) GetYamlConfig() string { + if x != nil { + return x.YamlConfig + } + return "" +} + +type SaveConfigResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SaveConfigResponse) Reset() { + *x = SaveConfigResponse{} + mi := &file_helios_keypad_keypad_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SaveConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SaveConfigResponse) ProtoMessage() {} + +func (x *SaveConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_keypad_keypad_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SaveConfigResponse.ProtoReflect.Descriptor instead. +func (*SaveConfigResponse) Descriptor() ([]byte, []int) { + return file_helios_keypad_keypad_proto_rawDescGZIP(), []int{3} +} + +type ListKeypadsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListKeypadsRequest) Reset() { + *x = ListKeypadsRequest{} + mi := &file_helios_keypad_keypad_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListKeypadsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListKeypadsRequest) ProtoMessage() {} + +func (x *ListKeypadsRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_keypad_keypad_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListKeypadsRequest.ProtoReflect.Descriptor instead. +func (*ListKeypadsRequest) Descriptor() ([]byte, []int) { + return file_helios_keypad_keypad_proto_rawDescGZIP(), []int{4} +} + +type ListKeypadsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HumanKeypads []*ListKeypadsResponse_HumanKeypad `protobuf:"bytes,1,rep,name=human_keypads,json=humanKeypads,proto3" json:"human_keypads,omitempty"` +} + +func (x *ListKeypadsResponse) Reset() { + *x = ListKeypadsResponse{} + mi := &file_helios_keypad_keypad_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListKeypadsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListKeypadsResponse) ProtoMessage() {} + +func (x *ListKeypadsResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_keypad_keypad_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListKeypadsResponse.ProtoReflect.Descriptor instead. +func (*ListKeypadsResponse) Descriptor() ([]byte, []int) { + return file_helios_keypad_keypad_proto_rawDescGZIP(), []int{5} +} + +func (x *ListKeypadsResponse) GetHumanKeypads() []*ListKeypadsResponse_HumanKeypad { + if x != nil { + return x.HumanKeypads + } + return nil +} + +type ListKeypadsResponse_HumanKeypad struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HumanId string `protobuf:"bytes,1,opt,name=human_id,json=humanId,proto3" json:"human_id,omitempty"` + YamlConfig string `protobuf:"bytes,2,opt,name=yaml_config,json=yamlConfig,proto3" json:"yaml_config,omitempty"` +} + +func (x *ListKeypadsResponse_HumanKeypad) Reset() { + *x = ListKeypadsResponse_HumanKeypad{} + mi := &file_helios_keypad_keypad_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListKeypadsResponse_HumanKeypad) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListKeypadsResponse_HumanKeypad) ProtoMessage() {} + +func (x *ListKeypadsResponse_HumanKeypad) ProtoReflect() protoreflect.Message { + mi := &file_helios_keypad_keypad_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListKeypadsResponse_HumanKeypad.ProtoReflect.Descriptor instead. +func (*ListKeypadsResponse_HumanKeypad) Descriptor() ([]byte, []int) { + return file_helios_keypad_keypad_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *ListKeypadsResponse_HumanKeypad) GetHumanId() string { + if x != nil { + return x.HumanId + } + return "" +} + +func (x *ListKeypadsResponse_HumanKeypad) GetYamlConfig() string { + if x != nil { + return x.YamlConfig + } + return "" +} + +var File_helios_keypad_keypad_proto protoreflect.FileDescriptor + +var file_helios_keypad_keypad_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x2f, + 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x47, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x34, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x79, 0x61, 0x6d, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x79, 0x61, 0x6d, 0x6c, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x34, 0x0a, 0x11, 0x53, 0x61, 0x76, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x79, 0x61, + 0x6d, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x79, 0x61, 0x6d, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x53, + 0x61, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb5, 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, + 0x4b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x53, 0x0a, 0x0d, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, + 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x70, 0x61, + 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x75, 0x6d, 0x61, 0x6e, + 0x4b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x52, 0x0c, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x4b, 0x65, 0x79, + 0x70, 0x61, 0x64, 0x73, 0x1a, 0x49, 0x0a, 0x0b, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x4b, 0x65, 0x79, + 0x70, 0x61, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x79, 0x61, 0x6d, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x79, 0x61, 0x6d, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, + 0x88, 0x02, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, + 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x2e, 0x47, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x2e, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x53, 0x61, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x20, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x2e, + 0x53, 0x61, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x61, + 0x64, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x70, + 0x61, 0x64, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6b, 0x65, 0x79, + 0x70, 0x61, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, + 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x70, 0x61, + 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, + 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x6b, 0x65, 0x79, 0x70, 0x61, + 0x64, 0x3b, 0x70, 0x62, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_helios_keypad_keypad_proto_rawDescOnce sync.Once + file_helios_keypad_keypad_proto_rawDescData = file_helios_keypad_keypad_proto_rawDesc +) + +func file_helios_keypad_keypad_proto_rawDescGZIP() []byte { + file_helios_keypad_keypad_proto_rawDescOnce.Do(func() { + file_helios_keypad_keypad_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_keypad_keypad_proto_rawDescData) + }) + return file_helios_keypad_keypad_proto_rawDescData +} + +var file_helios_keypad_keypad_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_helios_keypad_keypad_proto_goTypes = []any{ + (*GetConfigRequest)(nil), // 0: helios.keypad.GetConfigRequest + (*GetConfigResponse)(nil), // 1: helios.keypad.GetConfigResponse + (*SaveConfigRequest)(nil), // 2: helios.keypad.SaveConfigRequest + (*SaveConfigResponse)(nil), // 3: helios.keypad.SaveConfigResponse + (*ListKeypadsRequest)(nil), // 4: helios.keypad.ListKeypadsRequest + (*ListKeypadsResponse)(nil), // 5: helios.keypad.ListKeypadsResponse + (*ListKeypadsResponse_HumanKeypad)(nil), // 6: helios.keypad.ListKeypadsResponse.HumanKeypad +} +var file_helios_keypad_keypad_proto_depIdxs = []int32{ + 6, // 0: helios.keypad.ListKeypadsResponse.human_keypads:type_name -> helios.keypad.ListKeypadsResponse.HumanKeypad + 0, // 1: helios.keypad.KeypadService.GetConfig:input_type -> helios.keypad.GetConfigRequest + 2, // 2: helios.keypad.KeypadService.SaveConfig:input_type -> helios.keypad.SaveConfigRequest + 4, // 3: helios.keypad.KeypadService.ListKeypads:input_type -> helios.keypad.ListKeypadsRequest + 1, // 4: helios.keypad.KeypadService.GetConfig:output_type -> helios.keypad.GetConfigResponse + 3, // 5: helios.keypad.KeypadService.SaveConfig:output_type -> helios.keypad.SaveConfigResponse + 5, // 6: helios.keypad.KeypadService.ListKeypads:output_type -> helios.keypad.ListKeypadsResponse + 4, // [4:7] is the sub-list for method output_type + 1, // [1:4] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_helios_keypad_keypad_proto_init() } +func file_helios_keypad_keypad_proto_init() { + if File_helios_keypad_keypad_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_keypad_keypad_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_keypad_keypad_proto_goTypes, + DependencyIndexes: file_helios_keypad_keypad_proto_depIdxs, + MessageInfos: file_helios_keypad_keypad_proto_msgTypes, + }.Build() + File_helios_keypad_keypad_proto = out.File + file_helios_keypad_keypad_proto_rawDesc = nil + file_helios_keypad_keypad_proto_goTypes = nil + file_helios_keypad_keypad_proto_depIdxs = nil +} diff --git a/go/genproto/helios/keypad/keypad_grpc.pb.go b/go/genproto/helios/keypad/keypad_grpc.pb.go new file mode 100644 index 0000000..4739791 --- /dev/null +++ b/go/genproto/helios/keypad/keypad_grpc.pb.go @@ -0,0 +1,203 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/keypad/keypad.proto + +package pbkeypad + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + KeypadService_GetConfig_FullMethodName = "/helios.keypad.KeypadService/GetConfig" + KeypadService_SaveConfig_FullMethodName = "/helios.keypad.KeypadService/SaveConfig" + KeypadService_ListKeypads_FullMethodName = "/helios.keypad.KeypadService/ListKeypads" +) + +// KeypadServiceClient is the client API for KeypadService 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 KeypadServiceClient interface { + // Requires authed human. + GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error) + // Requires authed human. + SaveConfig(ctx context.Context, in *SaveConfigRequest, opts ...grpc.CallOption) (*SaveConfigResponse, error) + // Requires admin. + ListKeypads(ctx context.Context, in *ListKeypadsRequest, opts ...grpc.CallOption) (*ListKeypadsResponse, error) +} + +type keypadServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewKeypadServiceClient(cc grpc.ClientConnInterface) KeypadServiceClient { + return &keypadServiceClient{cc} +} + +func (c *keypadServiceClient) GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetConfigResponse) + err := c.cc.Invoke(ctx, KeypadService_GetConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keypadServiceClient) SaveConfig(ctx context.Context, in *SaveConfigRequest, opts ...grpc.CallOption) (*SaveConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SaveConfigResponse) + err := c.cc.Invoke(ctx, KeypadService_SaveConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keypadServiceClient) ListKeypads(ctx context.Context, in *ListKeypadsRequest, opts ...grpc.CallOption) (*ListKeypadsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListKeypadsResponse) + err := c.cc.Invoke(ctx, KeypadService_ListKeypads_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// KeypadServiceServer is the server API for KeypadService service. +// All implementations must embed UnimplementedKeypadServiceServer +// for forward compatibility. +type KeypadServiceServer interface { + // Requires authed human. + GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) + // Requires authed human. + SaveConfig(context.Context, *SaveConfigRequest) (*SaveConfigResponse, error) + // Requires admin. + ListKeypads(context.Context, *ListKeypadsRequest) (*ListKeypadsResponse, error) + mustEmbedUnimplementedKeypadServiceServer() +} + +// UnimplementedKeypadServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedKeypadServiceServer struct{} + +func (UnimplementedKeypadServiceServer) GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetConfig not implemented") +} +func (UnimplementedKeypadServiceServer) SaveConfig(context.Context, *SaveConfigRequest) (*SaveConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SaveConfig not implemented") +} +func (UnimplementedKeypadServiceServer) ListKeypads(context.Context, *ListKeypadsRequest) (*ListKeypadsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListKeypads not implemented") +} +func (UnimplementedKeypadServiceServer) mustEmbedUnimplementedKeypadServiceServer() {} +func (UnimplementedKeypadServiceServer) testEmbeddedByValue() {} + +// UnsafeKeypadServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to KeypadServiceServer will +// result in compilation errors. +type UnsafeKeypadServiceServer interface { + mustEmbedUnimplementedKeypadServiceServer() +} + +func RegisterKeypadServiceServer(s grpc.ServiceRegistrar, srv KeypadServiceServer) { + // If the following call pancis, it indicates UnimplementedKeypadServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&KeypadService_ServiceDesc, srv) +} + +func _KeypadService_GetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeypadServiceServer).GetConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: KeypadService_GetConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeypadServiceServer).GetConfig(ctx, req.(*GetConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeypadService_SaveConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SaveConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeypadServiceServer).SaveConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: KeypadService_SaveConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeypadServiceServer).SaveConfig(ctx, req.(*SaveConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeypadService_ListKeypads_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListKeypadsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeypadServiceServer).ListKeypads(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: KeypadService_ListKeypads_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeypadServiceServer).ListKeypads(ctx, req.(*ListKeypadsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// KeypadService_ServiceDesc is the grpc.ServiceDesc for KeypadService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var KeypadService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.keypad.KeypadService", + HandlerType: (*KeypadServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetConfig", + Handler: _KeypadService_GetConfig_Handler, + }, + { + MethodName: "SaveConfig", + Handler: _KeypadService_SaveConfig_Handler, + }, + { + MethodName: "ListKeypads", + Handler: _KeypadService_ListKeypads_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/keypad/keypad.proto", +} diff --git a/go/genproto/helios/messenger/messenger.pb.go b/go/genproto/helios/messenger/messenger.pb.go new file mode 100644 index 0000000..c09f32e --- /dev/null +++ b/go/genproto/helios/messenger/messenger.pb.go @@ -0,0 +1,715 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/messenger/messenger.proto + +package pbmessenger + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 ClientStateUpdate_UpdateType int32 + +const ( + ClientStateUpdate_UPDATE_TYPE_UNSPECIFIED ClientStateUpdate_UpdateType = 0 + ClientStateUpdate_UPDATE_TYPE_CLIENT_CONNECTED ClientStateUpdate_UpdateType = 1 + ClientStateUpdate_UPDATE_TYPE_CLIENT_DISCONNECTED ClientStateUpdate_UpdateType = 2 +) + +// Enum value maps for ClientStateUpdate_UpdateType. +var ( + ClientStateUpdate_UpdateType_name = map[int32]string{ + 0: "UPDATE_TYPE_UNSPECIFIED", + 1: "UPDATE_TYPE_CLIENT_CONNECTED", + 2: "UPDATE_TYPE_CLIENT_DISCONNECTED", + } + ClientStateUpdate_UpdateType_value = map[string]int32{ + "UPDATE_TYPE_UNSPECIFIED": 0, + "UPDATE_TYPE_CLIENT_CONNECTED": 1, + "UPDATE_TYPE_CLIENT_DISCONNECTED": 2, + } +) + +func (x ClientStateUpdate_UpdateType) Enum() *ClientStateUpdate_UpdateType { + p := new(ClientStateUpdate_UpdateType) + *p = x + return p +} + +func (x ClientStateUpdate_UpdateType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClientStateUpdate_UpdateType) Descriptor() protoreflect.EnumDescriptor { + return file_helios_messenger_messenger_proto_enumTypes[0].Descriptor() +} + +func (ClientStateUpdate_UpdateType) Type() protoreflect.EnumType { + return &file_helios_messenger_messenger_proto_enumTypes[0] +} + +func (x ClientStateUpdate_UpdateType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClientStateUpdate_UpdateType.Descriptor instead. +func (ClientStateUpdate_UpdateType) EnumDescriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{3, 0} +} + +type ClientInfo_ClientType int32 + +const ( + ClientInfo_CLIENT_TYPE_UNSPECIFIED ClientInfo_ClientType = 0 + ClientInfo_CLIENT_TYPE_KEYPAD ClientInfo_ClientType = 1 + ClientInfo_CLIENT_TYPE_DAEMON ClientInfo_ClientType = 2 +) + +// Enum value maps for ClientInfo_ClientType. +var ( + ClientInfo_ClientType_name = map[int32]string{ + 0: "CLIENT_TYPE_UNSPECIFIED", + 1: "CLIENT_TYPE_KEYPAD", + 2: "CLIENT_TYPE_DAEMON", + } + ClientInfo_ClientType_value = map[string]int32{ + "CLIENT_TYPE_UNSPECIFIED": 0, + "CLIENT_TYPE_KEYPAD": 1, + "CLIENT_TYPE_DAEMON": 2, + } +) + +func (x ClientInfo_ClientType) Enum() *ClientInfo_ClientType { + p := new(ClientInfo_ClientType) + *p = x + return p +} + +func (x ClientInfo_ClientType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClientInfo_ClientType) Descriptor() protoreflect.EnumDescriptor { + return file_helios_messenger_messenger_proto_enumTypes[1].Descriptor() +} + +func (ClientInfo_ClientType) Type() protoreflect.EnumType { + return &file_helios_messenger_messenger_proto_enumTypes[1] +} + +func (x ClientInfo_ClientType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClientInfo_ClientType.Descriptor instead. +func (ClientInfo_ClientType) EnumDescriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{4, 0} +} + +type OutboundMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageId string `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` + ToHostname string `protobuf:"bytes,2,opt,name=to_hostname,json=toHostname,proto3" json:"to_hostname,omitempty"` + // For heartbeats, should send "heartbeat". This keeps the connection alive. + Payload string `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *OutboundMessage) Reset() { + *x = OutboundMessage{} + mi := &file_helios_messenger_messenger_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OutboundMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OutboundMessage) ProtoMessage() {} + +func (x *OutboundMessage) ProtoReflect() protoreflect.Message { + mi := &file_helios_messenger_messenger_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OutboundMessage.ProtoReflect.Descriptor instead. +func (*OutboundMessage) Descriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{0} +} + +func (x *OutboundMessage) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +func (x *OutboundMessage) GetToHostname() string { + if x != nil { + return x.ToHostname + } + return "" +} + +func (x *OutboundMessage) GetPayload() string { + if x != nil { + return x.Payload + } + return "" +} + +type Message struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageId string `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` + ToHostname string `protobuf:"bytes,2,opt,name=to_hostname,json=toHostname,proto3" json:"to_hostname,omitempty"` + FromHostname string `protobuf:"bytes,3,opt,name=from_hostname,json=fromHostname,proto3" json:"from_hostname,omitempty"` + Payload string `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *Message) Reset() { + *x = Message{} + mi := &file_helios_messenger_messenger_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message) ProtoMessage() {} + +func (x *Message) ProtoReflect() protoreflect.Message { + mi := &file_helios_messenger_messenger_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message.ProtoReflect.Descriptor instead. +func (*Message) Descriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{1} +} + +func (x *Message) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +func (x *Message) GetToHostname() string { + if x != nil { + return x.ToHostname + } + return "" +} + +func (x *Message) GetFromHostname() string { + if x != nil { + return x.FromHostname + } + return "" +} + +func (x *Message) GetPayload() string { + if x != nil { + return x.Payload + } + return "" +} + +type InboundMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Data: + // + // *InboundMessage_ClientMessage + // *InboundMessage_Error + // *InboundMessage_ClientUpdate + Data isInboundMessage_Data `protobuf_oneof:"data"` +} + +func (x *InboundMessage) Reset() { + *x = InboundMessage{} + mi := &file_helios_messenger_messenger_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InboundMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InboundMessage) ProtoMessage() {} + +func (x *InboundMessage) ProtoReflect() protoreflect.Message { + mi := &file_helios_messenger_messenger_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InboundMessage.ProtoReflect.Descriptor instead. +func (*InboundMessage) Descriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{2} +} + +func (m *InboundMessage) GetData() isInboundMessage_Data { + if m != nil { + return m.Data + } + return nil +} + +func (x *InboundMessage) GetClientMessage() *Message { + if x, ok := x.GetData().(*InboundMessage_ClientMessage); ok { + return x.ClientMessage + } + return nil +} + +func (x *InboundMessage) GetError() string { + if x, ok := x.GetData().(*InboundMessage_Error); ok { + return x.Error + } + return "" +} + +func (x *InboundMessage) GetClientUpdate() *ClientStateUpdate { + if x, ok := x.GetData().(*InboundMessage_ClientUpdate); ok { + return x.ClientUpdate + } + return nil +} + +type isInboundMessage_Data interface { + isInboundMessage_Data() +} + +type InboundMessage_ClientMessage struct { + ClientMessage *Message `protobuf:"bytes,1,opt,name=client_message,json=clientMessage,proto3,oneof"` +} + +type InboundMessage_Error struct { + Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"` +} + +type InboundMessage_ClientUpdate struct { + ClientUpdate *ClientStateUpdate `protobuf:"bytes,3,opt,name=client_update,json=clientUpdate,proto3,oneof"` +} + +func (*InboundMessage_ClientMessage) isInboundMessage_Data() {} + +func (*InboundMessage_Error) isInboundMessage_Data() {} + +func (*InboundMessage_ClientUpdate) isInboundMessage_Data() {} + +type ClientStateUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type ClientStateUpdate_UpdateType `protobuf:"varint,1,opt,name=type,proto3,enum=helios.messenger.ClientStateUpdate_UpdateType" json:"type,omitempty"` + Client *ClientInfo `protobuf:"bytes,2,opt,name=client,proto3" json:"client,omitempty"` + AllClients []*ClientInfo `protobuf:"bytes,3,rep,name=all_clients,json=allClients,proto3" json:"all_clients,omitempty"` +} + +func (x *ClientStateUpdate) Reset() { + *x = ClientStateUpdate{} + mi := &file_helios_messenger_messenger_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClientStateUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClientStateUpdate) ProtoMessage() {} + +func (x *ClientStateUpdate) ProtoReflect() protoreflect.Message { + mi := &file_helios_messenger_messenger_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClientStateUpdate.ProtoReflect.Descriptor instead. +func (*ClientStateUpdate) Descriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{3} +} + +func (x *ClientStateUpdate) GetType() ClientStateUpdate_UpdateType { + if x != nil { + return x.Type + } + return ClientStateUpdate_UPDATE_TYPE_UNSPECIFIED +} + +func (x *ClientStateUpdate) GetClient() *ClientInfo { + if x != nil { + return x.Client + } + return nil +} + +func (x *ClientStateUpdate) GetAllClients() []*ClientInfo { + if x != nil { + return x.AllClients + } + return nil +} + +type ClientInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type ClientInfo_ClientType `protobuf:"varint,1,opt,name=type,proto3,enum=helios.messenger.ClientInfo_ClientType" json:"type,omitempty"` + Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"` + ConnectedAt int64 `protobuf:"varint,3,opt,name=connected_at,json=connectedAt,proto3" json:"connected_at,omitempty"` +} + +func (x *ClientInfo) Reset() { + *x = ClientInfo{} + mi := &file_helios_messenger_messenger_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClientInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClientInfo) ProtoMessage() {} + +func (x *ClientInfo) ProtoReflect() protoreflect.Message { + mi := &file_helios_messenger_messenger_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClientInfo.ProtoReflect.Descriptor instead. +func (*ClientInfo) Descriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{4} +} + +func (x *ClientInfo) GetType() ClientInfo_ClientType { + if x != nil { + return x.Type + } + return ClientInfo_CLIENT_TYPE_UNSPECIFIED +} + +func (x *ClientInfo) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +func (x *ClientInfo) GetConnectedAt() int64 { + if x != nil { + return x.ConnectedAt + } + return 0 +} + +type ListClientsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListClientsRequest) Reset() { + *x = ListClientsRequest{} + mi := &file_helios_messenger_messenger_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListClientsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListClientsRequest) ProtoMessage() {} + +func (x *ListClientsRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_messenger_messenger_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListClientsRequest.ProtoReflect.Descriptor instead. +func (*ListClientsRequest) Descriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{5} +} + +type ListClientsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Clients []*ClientInfo `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"` +} + +func (x *ListClientsResponse) Reset() { + *x = ListClientsResponse{} + mi := &file_helios_messenger_messenger_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListClientsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListClientsResponse) ProtoMessage() {} + +func (x *ListClientsResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_messenger_messenger_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListClientsResponse.ProtoReflect.Descriptor instead. +func (*ListClientsResponse) Descriptor() ([]byte, []int) { + return file_helios_messenger_messenger_proto_rawDescGZIP(), []int{6} +} + +func (x *ListClientsResponse) GetClients() []*ClientInfo { + if x != nil { + return x.Clients + } + return nil +} + +var File_helios_messenger_messenger_proto protoreflect.FileDescriptor + +var file_helios_messenger_messenger_proto_rawDesc = []byte{ + 0x0a, 0x20, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, + 0x65, 0x72, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x10, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x65, + 0x6e, 0x67, 0x65, 0x72, 0x22, 0x6b, 0x0a, 0x0f, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x5f, 0x68, 0x6f, 0x73, + 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x48, + 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x22, 0x88, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, + 0x74, 0x6f, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xc0, 0x01, 0x0a, + 0x0e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x42, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4a, 0x0a, 0x0d, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, + 0xbe, 0x02, 0x0a, 0x11, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x42, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, + 0x3d, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x70, + 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, + 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x55, + 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, + 0x54, 0x5f, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, + 0x22, 0xe3, 0x01, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x59, 0x0a, 0x0a, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4c, 0x49, + 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x50, 0x41, 0x44, 0x10, 0x01, 0x12, 0x16, + 0x0a, 0x12, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, + 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x02, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x13, + 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x32, 0xc1, 0x01, 0x0a, 0x10, + 0x4d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x51, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x4f, 0x75, + 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, + 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, + 0x01, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x44, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, + 0x6f, 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, + 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, + 0x6d, 0x65, 0x73, 0x73, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x3b, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x73, + 0x65, 0x6e, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_helios_messenger_messenger_proto_rawDescOnce sync.Once + file_helios_messenger_messenger_proto_rawDescData = file_helios_messenger_messenger_proto_rawDesc +) + +func file_helios_messenger_messenger_proto_rawDescGZIP() []byte { + file_helios_messenger_messenger_proto_rawDescOnce.Do(func() { + file_helios_messenger_messenger_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_messenger_messenger_proto_rawDescData) + }) + return file_helios_messenger_messenger_proto_rawDescData +} + +var file_helios_messenger_messenger_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_helios_messenger_messenger_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_helios_messenger_messenger_proto_goTypes = []any{ + (ClientStateUpdate_UpdateType)(0), // 0: helios.messenger.ClientStateUpdate.UpdateType + (ClientInfo_ClientType)(0), // 1: helios.messenger.ClientInfo.ClientType + (*OutboundMessage)(nil), // 2: helios.messenger.OutboundMessage + (*Message)(nil), // 3: helios.messenger.Message + (*InboundMessage)(nil), // 4: helios.messenger.InboundMessage + (*ClientStateUpdate)(nil), // 5: helios.messenger.ClientStateUpdate + (*ClientInfo)(nil), // 6: helios.messenger.ClientInfo + (*ListClientsRequest)(nil), // 7: helios.messenger.ListClientsRequest + (*ListClientsResponse)(nil), // 8: helios.messenger.ListClientsResponse +} +var file_helios_messenger_messenger_proto_depIdxs = []int32{ + 3, // 0: helios.messenger.InboundMessage.client_message:type_name -> helios.messenger.Message + 5, // 1: helios.messenger.InboundMessage.client_update:type_name -> helios.messenger.ClientStateUpdate + 0, // 2: helios.messenger.ClientStateUpdate.type:type_name -> helios.messenger.ClientStateUpdate.UpdateType + 6, // 3: helios.messenger.ClientStateUpdate.client:type_name -> helios.messenger.ClientInfo + 6, // 4: helios.messenger.ClientStateUpdate.all_clients:type_name -> helios.messenger.ClientInfo + 1, // 5: helios.messenger.ClientInfo.type:type_name -> helios.messenger.ClientInfo.ClientType + 6, // 6: helios.messenger.ListClientsResponse.clients:type_name -> helios.messenger.ClientInfo + 2, // 7: helios.messenger.MessengerService.Stream:input_type -> helios.messenger.OutboundMessage + 7, // 8: helios.messenger.MessengerService.ListClients:input_type -> helios.messenger.ListClientsRequest + 4, // 9: helios.messenger.MessengerService.Stream:output_type -> helios.messenger.InboundMessage + 8, // 10: helios.messenger.MessengerService.ListClients:output_type -> helios.messenger.ListClientsResponse + 9, // [9:11] is the sub-list for method output_type + 7, // [7:9] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_helios_messenger_messenger_proto_init() } +func file_helios_messenger_messenger_proto_init() { + if File_helios_messenger_messenger_proto != nil { + return + } + file_helios_messenger_messenger_proto_msgTypes[2].OneofWrappers = []any{ + (*InboundMessage_ClientMessage)(nil), + (*InboundMessage_Error)(nil), + (*InboundMessage_ClientUpdate)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_messenger_messenger_proto_rawDesc, + NumEnums: 2, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_messenger_messenger_proto_goTypes, + DependencyIndexes: file_helios_messenger_messenger_proto_depIdxs, + EnumInfos: file_helios_messenger_messenger_proto_enumTypes, + MessageInfos: file_helios_messenger_messenger_proto_msgTypes, + }.Build() + File_helios_messenger_messenger_proto = out.File + file_helios_messenger_messenger_proto_rawDesc = nil + file_helios_messenger_messenger_proto_goTypes = nil + file_helios_messenger_messenger_proto_depIdxs = nil +} diff --git a/go/genproto/helios/messenger/messenger_grpc.pb.go b/go/genproto/helios/messenger/messenger_grpc.pb.go new file mode 100644 index 0000000..cc505be --- /dev/null +++ b/go/genproto/helios/messenger/messenger_grpc.pb.go @@ -0,0 +1,164 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/messenger/messenger.proto + +package pbmessenger + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + MessengerService_Stream_FullMethodName = "/helios.messenger.MessengerService/Stream" + MessengerService_ListClients_FullMethodName = "/helios.messenger.MessengerService/ListClients" +) + +// MessengerServiceClient is the client API for MessengerService 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. +// +// Helios' messenger service serves as a dumb 'pipe' for communication between clients of the same account +type MessengerServiceClient interface { + // Note: must set hostname & authorization (session_id) headers + // Send heartbeats to keep connection alive. + // Also make sure to have reconnect logic as helios deployments does zero-downtime deploys, but still terminates old pods. + Stream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[OutboundMessage, InboundMessage], error) + ListClients(ctx context.Context, in *ListClientsRequest, opts ...grpc.CallOption) (*ListClientsResponse, error) +} + +type messengerServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewMessengerServiceClient(cc grpc.ClientConnInterface) MessengerServiceClient { + return &messengerServiceClient{cc} +} + +func (c *messengerServiceClient) Stream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[OutboundMessage, InboundMessage], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &MessengerService_ServiceDesc.Streams[0], MessengerService_Stream_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[OutboundMessage, InboundMessage]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type MessengerService_StreamClient = grpc.BidiStreamingClient[OutboundMessage, InboundMessage] + +func (c *messengerServiceClient) ListClients(ctx context.Context, in *ListClientsRequest, opts ...grpc.CallOption) (*ListClientsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListClientsResponse) + err := c.cc.Invoke(ctx, MessengerService_ListClients_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MessengerServiceServer is the server API for MessengerService service. +// All implementations must embed UnimplementedMessengerServiceServer +// for forward compatibility. +// +// Helios' messenger service serves as a dumb 'pipe' for communication between clients of the same account +type MessengerServiceServer interface { + // Note: must set hostname & authorization (session_id) headers + // Send heartbeats to keep connection alive. + // Also make sure to have reconnect logic as helios deployments does zero-downtime deploys, but still terminates old pods. + Stream(grpc.BidiStreamingServer[OutboundMessage, InboundMessage]) error + ListClients(context.Context, *ListClientsRequest) (*ListClientsResponse, error) + mustEmbedUnimplementedMessengerServiceServer() +} + +// UnimplementedMessengerServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedMessengerServiceServer struct{} + +func (UnimplementedMessengerServiceServer) Stream(grpc.BidiStreamingServer[OutboundMessage, InboundMessage]) error { + return status.Errorf(codes.Unimplemented, "method Stream not implemented") +} +func (UnimplementedMessengerServiceServer) ListClients(context.Context, *ListClientsRequest) (*ListClientsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListClients not implemented") +} +func (UnimplementedMessengerServiceServer) mustEmbedUnimplementedMessengerServiceServer() {} +func (UnimplementedMessengerServiceServer) testEmbeddedByValue() {} + +// UnsafeMessengerServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MessengerServiceServer will +// result in compilation errors. +type UnsafeMessengerServiceServer interface { + mustEmbedUnimplementedMessengerServiceServer() +} + +func RegisterMessengerServiceServer(s grpc.ServiceRegistrar, srv MessengerServiceServer) { + // If the following call pancis, it indicates UnimplementedMessengerServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&MessengerService_ServiceDesc, srv) +} + +func _MessengerService_Stream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(MessengerServiceServer).Stream(&grpc.GenericServerStream[OutboundMessage, InboundMessage]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type MessengerService_StreamServer = grpc.BidiStreamingServer[OutboundMessage, InboundMessage] + +func _MessengerService_ListClients_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListClientsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessengerServiceServer).ListClients(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessengerService_ListClients_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessengerServiceServer).ListClients(ctx, req.(*ListClientsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// MessengerService_ServiceDesc is the grpc.ServiceDesc for MessengerService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var MessengerService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.messenger.MessengerService", + HandlerType: (*MessengerServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListClients", + Handler: _MessengerService_ListClients_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Stream", + Handler: _MessengerService_Stream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "helios/messenger/messenger.proto", +} diff --git a/go/genproto/helios/speech/speech.pb.go b/go/genproto/helios/speech/speech.pb.go new file mode 100644 index 0000000..c8fbf9e --- /dev/null +++ b/go/genproto/helios/speech/speech.pb.go @@ -0,0 +1,349 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/speech/speech.proto + +package pbspeech + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 GetUploadUrlRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContentType string `protobuf:"bytes,1,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + ContentLength int64 `protobuf:"varint,2,opt,name=content_length,json=contentLength,proto3" json:"content_length,omitempty"` +} + +func (x *GetUploadUrlRequest) Reset() { + *x = GetUploadUrlRequest{} + mi := &file_helios_speech_speech_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUploadUrlRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUploadUrlRequest) ProtoMessage() {} + +func (x *GetUploadUrlRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_speech_speech_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUploadUrlRequest.ProtoReflect.Descriptor instead. +func (*GetUploadUrlRequest) Descriptor() ([]byte, []int) { + return file_helios_speech_speech_proto_rawDescGZIP(), []int{0} +} + +func (x *GetUploadUrlRequest) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *GetUploadUrlRequest) GetContentLength() int64 { + if x != nil { + return x.ContentLength + } + return 0 +} + +type GetUploadUrlResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Reference id to the object + ObjectId string `protobuf:"bytes,1,opt,name=object_id,json=objectId,proto3" json:"object_id,omitempty"` + // Make a PUT request to this url with the content + UploadUrl string `protobuf:"bytes,2,opt,name=upload_url,json=uploadUrl,proto3" json:"upload_url,omitempty"` + // Use these headers in the upload PUT request + UploadHeaders map[string]string `protobuf:"bytes,3,rep,name=upload_headers,json=uploadHeaders,proto3" json:"upload_headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *GetUploadUrlResponse) Reset() { + *x = GetUploadUrlResponse{} + mi := &file_helios_speech_speech_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUploadUrlResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUploadUrlResponse) ProtoMessage() {} + +func (x *GetUploadUrlResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_speech_speech_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUploadUrlResponse.ProtoReflect.Descriptor instead. +func (*GetUploadUrlResponse) Descriptor() ([]byte, []int) { + return file_helios_speech_speech_proto_rawDescGZIP(), []int{1} +} + +func (x *GetUploadUrlResponse) GetObjectId() string { + if x != nil { + return x.ObjectId + } + return "" +} + +func (x *GetUploadUrlResponse) GetUploadUrl() string { + if x != nil { + return x.UploadUrl + } + return "" +} + +func (x *GetUploadUrlResponse) GetUploadHeaders() map[string]string { + if x != nil { + return x.UploadHeaders + } + return nil +} + +type TranscribeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ObjectId string `protobuf:"bytes,1,opt,name=object_id,json=objectId,proto3" json:"object_id,omitempty"` + // Whether or not to use deepgram smart format + SmartFormat bool `protobuf:"varint,2,opt,name=smart_format,json=smartFormat,proto3" json:"smart_format,omitempty"` +} + +func (x *TranscribeRequest) Reset() { + *x = TranscribeRequest{} + mi := &file_helios_speech_speech_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TranscribeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TranscribeRequest) ProtoMessage() {} + +func (x *TranscribeRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_speech_speech_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TranscribeRequest.ProtoReflect.Descriptor instead. +func (*TranscribeRequest) Descriptor() ([]byte, []int) { + return file_helios_speech_speech_proto_rawDescGZIP(), []int{2} +} + +func (x *TranscribeRequest) GetObjectId() string { + if x != nil { + return x.ObjectId + } + return "" +} + +func (x *TranscribeRequest) GetSmartFormat() bool { + if x != nil { + return x.SmartFormat + } + return false +} + +type TranscribeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FullText string `protobuf:"bytes,1,opt,name=full_text,json=fullText,proto3" json:"full_text,omitempty"` +} + +func (x *TranscribeResponse) Reset() { + *x = TranscribeResponse{} + mi := &file_helios_speech_speech_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TranscribeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TranscribeResponse) ProtoMessage() {} + +func (x *TranscribeResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_speech_speech_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TranscribeResponse.ProtoReflect.Descriptor instead. +func (*TranscribeResponse) Descriptor() ([]byte, []int) { + return file_helios_speech_speech_proto_rawDescGZIP(), []int{3} +} + +func (x *TranscribeResponse) GetFullText() string { + if x != nil { + return x.FullText + } + return "" +} + +var File_helios_speech_speech_proto protoreflect.FileDescriptor + +var file_helios_speech_speech_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x2f, + 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x22, 0x5f, 0x0a, 0x13, 0x47, + 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0xf3, 0x01, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, + 0x6c, 0x12, 0x5d, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x68, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x65, 0x6c, 0x69, + 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x1a, 0x40, 0x0a, 0x12, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x53, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x5f, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x6d, 0x61, 0x72, + 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x31, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x32, 0xbb, 0x01, 0x0a, 0x0d, 0x53, + 0x70, 0x65, 0x65, 0x63, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x57, 0x0a, 0x0c, + 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x12, 0x22, 0x2e, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x2e, 0x47, 0x65, 0x74, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, + 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x65, + 0x65, 0x63, 0x68, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x73, + 0x70, 0x65, 0x65, 0x63, 0x68, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, + 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x3b, + 0x70, 0x62, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_helios_speech_speech_proto_rawDescOnce sync.Once + file_helios_speech_speech_proto_rawDescData = file_helios_speech_speech_proto_rawDesc +) + +func file_helios_speech_speech_proto_rawDescGZIP() []byte { + file_helios_speech_speech_proto_rawDescOnce.Do(func() { + file_helios_speech_speech_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_speech_speech_proto_rawDescData) + }) + return file_helios_speech_speech_proto_rawDescData +} + +var file_helios_speech_speech_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_helios_speech_speech_proto_goTypes = []any{ + (*GetUploadUrlRequest)(nil), // 0: helios.speech.GetUploadUrlRequest + (*GetUploadUrlResponse)(nil), // 1: helios.speech.GetUploadUrlResponse + (*TranscribeRequest)(nil), // 2: helios.speech.TranscribeRequest + (*TranscribeResponse)(nil), // 3: helios.speech.TranscribeResponse + nil, // 4: helios.speech.GetUploadUrlResponse.UploadHeadersEntry +} +var file_helios_speech_speech_proto_depIdxs = []int32{ + 4, // 0: helios.speech.GetUploadUrlResponse.upload_headers:type_name -> helios.speech.GetUploadUrlResponse.UploadHeadersEntry + 0, // 1: helios.speech.SpeechService.GetUploadUrl:input_type -> helios.speech.GetUploadUrlRequest + 2, // 2: helios.speech.SpeechService.Transcribe:input_type -> helios.speech.TranscribeRequest + 1, // 3: helios.speech.SpeechService.GetUploadUrl:output_type -> helios.speech.GetUploadUrlResponse + 3, // 4: helios.speech.SpeechService.Transcribe:output_type -> helios.speech.TranscribeResponse + 3, // [3:5] is the sub-list for method output_type + 1, // [1:3] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_helios_speech_speech_proto_init() } +func file_helios_speech_speech_proto_init() { + if File_helios_speech_speech_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_speech_speech_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_speech_speech_proto_goTypes, + DependencyIndexes: file_helios_speech_speech_proto_depIdxs, + MessageInfos: file_helios_speech_speech_proto_msgTypes, + }.Build() + File_helios_speech_speech_proto = out.File + file_helios_speech_speech_proto_rawDesc = nil + file_helios_speech_speech_proto_goTypes = nil + file_helios_speech_speech_proto_depIdxs = nil +} diff --git a/go/genproto/helios/speech/speech_grpc.pb.go b/go/genproto/helios/speech/speech_grpc.pb.go new file mode 100644 index 0000000..88eea69 --- /dev/null +++ b/go/genproto/helios/speech/speech_grpc.pb.go @@ -0,0 +1,163 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/speech/speech.proto + +package pbspeech + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + SpeechService_GetUploadUrl_FullMethodName = "/helios.speech.SpeechService/GetUploadUrl" + SpeechService_Transcribe_FullMethodName = "/helios.speech.SpeechService/Transcribe" +) + +// SpeechServiceClient is the client API for SpeechService 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 SpeechServiceClient interface { + GetUploadUrl(ctx context.Context, in *GetUploadUrlRequest, opts ...grpc.CallOption) (*GetUploadUrlResponse, error) + // Transcribes the given media & cleans up the resources. + // NOTE: must have uploaded to referenced object. + Transcribe(ctx context.Context, in *TranscribeRequest, opts ...grpc.CallOption) (*TranscribeResponse, error) +} + +type speechServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewSpeechServiceClient(cc grpc.ClientConnInterface) SpeechServiceClient { + return &speechServiceClient{cc} +} + +func (c *speechServiceClient) GetUploadUrl(ctx context.Context, in *GetUploadUrlRequest, opts ...grpc.CallOption) (*GetUploadUrlResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUploadUrlResponse) + err := c.cc.Invoke(ctx, SpeechService_GetUploadUrl_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *speechServiceClient) Transcribe(ctx context.Context, in *TranscribeRequest, opts ...grpc.CallOption) (*TranscribeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(TranscribeResponse) + err := c.cc.Invoke(ctx, SpeechService_Transcribe_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SpeechServiceServer is the server API for SpeechService service. +// All implementations must embed UnimplementedSpeechServiceServer +// for forward compatibility. +type SpeechServiceServer interface { + GetUploadUrl(context.Context, *GetUploadUrlRequest) (*GetUploadUrlResponse, error) + // Transcribes the given media & cleans up the resources. + // NOTE: must have uploaded to referenced object. + Transcribe(context.Context, *TranscribeRequest) (*TranscribeResponse, error) + mustEmbedUnimplementedSpeechServiceServer() +} + +// UnimplementedSpeechServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedSpeechServiceServer struct{} + +func (UnimplementedSpeechServiceServer) GetUploadUrl(context.Context, *GetUploadUrlRequest) (*GetUploadUrlResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUploadUrl not implemented") +} +func (UnimplementedSpeechServiceServer) Transcribe(context.Context, *TranscribeRequest) (*TranscribeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Transcribe not implemented") +} +func (UnimplementedSpeechServiceServer) mustEmbedUnimplementedSpeechServiceServer() {} +func (UnimplementedSpeechServiceServer) testEmbeddedByValue() {} + +// UnsafeSpeechServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to SpeechServiceServer will +// result in compilation errors. +type UnsafeSpeechServiceServer interface { + mustEmbedUnimplementedSpeechServiceServer() +} + +func RegisterSpeechServiceServer(s grpc.ServiceRegistrar, srv SpeechServiceServer) { + // If the following call pancis, it indicates UnimplementedSpeechServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&SpeechService_ServiceDesc, srv) +} + +func _SpeechService_GetUploadUrl_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUploadUrlRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SpeechServiceServer).GetUploadUrl(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SpeechService_GetUploadUrl_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SpeechServiceServer).GetUploadUrl(ctx, req.(*GetUploadUrlRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SpeechService_Transcribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TranscribeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SpeechServiceServer).Transcribe(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SpeechService_Transcribe_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SpeechServiceServer).Transcribe(ctx, req.(*TranscribeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// SpeechService_ServiceDesc is the grpc.ServiceDesc for SpeechService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var SpeechService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.speech.SpeechService", + HandlerType: (*SpeechServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetUploadUrl", + Handler: _SpeechService_GetUploadUrl_Handler, + }, + { + MethodName: "Transcribe", + Handler: _SpeechService_Transcribe_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/speech/speech.proto", +} diff --git a/go/genproto/helios/waitlist/waitlist.pb.go b/go/genproto/helios/waitlist/waitlist.pb.go new file mode 100644 index 0000000..fb162ae --- /dev/null +++ b/go/genproto/helios/waitlist/waitlist.pb.go @@ -0,0 +1,779 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/waitlist/waitlist.proto + +package pbwaitlist + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 GetWaitlistRequest_Filter int32 + +const ( + GetWaitlistRequest_FilterUnspecified GetWaitlistRequest_Filter = 0 + GetWaitlistRequest_FilterAll GetWaitlistRequest_Filter = 1 + GetWaitlistRequest_FilterInvitedOnly GetWaitlistRequest_Filter = 2 + GetWaitlistRequest_FilterUninvitedOnly GetWaitlistRequest_Filter = 3 +) + +// Enum value maps for GetWaitlistRequest_Filter. +var ( + GetWaitlistRequest_Filter_name = map[int32]string{ + 0: "FilterUnspecified", + 1: "FilterAll", + 2: "FilterInvitedOnly", + 3: "FilterUninvitedOnly", + } + GetWaitlistRequest_Filter_value = map[string]int32{ + "FilterUnspecified": 0, + "FilterAll": 1, + "FilterInvitedOnly": 2, + "FilterUninvitedOnly": 3, + } +) + +func (x GetWaitlistRequest_Filter) Enum() *GetWaitlistRequest_Filter { + p := new(GetWaitlistRequest_Filter) + *p = x + return p +} + +func (x GetWaitlistRequest_Filter) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GetWaitlistRequest_Filter) Descriptor() protoreflect.EnumDescriptor { + return file_helios_waitlist_waitlist_proto_enumTypes[0].Descriptor() +} + +func (GetWaitlistRequest_Filter) Type() protoreflect.EnumType { + return &file_helios_waitlist_waitlist_proto_enumTypes[0] +} + +func (x GetWaitlistRequest_Filter) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GetWaitlistRequest_Filter.Descriptor instead. +func (GetWaitlistRequest_Filter) EnumDescriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{3, 0} +} + +type WaitlistEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Metadata map[string]string `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + IsInvited bool `protobuf:"varint,4,opt,name=is_invited,json=isInvited,proto3" json:"is_invited,omitempty"` +} + +func (x *WaitlistEntry) Reset() { + *x = WaitlistEntry{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WaitlistEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WaitlistEntry) ProtoMessage() {} + +func (x *WaitlistEntry) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WaitlistEntry.ProtoReflect.Descriptor instead. +func (*WaitlistEntry) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{0} +} + +func (x *WaitlistEntry) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *WaitlistEntry) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *WaitlistEntry) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *WaitlistEntry) GetIsInvited() bool { + if x != nil { + return x.IsInvited + } + return false +} + +type AddToWaitlistRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Metadata map[string]string `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *AddToWaitlistRequest) Reset() { + *x = AddToWaitlistRequest{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddToWaitlistRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddToWaitlistRequest) ProtoMessage() {} + +func (x *AddToWaitlistRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddToWaitlistRequest.ProtoReflect.Descriptor instead. +func (*AddToWaitlistRequest) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{1} +} + +func (x *AddToWaitlistRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *AddToWaitlistRequest) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +type AddToWaitlistResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddToWaitlistResponse) Reset() { + *x = AddToWaitlistResponse{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddToWaitlistResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddToWaitlistResponse) ProtoMessage() {} + +func (x *AddToWaitlistResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddToWaitlistResponse.ProtoReflect.Descriptor instead. +func (*AddToWaitlistResponse) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{2} +} + +type GetWaitlistRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Filter GetWaitlistRequest_Filter `protobuf:"varint,1,opt,name=filter,proto3,enum=helios.waitlist.GetWaitlistRequest_Filter" json:"filter,omitempty"` +} + +func (x *GetWaitlistRequest) Reset() { + *x = GetWaitlistRequest{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetWaitlistRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWaitlistRequest) ProtoMessage() {} + +func (x *GetWaitlistRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWaitlistRequest.ProtoReflect.Descriptor instead. +func (*GetWaitlistRequest) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{3} +} + +func (x *GetWaitlistRequest) GetFilter() GetWaitlistRequest_Filter { + if x != nil { + return x.Filter + } + return GetWaitlistRequest_FilterUnspecified +} + +type GetWaitlistResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WaitlistEntries []*WaitlistEntry `protobuf:"bytes,1,rep,name=waitlist_entries,json=waitlistEntries,proto3" json:"waitlist_entries,omitempty"` +} + +func (x *GetWaitlistResponse) Reset() { + *x = GetWaitlistResponse{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetWaitlistResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWaitlistResponse) ProtoMessage() {} + +func (x *GetWaitlistResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWaitlistResponse.ProtoReflect.Descriptor instead. +func (*GetWaitlistResponse) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{4} +} + +func (x *GetWaitlistResponse) GetWaitlistEntries() []*WaitlistEntry { + if x != nil { + return x.WaitlistEntries + } + return nil +} + +type GetWaitlistEntryRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *GetWaitlistEntryRequest) Reset() { + *x = GetWaitlistEntryRequest{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetWaitlistEntryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWaitlistEntryRequest) ProtoMessage() {} + +func (x *GetWaitlistEntryRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWaitlistEntryRequest.ProtoReflect.Descriptor instead. +func (*GetWaitlistEntryRequest) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{5} +} + +func (x *GetWaitlistEntryRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type GetWaitlistEntryResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WaitlistEntry *WaitlistEntry `protobuf:"bytes,1,opt,name=waitlist_entry,json=waitlistEntry,proto3" json:"waitlist_entry,omitempty"` +} + +func (x *GetWaitlistEntryResponse) Reset() { + *x = GetWaitlistEntryResponse{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetWaitlistEntryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWaitlistEntryResponse) ProtoMessage() {} + +func (x *GetWaitlistEntryResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWaitlistEntryResponse.ProtoReflect.Descriptor instead. +func (*GetWaitlistEntryResponse) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{6} +} + +func (x *GetWaitlistEntryResponse) GetWaitlistEntry() *WaitlistEntry { + if x != nil { + return x.WaitlistEntry + } + return nil +} + +type InviteWaitlistEntrantRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *InviteWaitlistEntrantRequest) Reset() { + *x = InviteWaitlistEntrantRequest{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InviteWaitlistEntrantRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InviteWaitlistEntrantRequest) ProtoMessage() {} + +func (x *InviteWaitlistEntrantRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InviteWaitlistEntrantRequest.ProtoReflect.Descriptor instead. +func (*InviteWaitlistEntrantRequest) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{7} +} + +func (x *InviteWaitlistEntrantRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type InviteWaitlistEntrantResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *InviteWaitlistEntrantResponse) Reset() { + *x = InviteWaitlistEntrantResponse{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InviteWaitlistEntrantResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InviteWaitlistEntrantResponse) ProtoMessage() {} + +func (x *InviteWaitlistEntrantResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InviteWaitlistEntrantResponse.ProtoReflect.Descriptor instead. +func (*InviteWaitlistEntrantResponse) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{8} +} + +type InquiryRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *InquiryRequest) Reset() { + *x = InquiryRequest{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InquiryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InquiryRequest) ProtoMessage() {} + +func (x *InquiryRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InquiryRequest.ProtoReflect.Descriptor instead. +func (*InquiryRequest) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{9} +} + +func (x *InquiryRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *InquiryRequest) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type InquiryResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *InquiryResponse) Reset() { + *x = InquiryResponse{} + mi := &file_helios_waitlist_waitlist_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InquiryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InquiryResponse) ProtoMessage() {} + +func (x *InquiryResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_waitlist_waitlist_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InquiryResponse.ProtoReflect.Descriptor instead. +func (*InquiryResponse) Descriptor() ([]byte, []int) { + return file_helios_waitlist_waitlist_proto_rawDescGZIP(), []int{10} +} + +var File_helios_waitlist_waitlist_proto protoreflect.FileDescriptor + +var file_helios_waitlist_waitlist_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, + 0x74, 0x2f, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x0f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, + 0x74, 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, 0x86, 0x02, 0x0a, 0x0d, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x48, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x57, + 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x03, 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, + 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x64, 0x1a, 0x3b, + 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xba, 0x01, 0x0a, 0x14, + 0x41, 0x64, 0x64, 0x54, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x4f, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x41, + 0x64, 0x64, 0x54, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x17, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x54, + 0x6f, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0xb8, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, + 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, + 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x5e, 0x0a, 0x06, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x15, 0x0a, 0x11, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x55, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0d, 0x0a, + 0x09, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x41, 0x6c, 0x6c, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x6c, + 0x79, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x55, 0x6e, 0x69, + 0x6e, 0x76, 0x69, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x03, 0x22, 0x60, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x10, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x77, + 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x2f, + 0x0a, 0x17, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, + 0x61, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x77, + 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, + 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0d, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x22, 0x34, 0x0a, 0x1c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x57, 0x61, 0x69, 0x74, + 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x1f, 0x0a, 0x1d, 0x49, 0x6e, 0x76, 0x69, + 0x74, 0x65, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x40, 0x0a, 0x0e, 0x49, 0x6e, 0x71, + 0x75, 0x69, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x11, 0x0a, 0x0f, 0x49, + 0x6e, 0x71, 0x75, 0x69, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x84, + 0x04, 0x0a, 0x0f, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x6c, + 0x69, 0x73, 0x74, 0x12, 0x25, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, + 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x6c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x41, 0x64, 0x64, + 0x54, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, + 0x69, 0x73, 0x74, 0x12, 0x23, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, + 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, + 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, + 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x69, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x28, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, + 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, + 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, + 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x15, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x65, 0x57, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, + 0x72, 0x61, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, + 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x57, 0x61, 0x69, + 0x74, 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, + 0x74, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x57, 0x61, 0x69, 0x74, + 0x6c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x07, 0x49, 0x6e, 0x71, 0x75, 0x69, 0x72, 0x79, + 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, + 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x71, 0x75, 0x69, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x6c, + 0x69, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x71, 0x75, 0x69, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x3b, 0x70, + 0x62, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_helios_waitlist_waitlist_proto_rawDescOnce sync.Once + file_helios_waitlist_waitlist_proto_rawDescData = file_helios_waitlist_waitlist_proto_rawDesc +) + +func file_helios_waitlist_waitlist_proto_rawDescGZIP() []byte { + file_helios_waitlist_waitlist_proto_rawDescOnce.Do(func() { + file_helios_waitlist_waitlist_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_waitlist_waitlist_proto_rawDescData) + }) + return file_helios_waitlist_waitlist_proto_rawDescData +} + +var file_helios_waitlist_waitlist_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_helios_waitlist_waitlist_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_helios_waitlist_waitlist_proto_goTypes = []any{ + (GetWaitlistRequest_Filter)(0), // 0: helios.waitlist.GetWaitlistRequest.Filter + (*WaitlistEntry)(nil), // 1: helios.waitlist.WaitlistEntry + (*AddToWaitlistRequest)(nil), // 2: helios.waitlist.AddToWaitlistRequest + (*AddToWaitlistResponse)(nil), // 3: helios.waitlist.AddToWaitlistResponse + (*GetWaitlistRequest)(nil), // 4: helios.waitlist.GetWaitlistRequest + (*GetWaitlistResponse)(nil), // 5: helios.waitlist.GetWaitlistResponse + (*GetWaitlistEntryRequest)(nil), // 6: helios.waitlist.GetWaitlistEntryRequest + (*GetWaitlistEntryResponse)(nil), // 7: helios.waitlist.GetWaitlistEntryResponse + (*InviteWaitlistEntrantRequest)(nil), // 8: helios.waitlist.InviteWaitlistEntrantRequest + (*InviteWaitlistEntrantResponse)(nil), // 9: helios.waitlist.InviteWaitlistEntrantResponse + (*InquiryRequest)(nil), // 10: helios.waitlist.InquiryRequest + (*InquiryResponse)(nil), // 11: helios.waitlist.InquiryResponse + nil, // 12: helios.waitlist.WaitlistEntry.MetadataEntry + nil, // 13: helios.waitlist.AddToWaitlistRequest.MetadataEntry + (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp +} +var file_helios_waitlist_waitlist_proto_depIdxs = []int32{ + 12, // 0: helios.waitlist.WaitlistEntry.metadata:type_name -> helios.waitlist.WaitlistEntry.MetadataEntry + 14, // 1: helios.waitlist.WaitlistEntry.created_at:type_name -> google.protobuf.Timestamp + 13, // 2: helios.waitlist.AddToWaitlistRequest.metadata:type_name -> helios.waitlist.AddToWaitlistRequest.MetadataEntry + 0, // 3: helios.waitlist.GetWaitlistRequest.filter:type_name -> helios.waitlist.GetWaitlistRequest.Filter + 1, // 4: helios.waitlist.GetWaitlistResponse.waitlist_entries:type_name -> helios.waitlist.WaitlistEntry + 1, // 5: helios.waitlist.GetWaitlistEntryResponse.waitlist_entry:type_name -> helios.waitlist.WaitlistEntry + 2, // 6: helios.waitlist.WaitlistService.AddToWaitlist:input_type -> helios.waitlist.AddToWaitlistRequest + 4, // 7: helios.waitlist.WaitlistService.GetWaitlist:input_type -> helios.waitlist.GetWaitlistRequest + 6, // 8: helios.waitlist.WaitlistService.GetWaitlistEntry:input_type -> helios.waitlist.GetWaitlistEntryRequest + 8, // 9: helios.waitlist.WaitlistService.InviteWaitlistEntrant:input_type -> helios.waitlist.InviteWaitlistEntrantRequest + 10, // 10: helios.waitlist.WaitlistService.Inquiry:input_type -> helios.waitlist.InquiryRequest + 3, // 11: helios.waitlist.WaitlistService.AddToWaitlist:output_type -> helios.waitlist.AddToWaitlistResponse + 5, // 12: helios.waitlist.WaitlistService.GetWaitlist:output_type -> helios.waitlist.GetWaitlistResponse + 7, // 13: helios.waitlist.WaitlistService.GetWaitlistEntry:output_type -> helios.waitlist.GetWaitlistEntryResponse + 9, // 14: helios.waitlist.WaitlistService.InviteWaitlistEntrant:output_type -> helios.waitlist.InviteWaitlistEntrantResponse + 11, // 15: helios.waitlist.WaitlistService.Inquiry:output_type -> helios.waitlist.InquiryResponse + 11, // [11:16] is the sub-list for method output_type + 6, // [6:11] 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_helios_waitlist_waitlist_proto_init() } +func file_helios_waitlist_waitlist_proto_init() { + if File_helios_waitlist_waitlist_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_waitlist_waitlist_proto_rawDesc, + NumEnums: 1, + NumMessages: 13, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_waitlist_waitlist_proto_goTypes, + DependencyIndexes: file_helios_waitlist_waitlist_proto_depIdxs, + EnumInfos: file_helios_waitlist_waitlist_proto_enumTypes, + MessageInfos: file_helios_waitlist_waitlist_proto_msgTypes, + }.Build() + File_helios_waitlist_waitlist_proto = out.File + file_helios_waitlist_waitlist_proto_rawDesc = nil + file_helios_waitlist_waitlist_proto_goTypes = nil + file_helios_waitlist_waitlist_proto_depIdxs = nil +} diff --git a/go/genproto/helios/waitlist/waitlist_grpc.pb.go b/go/genproto/helios/waitlist/waitlist_grpc.pb.go new file mode 100644 index 0000000..8ddab2d --- /dev/null +++ b/go/genproto/helios/waitlist/waitlist_grpc.pb.go @@ -0,0 +1,273 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/waitlist/waitlist.proto + +package pbwaitlist + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + WaitlistService_AddToWaitlist_FullMethodName = "/helios.waitlist.WaitlistService/AddToWaitlist" + WaitlistService_GetWaitlist_FullMethodName = "/helios.waitlist.WaitlistService/GetWaitlist" + WaitlistService_GetWaitlistEntry_FullMethodName = "/helios.waitlist.WaitlistService/GetWaitlistEntry" + WaitlistService_InviteWaitlistEntrant_FullMethodName = "/helios.waitlist.WaitlistService/InviteWaitlistEntrant" + WaitlistService_Inquiry_FullMethodName = "/helios.waitlist.WaitlistService/Inquiry" +) + +// WaitlistServiceClient is the client API for WaitlistService 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 WaitlistServiceClient interface { + AddToWaitlist(ctx context.Context, in *AddToWaitlistRequest, opts ...grpc.CallOption) (*AddToWaitlistResponse, error) + GetWaitlist(ctx context.Context, in *GetWaitlistRequest, opts ...grpc.CallOption) (*GetWaitlistResponse, error) + GetWaitlistEntry(ctx context.Context, in *GetWaitlistEntryRequest, opts ...grpc.CallOption) (*GetWaitlistEntryResponse, error) + InviteWaitlistEntrant(ctx context.Context, in *InviteWaitlistEntrantRequest, opts ...grpc.CallOption) (*InviteWaitlistEntrantResponse, error) + Inquiry(ctx context.Context, in *InquiryRequest, opts ...grpc.CallOption) (*InquiryResponse, error) +} + +type waitlistServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewWaitlistServiceClient(cc grpc.ClientConnInterface) WaitlistServiceClient { + return &waitlistServiceClient{cc} +} + +func (c *waitlistServiceClient) AddToWaitlist(ctx context.Context, in *AddToWaitlistRequest, opts ...grpc.CallOption) (*AddToWaitlistResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddToWaitlistResponse) + err := c.cc.Invoke(ctx, WaitlistService_AddToWaitlist_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *waitlistServiceClient) GetWaitlist(ctx context.Context, in *GetWaitlistRequest, opts ...grpc.CallOption) (*GetWaitlistResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWaitlistResponse) + err := c.cc.Invoke(ctx, WaitlistService_GetWaitlist_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *waitlistServiceClient) GetWaitlistEntry(ctx context.Context, in *GetWaitlistEntryRequest, opts ...grpc.CallOption) (*GetWaitlistEntryResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWaitlistEntryResponse) + err := c.cc.Invoke(ctx, WaitlistService_GetWaitlistEntry_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *waitlistServiceClient) InviteWaitlistEntrant(ctx context.Context, in *InviteWaitlistEntrantRequest, opts ...grpc.CallOption) (*InviteWaitlistEntrantResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InviteWaitlistEntrantResponse) + err := c.cc.Invoke(ctx, WaitlistService_InviteWaitlistEntrant_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *waitlistServiceClient) Inquiry(ctx context.Context, in *InquiryRequest, opts ...grpc.CallOption) (*InquiryResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InquiryResponse) + err := c.cc.Invoke(ctx, WaitlistService_Inquiry_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// WaitlistServiceServer is the server API for WaitlistService service. +// All implementations must embed UnimplementedWaitlistServiceServer +// for forward compatibility. +type WaitlistServiceServer interface { + AddToWaitlist(context.Context, *AddToWaitlistRequest) (*AddToWaitlistResponse, error) + GetWaitlist(context.Context, *GetWaitlistRequest) (*GetWaitlistResponse, error) + GetWaitlistEntry(context.Context, *GetWaitlistEntryRequest) (*GetWaitlistEntryResponse, error) + InviteWaitlistEntrant(context.Context, *InviteWaitlistEntrantRequest) (*InviteWaitlistEntrantResponse, error) + Inquiry(context.Context, *InquiryRequest) (*InquiryResponse, error) + mustEmbedUnimplementedWaitlistServiceServer() +} + +// UnimplementedWaitlistServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedWaitlistServiceServer struct{} + +func (UnimplementedWaitlistServiceServer) AddToWaitlist(context.Context, *AddToWaitlistRequest) (*AddToWaitlistResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddToWaitlist not implemented") +} +func (UnimplementedWaitlistServiceServer) GetWaitlist(context.Context, *GetWaitlistRequest) (*GetWaitlistResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWaitlist not implemented") +} +func (UnimplementedWaitlistServiceServer) GetWaitlistEntry(context.Context, *GetWaitlistEntryRequest) (*GetWaitlistEntryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWaitlistEntry not implemented") +} +func (UnimplementedWaitlistServiceServer) InviteWaitlistEntrant(context.Context, *InviteWaitlistEntrantRequest) (*InviteWaitlistEntrantResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method InviteWaitlistEntrant not implemented") +} +func (UnimplementedWaitlistServiceServer) Inquiry(context.Context, *InquiryRequest) (*InquiryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Inquiry not implemented") +} +func (UnimplementedWaitlistServiceServer) mustEmbedUnimplementedWaitlistServiceServer() {} +func (UnimplementedWaitlistServiceServer) testEmbeddedByValue() {} + +// UnsafeWaitlistServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to WaitlistServiceServer will +// result in compilation errors. +type UnsafeWaitlistServiceServer interface { + mustEmbedUnimplementedWaitlistServiceServer() +} + +func RegisterWaitlistServiceServer(s grpc.ServiceRegistrar, srv WaitlistServiceServer) { + // If the following call pancis, it indicates UnimplementedWaitlistServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&WaitlistService_ServiceDesc, srv) +} + +func _WaitlistService_AddToWaitlist_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddToWaitlistRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WaitlistServiceServer).AddToWaitlist(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WaitlistService_AddToWaitlist_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WaitlistServiceServer).AddToWaitlist(ctx, req.(*AddToWaitlistRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WaitlistService_GetWaitlist_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWaitlistRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WaitlistServiceServer).GetWaitlist(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WaitlistService_GetWaitlist_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WaitlistServiceServer).GetWaitlist(ctx, req.(*GetWaitlistRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WaitlistService_GetWaitlistEntry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWaitlistEntryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WaitlistServiceServer).GetWaitlistEntry(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WaitlistService_GetWaitlistEntry_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WaitlistServiceServer).GetWaitlistEntry(ctx, req.(*GetWaitlistEntryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WaitlistService_InviteWaitlistEntrant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InviteWaitlistEntrantRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WaitlistServiceServer).InviteWaitlistEntrant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WaitlistService_InviteWaitlistEntrant_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WaitlistServiceServer).InviteWaitlistEntrant(ctx, req.(*InviteWaitlistEntrantRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WaitlistService_Inquiry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InquiryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WaitlistServiceServer).Inquiry(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WaitlistService_Inquiry_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WaitlistServiceServer).Inquiry(ctx, req.(*InquiryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// WaitlistService_ServiceDesc is the grpc.ServiceDesc for WaitlistService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var WaitlistService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.waitlist.WaitlistService", + HandlerType: (*WaitlistServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddToWaitlist", + Handler: _WaitlistService_AddToWaitlist_Handler, + }, + { + MethodName: "GetWaitlist", + Handler: _WaitlistService_GetWaitlist_Handler, + }, + { + MethodName: "GetWaitlistEntry", + Handler: _WaitlistService_GetWaitlistEntry_Handler, + }, + { + MethodName: "InviteWaitlistEntrant", + Handler: _WaitlistService_InviteWaitlistEntrant_Handler, + }, + { + MethodName: "Inquiry", + Handler: _WaitlistService_Inquiry_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/waitlist/waitlist.proto", +} diff --git a/go/genproto/helios/widgets/widgets.pb.go b/go/genproto/helios/widgets/widgets.pb.go new file mode 100644 index 0000000..b4a989d --- /dev/null +++ b/go/genproto/helios/widgets/widgets.pb.go @@ -0,0 +1,554 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/widgets/widgets.proto + +package pbwidgets + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 WidgetSizeVariant int32 + +const ( + WidgetSizeVariant_WIDGET_SIZE_VARIANT_UNSPECIFIED WidgetSizeVariant = 0 + WidgetSizeVariant_WIDGET_SIZE_VARIANT_1_X_1 WidgetSizeVariant = 1 + WidgetSizeVariant_WIDGET_SIZE_VARIANT_2_X_1 WidgetSizeVariant = 2 + WidgetSizeVariant_WIDGET_SIZE_VARIANT_1_X_2 WidgetSizeVariant = 3 + WidgetSizeVariant_WIDGET_SIZE_VARIANT_2_X_2 WidgetSizeVariant = 4 + WidgetSizeVariant_WIDGET_SIZE_VARIANT_4_X_4 WidgetSizeVariant = 5 +) + +// Enum value maps for WidgetSizeVariant. +var ( + WidgetSizeVariant_name = map[int32]string{ + 0: "WIDGET_SIZE_VARIANT_UNSPECIFIED", + 1: "WIDGET_SIZE_VARIANT_1_X_1", + 2: "WIDGET_SIZE_VARIANT_2_X_1", + 3: "WIDGET_SIZE_VARIANT_1_X_2", + 4: "WIDGET_SIZE_VARIANT_2_X_2", + 5: "WIDGET_SIZE_VARIANT_4_X_4", + } + WidgetSizeVariant_value = map[string]int32{ + "WIDGET_SIZE_VARIANT_UNSPECIFIED": 0, + "WIDGET_SIZE_VARIANT_1_X_1": 1, + "WIDGET_SIZE_VARIANT_2_X_1": 2, + "WIDGET_SIZE_VARIANT_1_X_2": 3, + "WIDGET_SIZE_VARIANT_2_X_2": 4, + "WIDGET_SIZE_VARIANT_4_X_4": 5, + } +) + +func (x WidgetSizeVariant) Enum() *WidgetSizeVariant { + p := new(WidgetSizeVariant) + *p = x + return p +} + +func (x WidgetSizeVariant) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WidgetSizeVariant) Descriptor() protoreflect.EnumDescriptor { + return file_helios_widgets_widgets_proto_enumTypes[0].Descriptor() +} + +func (WidgetSizeVariant) Type() protoreflect.EnumType { + return &file_helios_widgets_widgets_proto_enumTypes[0] +} + +func (x WidgetSizeVariant) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WidgetSizeVariant.Descriptor instead. +func (WidgetSizeVariant) EnumDescriptor() ([]byte, []int) { + return file_helios_widgets_widgets_proto_rawDescGZIP(), []int{0} +} + +// A flowy system representation of a human's context/what they're doing. +type AppContext struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // e.g. Figma (web) + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + IconUri *AppContext_IconUri `protobuf:"bytes,3,opt,name=icon_uri,json=iconUri,proto3" json:"icon_uri,omitempty"` + // Types that are assignable to ContextMatch: + // + // *AppContext_DesktopAppProcessName + // *AppContext_WebAppDomain + // *AppContext_WebUrlPrefix + ContextMatch isAppContext_ContextMatch `protobuf_oneof:"context_match"` + // Optional. + // Hue that matches the branding of this app context. Used for widget gradient bg aesthetic. + HueColorHex string `protobuf:"bytes,7,opt,name=hue_color_hex,json=hueColorHex,proto3" json:"hue_color_hex,omitempty"` +} + +func (x *AppContext) Reset() { + *x = AppContext{} + mi := &file_helios_widgets_widgets_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AppContext) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AppContext) ProtoMessage() {} + +func (x *AppContext) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgets_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AppContext.ProtoReflect.Descriptor instead. +func (*AppContext) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgets_proto_rawDescGZIP(), []int{0} +} + +func (x *AppContext) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AppContext) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *AppContext) GetIconUri() *AppContext_IconUri { + if x != nil { + return x.IconUri + } + return nil +} + +func (m *AppContext) GetContextMatch() isAppContext_ContextMatch { + if m != nil { + return m.ContextMatch + } + return nil +} + +func (x *AppContext) GetDesktopAppProcessName() string { + if x, ok := x.GetContextMatch().(*AppContext_DesktopAppProcessName); ok { + return x.DesktopAppProcessName + } + return "" +} + +func (x *AppContext) GetWebAppDomain() string { + if x, ok := x.GetContextMatch().(*AppContext_WebAppDomain); ok { + return x.WebAppDomain + } + return "" +} + +func (x *AppContext) GetWebUrlPrefix() string { + if x, ok := x.GetContextMatch().(*AppContext_WebUrlPrefix); ok { + return x.WebUrlPrefix + } + return "" +} + +func (x *AppContext) GetHueColorHex() string { + if x != nil { + return x.HueColorHex + } + return "" +} + +type isAppContext_ContextMatch interface { + isAppContext_ContextMatch() +} + +type AppContext_DesktopAppProcessName struct { + // e.g. Code + DesktopAppProcessName string `protobuf:"bytes,4,opt,name=desktop_app_process_name,json=desktopAppProcessName,proto3,oneof"` +} + +type AppContext_WebAppDomain struct { + // e.g. figma.com + WebAppDomain string `protobuf:"bytes,5,opt,name=web_app_domain,json=webAppDomain,proto3,oneof"` +} + +type AppContext_WebUrlPrefix struct { + // e.g. youtube.com/watch + WebUrlPrefix string `protobuf:"bytes,6,opt,name=web_url_prefix,json=webUrlPrefix,proto3,oneof"` +} + +func (*AppContext_DesktopAppProcessName) isAppContext_ContextMatch() {} + +func (*AppContext_WebAppDomain) isAppContext_ContextMatch() {} + +func (*AppContext_WebUrlPrefix) isAppContext_ContextMatch() {} + +type Space 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"` + // Optional. + // This defines how this space auto-activates, as well as what action a manual trigger performs (e.g. focus desktop app, find relevant browser tab) + AppContext *AppContext `protobuf:"bytes,3,opt,name=app_context,json=appContext,proto3" json:"app_context,omitempty"` + WidgetsInstances []*WidgetInstance `protobuf:"bytes,4,rep,name=widgets_instances,json=widgetsInstances,proto3" json:"widgets_instances,omitempty"` +} + +func (x *Space) Reset() { + *x = Space{} + mi := &file_helios_widgets_widgets_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Space) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Space) ProtoMessage() {} + +func (x *Space) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgets_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Space.ProtoReflect.Descriptor instead. +func (*Space) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgets_proto_rawDescGZIP(), []int{1} +} + +func (x *Space) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Space) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Space) GetAppContext() *AppContext { + if x != nil { + return x.AppContext + } + return nil +} + +func (x *Space) GetWidgetsInstances() []*WidgetInstance { + if x != nil { + return x.WidgetsInstances + } + return nil +} + +type WidgetInstance struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + WidgetIdentifier string `protobuf:"bytes,2,opt,name=widget_identifier,json=widgetIdentifier,proto3" json:"widget_identifier,omitempty"` + WidgetVersion string `protobuf:"bytes,3,opt,name=widget_version,json=widgetVersion,proto3" json:"widget_version,omitempty"` + // The selected size_variant from the available ones of the underlying widget. + WidgetSizeVariant WidgetSizeVariant `protobuf:"varint,4,opt,name=widget_size_variant,json=widgetSizeVariant,proto3,enum=helios.widgets.WidgetSizeVariant" json:"widget_size_variant,omitempty"` + // Configuration data or state for this specific widget instance. + // e.g. bookmark url, list of saved terminal commands + Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *WidgetInstance) Reset() { + *x = WidgetInstance{} + mi := &file_helios_widgets_widgets_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WidgetInstance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WidgetInstance) ProtoMessage() {} + +func (x *WidgetInstance) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgets_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WidgetInstance.ProtoReflect.Descriptor instead. +func (*WidgetInstance) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgets_proto_rawDescGZIP(), []int{2} +} + +func (x *WidgetInstance) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *WidgetInstance) GetWidgetIdentifier() string { + if x != nil { + return x.WidgetIdentifier + } + return "" +} + +func (x *WidgetInstance) GetWidgetVersion() string { + if x != nil { + return x.WidgetVersion + } + return "" +} + +func (x *WidgetInstance) GetWidgetSizeVariant() WidgetSizeVariant { + if x != nil { + return x.WidgetSizeVariant + } + return WidgetSizeVariant_WIDGET_SIZE_VARIANT_UNSPECIFIED +} + +func (x *WidgetInstance) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type AppContext_IconUri struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Dark string `protobuf:"bytes,1,opt,name=dark,proto3" json:"dark,omitempty"` + Light string `protobuf:"bytes,2,opt,name=light,proto3" json:"light,omitempty"` +} + +func (x *AppContext_IconUri) Reset() { + *x = AppContext_IconUri{} + mi := &file_helios_widgets_widgets_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AppContext_IconUri) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AppContext_IconUri) ProtoMessage() {} + +func (x *AppContext_IconUri) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgets_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AppContext_IconUri.ProtoReflect.Descriptor instead. +func (*AppContext_IconUri) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgets_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *AppContext_IconUri) GetDark() string { + if x != nil { + return x.Dark + } + return "" +} + +func (x *AppContext_IconUri) GetLight() string { + if x != nil { + return x.Light + } + return "" +} + +var File_helios_widgets_widgets_proto protoreflect.FileDescriptor + +var file_helios_widgets_widgets_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, + 0x2f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x22, 0xf3, + 0x02, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, + 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x3d, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x49, + 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x12, + 0x39, 0x0a, 0x18, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x61, 0x70, 0x70, 0x5f, 0x70, + 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x15, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x41, 0x70, 0x70, 0x50, + 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x77, 0x65, + 0x62, 0x5f, 0x61, 0x70, 0x70, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x77, 0x65, 0x62, 0x41, 0x70, 0x70, 0x44, 0x6f, 0x6d, 0x61, + 0x69, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x77, 0x65, 0x62, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x70, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x77, 0x65, + 0x62, 0x55, 0x72, 0x6c, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x75, + 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x65, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x68, 0x75, 0x65, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x48, 0x65, 0x78, 0x1a, 0x33, + 0x0a, 0x07, 0x49, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x72, + 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x72, 0x6b, 0x12, 0x14, 0x0a, + 0x05, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x22, 0xb5, 0x01, 0x0a, 0x05, 0x53, 0x70, 0x61, 0x63, 0x65, 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, 0x3b, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, + 0x4b, 0x0a, 0x11, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x57, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x10, 0x77, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x22, 0xdb, 0x01, 0x0a, + 0x0e, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x2b, 0x0a, 0x11, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, + 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x13, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x69, + 0x7a, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x21, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, + 0x73, 0x2e, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x6e, 0x74, 0x52, 0x11, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x56, + 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0xd3, 0x01, 0x0a, 0x11, 0x57, + 0x69, 0x64, 0x67, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, + 0x12, 0x23, 0x0a, 0x1f, 0x57, 0x49, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x5f, + 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x57, 0x49, 0x44, 0x47, 0x45, 0x54, 0x5f, + 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x5f, 0x31, 0x5f, 0x58, + 0x5f, 0x31, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x57, 0x49, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x53, + 0x49, 0x5a, 0x45, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x5f, 0x32, 0x5f, 0x58, 0x5f, + 0x31, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x57, 0x49, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x53, 0x49, + 0x5a, 0x45, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x5f, 0x31, 0x5f, 0x58, 0x5f, 0x32, + 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x57, 0x49, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x53, 0x49, 0x5a, + 0x45, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x5f, 0x32, 0x5f, 0x58, 0x5f, 0x32, 0x10, + 0x04, 0x12, 0x1d, 0x0a, 0x19, 0x57, 0x49, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x53, 0x49, 0x5a, 0x45, + 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x5f, 0x34, 0x5f, 0x58, 0x5f, 0x34, 0x10, 0x05, + 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, + 0x6c, 0x6f, 0x77, 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, + 0x2f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x3b, 0x70, 0x62, 0x77, 0x69, 0x64, 0x67, 0x65, + 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_helios_widgets_widgets_proto_rawDescOnce sync.Once + file_helios_widgets_widgets_proto_rawDescData = file_helios_widgets_widgets_proto_rawDesc +) + +func file_helios_widgets_widgets_proto_rawDescGZIP() []byte { + file_helios_widgets_widgets_proto_rawDescOnce.Do(func() { + file_helios_widgets_widgets_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_widgets_widgets_proto_rawDescData) + }) + return file_helios_widgets_widgets_proto_rawDescData +} + +var file_helios_widgets_widgets_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_helios_widgets_widgets_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_helios_widgets_widgets_proto_goTypes = []any{ + (WidgetSizeVariant)(0), // 0: helios.widgets.WidgetSizeVariant + (*AppContext)(nil), // 1: helios.widgets.AppContext + (*Space)(nil), // 2: helios.widgets.Space + (*WidgetInstance)(nil), // 3: helios.widgets.WidgetInstance + (*AppContext_IconUri)(nil), // 4: helios.widgets.AppContext.IconUri +} +var file_helios_widgets_widgets_proto_depIdxs = []int32{ + 4, // 0: helios.widgets.AppContext.icon_uri:type_name -> helios.widgets.AppContext.IconUri + 1, // 1: helios.widgets.Space.app_context:type_name -> helios.widgets.AppContext + 3, // 2: helios.widgets.Space.widgets_instances:type_name -> helios.widgets.WidgetInstance + 0, // 3: helios.widgets.WidgetInstance.widget_size_variant:type_name -> helios.widgets.WidgetSizeVariant + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_helios_widgets_widgets_proto_init() } +func file_helios_widgets_widgets_proto_init() { + if File_helios_widgets_widgets_proto != nil { + return + } + file_helios_widgets_widgets_proto_msgTypes[0].OneofWrappers = []any{ + (*AppContext_DesktopAppProcessName)(nil), + (*AppContext_WebAppDomain)(nil), + (*AppContext_WebUrlPrefix)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_widgets_widgets_proto_rawDesc, + NumEnums: 1, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_helios_widgets_widgets_proto_goTypes, + DependencyIndexes: file_helios_widgets_widgets_proto_depIdxs, + EnumInfos: file_helios_widgets_widgets_proto_enumTypes, + MessageInfos: file_helios_widgets_widgets_proto_msgTypes, + }.Build() + File_helios_widgets_widgets_proto = out.File + file_helios_widgets_widgets_proto_rawDesc = nil + file_helios_widgets_widgets_proto_goTypes = nil + file_helios_widgets_widgets_proto_depIdxs = nil +} diff --git a/go/genproto/helios/widgets/widgetservice.pb.go b/go/genproto/helios/widgets/widgetservice.pb.go new file mode 100644 index 0000000..df0242f --- /dev/null +++ b/go/genproto/helios/widgets/widgetservice.pb.go @@ -0,0 +1,1191 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: helios/widgets/widgetservice.proto + +package pbwidgets + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 ListAppContextsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListAppContextsRequest) Reset() { + *x = ListAppContextsRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListAppContextsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAppContextsRequest) ProtoMessage() {} + +func (x *ListAppContextsRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListAppContextsRequest.ProtoReflect.Descriptor instead. +func (*ListAppContextsRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{0} +} + +type ListAppContextsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AppContexts []*AppContext `protobuf:"bytes,1,rep,name=app_contexts,json=appContexts,proto3" json:"app_contexts,omitempty"` +} + +func (x *ListAppContextsResponse) Reset() { + *x = ListAppContextsResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListAppContextsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAppContextsResponse) ProtoMessage() {} + +func (x *ListAppContextsResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListAppContextsResponse.ProtoReflect.Descriptor instead. +func (*ListAppContextsResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{1} +} + +func (x *ListAppContextsResponse) GetAppContexts() []*AppContext { + if x != nil { + return x.AppContexts + } + return nil +} + +type ListSpacesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListSpacesRequest) Reset() { + *x = ListSpacesRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSpacesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSpacesRequest) ProtoMessage() {} + +func (x *ListSpacesRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSpacesRequest.ProtoReflect.Descriptor instead. +func (*ListSpacesRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{2} +} + +type ListSpacesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Spaces []*Space `protobuf:"bytes,1,rep,name=spaces,proto3" json:"spaces,omitempty"` +} + +func (x *ListSpacesResponse) Reset() { + *x = ListSpacesResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSpacesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSpacesResponse) ProtoMessage() {} + +func (x *ListSpacesResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSpacesResponse.ProtoReflect.Descriptor instead. +func (*ListSpacesResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{3} +} + +func (x *ListSpacesResponse) GetSpaces() []*Space { + if x != nil { + return x.Spaces + } + return nil +} + +type AddSpaceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Optional. + AppContextId string `protobuf:"bytes,2,opt,name=app_context_id,json=appContextId,proto3" json:"app_context_id,omitempty"` +} + +func (x *AddSpaceRequest) Reset() { + *x = AddSpaceRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddSpaceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSpaceRequest) ProtoMessage() {} + +func (x *AddSpaceRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSpaceRequest.ProtoReflect.Descriptor instead. +func (*AddSpaceRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{4} +} + +func (x *AddSpaceRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AddSpaceRequest) GetAppContextId() string { + if x != nil { + return x.AppContextId + } + return "" +} + +type AddSpaceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Space *Space `protobuf:"bytes,1,opt,name=space,proto3" json:"space,omitempty"` +} + +func (x *AddSpaceResponse) Reset() { + *x = AddSpaceResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddSpaceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSpaceResponse) ProtoMessage() {} + +func (x *AddSpaceResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSpaceResponse.ProtoReflect.Descriptor instead. +func (*AddSpaceResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{5} +} + +func (x *AddSpaceResponse) GetSpace() *Space { + if x != nil { + return x.Space + } + return nil +} + +type UpdateSpaceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + AppContextId string `protobuf:"bytes,3,opt,name=app_context_id,json=appContextId,proto3" json:"app_context_id,omitempty"` +} + +func (x *UpdateSpaceRequest) Reset() { + *x = UpdateSpaceRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateSpaceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSpaceRequest) ProtoMessage() {} + +func (x *UpdateSpaceRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSpaceRequest.ProtoReflect.Descriptor instead. +func (*UpdateSpaceRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateSpaceRequest) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +func (x *UpdateSpaceRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateSpaceRequest) GetAppContextId() string { + if x != nil { + return x.AppContextId + } + return "" +} + +type UpdateSpaceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Space *Space `protobuf:"bytes,1,opt,name=space,proto3" json:"space,omitempty"` +} + +func (x *UpdateSpaceResponse) Reset() { + *x = UpdateSpaceResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateSpaceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSpaceResponse) ProtoMessage() {} + +func (x *UpdateSpaceResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSpaceResponse.ProtoReflect.Descriptor instead. +func (*UpdateSpaceResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateSpaceResponse) GetSpace() *Space { + if x != nil { + return x.Space + } + return nil +} + +type DeleteSpaceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` +} + +func (x *DeleteSpaceRequest) Reset() { + *x = DeleteSpaceRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteSpaceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSpaceRequest) ProtoMessage() {} + +func (x *DeleteSpaceRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSpaceRequest.ProtoReflect.Descriptor instead. +func (*DeleteSpaceRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{8} +} + +func (x *DeleteSpaceRequest) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +type DeleteSpaceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSpaceResponse) Reset() { + *x = DeleteSpaceResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteSpaceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSpaceResponse) ProtoMessage() {} + +func (x *DeleteSpaceResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSpaceResponse.ProtoReflect.Descriptor instead. +func (*DeleteSpaceResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{9} +} + +type ReorderSpacesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SpaceIds []string `protobuf:"bytes,1,rep,name=space_ids,json=spaceIds,proto3" json:"space_ids,omitempty"` +} + +func (x *ReorderSpacesRequest) Reset() { + *x = ReorderSpacesRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReorderSpacesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReorderSpacesRequest) ProtoMessage() {} + +func (x *ReorderSpacesRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReorderSpacesRequest.ProtoReflect.Descriptor instead. +func (*ReorderSpacesRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{10} +} + +func (x *ReorderSpacesRequest) GetSpaceIds() []string { + if x != nil { + return x.SpaceIds + } + return nil +} + +type ReorderSpacesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ReorderSpacesResponse) Reset() { + *x = ReorderSpacesResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReorderSpacesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReorderSpacesResponse) ProtoMessage() {} + +func (x *ReorderSpacesResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReorderSpacesResponse.ProtoReflect.Descriptor instead. +func (*ReorderSpacesResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{11} +} + +type CreateWidgetInstanceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` + WidgetIdentifier string `protobuf:"bytes,2,opt,name=widget_identifier,json=widgetIdentifier,proto3" json:"widget_identifier,omitempty"` + WidgetVersion string `protobuf:"bytes,3,opt,name=widget_version,json=widgetVersion,proto3" json:"widget_version,omitempty"` + WidgetSizeVariant WidgetSizeVariant `protobuf:"varint,4,opt,name=widget_size_variant,json=widgetSizeVariant,proto3,enum=helios.widgets.WidgetSizeVariant" json:"widget_size_variant,omitempty"` +} + +func (x *CreateWidgetInstanceRequest) Reset() { + *x = CreateWidgetInstanceRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateWidgetInstanceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateWidgetInstanceRequest) ProtoMessage() {} + +func (x *CreateWidgetInstanceRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateWidgetInstanceRequest.ProtoReflect.Descriptor instead. +func (*CreateWidgetInstanceRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{12} +} + +func (x *CreateWidgetInstanceRequest) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +func (x *CreateWidgetInstanceRequest) GetWidgetIdentifier() string { + if x != nil { + return x.WidgetIdentifier + } + return "" +} + +func (x *CreateWidgetInstanceRequest) GetWidgetVersion() string { + if x != nil { + return x.WidgetVersion + } + return "" +} + +func (x *CreateWidgetInstanceRequest) GetWidgetSizeVariant() WidgetSizeVariant { + if x != nil { + return x.WidgetSizeVariant + } + return WidgetSizeVariant_WIDGET_SIZE_VARIANT_UNSPECIFIED +} + +type CreateWidgetInstanceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WidgetInstance *WidgetInstance `protobuf:"bytes,1,opt,name=widget_instance,json=widgetInstance,proto3" json:"widget_instance,omitempty"` +} + +func (x *CreateWidgetInstanceResponse) Reset() { + *x = CreateWidgetInstanceResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateWidgetInstanceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateWidgetInstanceResponse) ProtoMessage() {} + +func (x *CreateWidgetInstanceResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateWidgetInstanceResponse.ProtoReflect.Descriptor instead. +func (*CreateWidgetInstanceResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{13} +} + +func (x *CreateWidgetInstanceResponse) GetWidgetInstance() *WidgetInstance { + if x != nil { + return x.WidgetInstance + } + return nil +} + +type SaveWidgetInstanceDataRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WidgetInstanceId string `protobuf:"bytes,1,opt,name=widget_instance_id,json=widgetInstanceId,proto3" json:"widget_instance_id,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *SaveWidgetInstanceDataRequest) Reset() { + *x = SaveWidgetInstanceDataRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SaveWidgetInstanceDataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SaveWidgetInstanceDataRequest) ProtoMessage() {} + +func (x *SaveWidgetInstanceDataRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SaveWidgetInstanceDataRequest.ProtoReflect.Descriptor instead. +func (*SaveWidgetInstanceDataRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{14} +} + +func (x *SaveWidgetInstanceDataRequest) GetWidgetInstanceId() string { + if x != nil { + return x.WidgetInstanceId + } + return "" +} + +func (x *SaveWidgetInstanceDataRequest) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type SaveWidgetInstanceDataResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SaveWidgetInstanceDataResponse) Reset() { + *x = SaveWidgetInstanceDataResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SaveWidgetInstanceDataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SaveWidgetInstanceDataResponse) ProtoMessage() {} + +func (x *SaveWidgetInstanceDataResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SaveWidgetInstanceDataResponse.ProtoReflect.Descriptor instead. +func (*SaveWidgetInstanceDataResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{15} +} + +type MoveWidgetInstanceToSpaceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WidgetInstanceId string `protobuf:"bytes,1,opt,name=widget_instance_id,json=widgetInstanceId,proto3" json:"widget_instance_id,omitempty"` + TargetSpaceId string `protobuf:"bytes,2,opt,name=target_space_id,json=targetSpaceId,proto3" json:"target_space_id,omitempty"` +} + +func (x *MoveWidgetInstanceToSpaceRequest) Reset() { + *x = MoveWidgetInstanceToSpaceRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MoveWidgetInstanceToSpaceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MoveWidgetInstanceToSpaceRequest) ProtoMessage() {} + +func (x *MoveWidgetInstanceToSpaceRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MoveWidgetInstanceToSpaceRequest.ProtoReflect.Descriptor instead. +func (*MoveWidgetInstanceToSpaceRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{16} +} + +func (x *MoveWidgetInstanceToSpaceRequest) GetWidgetInstanceId() string { + if x != nil { + return x.WidgetInstanceId + } + return "" +} + +func (x *MoveWidgetInstanceToSpaceRequest) GetTargetSpaceId() string { + if x != nil { + return x.TargetSpaceId + } + return "" +} + +type MoveWidgetInstanceToSpaceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MoveWidgetInstanceToSpaceResponse) Reset() { + *x = MoveWidgetInstanceToSpaceResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MoveWidgetInstanceToSpaceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MoveWidgetInstanceToSpaceResponse) ProtoMessage() {} + +func (x *MoveWidgetInstanceToSpaceResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MoveWidgetInstanceToSpaceResponse.ProtoReflect.Descriptor instead. +func (*MoveWidgetInstanceToSpaceResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{17} +} + +type DeleteWidgetInstanceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WidgetInstanceId string `protobuf:"bytes,1,opt,name=widget_instance_id,json=widgetInstanceId,proto3" json:"widget_instance_id,omitempty"` +} + +func (x *DeleteWidgetInstanceRequest) Reset() { + *x = DeleteWidgetInstanceRequest{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteWidgetInstanceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteWidgetInstanceRequest) ProtoMessage() {} + +func (x *DeleteWidgetInstanceRequest) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteWidgetInstanceRequest.ProtoReflect.Descriptor instead. +func (*DeleteWidgetInstanceRequest) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{18} +} + +func (x *DeleteWidgetInstanceRequest) GetWidgetInstanceId() string { + if x != nil { + return x.WidgetInstanceId + } + return "" +} + +type DeleteWidgetInstanceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteWidgetInstanceResponse) Reset() { + *x = DeleteWidgetInstanceResponse{} + mi := &file_helios_widgets_widgetservice_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteWidgetInstanceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteWidgetInstanceResponse) ProtoMessage() {} + +func (x *DeleteWidgetInstanceResponse) ProtoReflect() protoreflect.Message { + mi := &file_helios_widgets_widgetservice_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteWidgetInstanceResponse.ProtoReflect.Descriptor instead. +func (*DeleteWidgetInstanceResponse) Descriptor() ([]byte, []int) { + return file_helios_widgets_widgetservice_proto_rawDescGZIP(), []int{19} +} + +var File_helios_widgets_widgetservice_proto protoreflect.FileDescriptor + +var file_helios_widgets_widgetservice_proto_rawDesc = []byte{ + 0x0a, 0x22, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, + 0x2f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, + 0x67, 0x65, 0x74, 0x73, 0x1a, 0x1c, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x77, 0x69, 0x64, + 0x67, 0x65, 0x74, 0x73, 0x2f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x18, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x58, 0x0a, 0x17, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x61, 0x70, 0x70, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x41, + 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x73, 0x22, 0x13, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, 0x12, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, + 0x74, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x22, 0x4b, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x53, 0x70, 0x61, 0x63, 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, 0x24, 0x0a, 0x0e, 0x61, 0x70, 0x70, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x49, 0x64, 0x22, 0x3f, 0x0a, + 0x10, 0x41, 0x64, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, + 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x69, + 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x70, 0x70, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x49, 0x64, 0x22, 0x42, 0x0a, 0x13, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, + 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x2f, 0x0a, + 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x15, + 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a, 0x14, 0x52, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, + 0x09, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0xdf, 0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, + 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2b, + 0x0a, 0x11, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x69, 0x64, 0x67, 0x65, + 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x77, + 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x13, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x7a, + 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x21, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, + 0x2e, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, + 0x6e, 0x74, 0x52, 0x11, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x56, 0x61, + 0x72, 0x69, 0x61, 0x6e, 0x74, 0x22, 0x67, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, + 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, + 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x0e, + 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x61, + 0x0a, 0x1d, 0x53, 0x61, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x2c, 0x0a, 0x12, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x69, 0x64, + 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x61, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x78, 0x0a, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, + 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x6f, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x69, 0x64, 0x67, 0x65, + 0x74, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x23, 0x0a, + 0x21, 0x4d, 0x6f, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x54, 0x6f, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x4b, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, + 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, + 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, + 0x9b, 0x08, 0x0a, 0x0d, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x73, 0x12, 0x26, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, + 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, + 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, + 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, + 0x0a, 0x08, 0x41, 0x64, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x41, 0x64, 0x64, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x58, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x22, + 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0b, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, + 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, + 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x0d, 0x52, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, + 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x53, 0x70, 0x61, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x6c, + 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x64, + 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x2b, 0x2e, 0x68, 0x65, + 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, + 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x79, 0x0a, 0x16, 0x53, 0x61, 0x76, 0x65, + 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x2d, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, + 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x82, 0x01, 0x0a, 0x19, 0x4d, 0x6f, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x6f, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x12, 0x30, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, + 0x74, 0x73, 0x2e, 0x4d, 0x6f, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x6f, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, + 0x67, 0x65, 0x74, 0x73, 0x2e, 0x4d, 0x6f, 0x76, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x6f, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x12, 0x2b, 0x2e, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, + 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, + 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x40, 0x5a, + 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x77, + 0x79, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x67, 0x65, + 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x69, 0x6f, 0x73, 0x2f, 0x77, 0x69, + 0x64, 0x67, 0x65, 0x74, 0x73, 0x3b, 0x70, 0x62, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_helios_widgets_widgetservice_proto_rawDescOnce sync.Once + file_helios_widgets_widgetservice_proto_rawDescData = file_helios_widgets_widgetservice_proto_rawDesc +) + +func file_helios_widgets_widgetservice_proto_rawDescGZIP() []byte { + file_helios_widgets_widgetservice_proto_rawDescOnce.Do(func() { + file_helios_widgets_widgetservice_proto_rawDescData = protoimpl.X.CompressGZIP(file_helios_widgets_widgetservice_proto_rawDescData) + }) + return file_helios_widgets_widgetservice_proto_rawDescData +} + +var file_helios_widgets_widgetservice_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_helios_widgets_widgetservice_proto_goTypes = []any{ + (*ListAppContextsRequest)(nil), // 0: helios.widgets.ListAppContextsRequest + (*ListAppContextsResponse)(nil), // 1: helios.widgets.ListAppContextsResponse + (*ListSpacesRequest)(nil), // 2: helios.widgets.ListSpacesRequest + (*ListSpacesResponse)(nil), // 3: helios.widgets.ListSpacesResponse + (*AddSpaceRequest)(nil), // 4: helios.widgets.AddSpaceRequest + (*AddSpaceResponse)(nil), // 5: helios.widgets.AddSpaceResponse + (*UpdateSpaceRequest)(nil), // 6: helios.widgets.UpdateSpaceRequest + (*UpdateSpaceResponse)(nil), // 7: helios.widgets.UpdateSpaceResponse + (*DeleteSpaceRequest)(nil), // 8: helios.widgets.DeleteSpaceRequest + (*DeleteSpaceResponse)(nil), // 9: helios.widgets.DeleteSpaceResponse + (*ReorderSpacesRequest)(nil), // 10: helios.widgets.ReorderSpacesRequest + (*ReorderSpacesResponse)(nil), // 11: helios.widgets.ReorderSpacesResponse + (*CreateWidgetInstanceRequest)(nil), // 12: helios.widgets.CreateWidgetInstanceRequest + (*CreateWidgetInstanceResponse)(nil), // 13: helios.widgets.CreateWidgetInstanceResponse + (*SaveWidgetInstanceDataRequest)(nil), // 14: helios.widgets.SaveWidgetInstanceDataRequest + (*SaveWidgetInstanceDataResponse)(nil), // 15: helios.widgets.SaveWidgetInstanceDataResponse + (*MoveWidgetInstanceToSpaceRequest)(nil), // 16: helios.widgets.MoveWidgetInstanceToSpaceRequest + (*MoveWidgetInstanceToSpaceResponse)(nil), // 17: helios.widgets.MoveWidgetInstanceToSpaceResponse + (*DeleteWidgetInstanceRequest)(nil), // 18: helios.widgets.DeleteWidgetInstanceRequest + (*DeleteWidgetInstanceResponse)(nil), // 19: helios.widgets.DeleteWidgetInstanceResponse + (*AppContext)(nil), // 20: helios.widgets.AppContext + (*Space)(nil), // 21: helios.widgets.Space + (WidgetSizeVariant)(0), // 22: helios.widgets.WidgetSizeVariant + (*WidgetInstance)(nil), // 23: helios.widgets.WidgetInstance +} +var file_helios_widgets_widgetservice_proto_depIdxs = []int32{ + 20, // 0: helios.widgets.ListAppContextsResponse.app_contexts:type_name -> helios.widgets.AppContext + 21, // 1: helios.widgets.ListSpacesResponse.spaces:type_name -> helios.widgets.Space + 21, // 2: helios.widgets.AddSpaceResponse.space:type_name -> helios.widgets.Space + 21, // 3: helios.widgets.UpdateSpaceResponse.space:type_name -> helios.widgets.Space + 22, // 4: helios.widgets.CreateWidgetInstanceRequest.widget_size_variant:type_name -> helios.widgets.WidgetSizeVariant + 23, // 5: helios.widgets.CreateWidgetInstanceResponse.widget_instance:type_name -> helios.widgets.WidgetInstance + 0, // 6: helios.widgets.WidgetService.ListAppContexts:input_type -> helios.widgets.ListAppContextsRequest + 2, // 7: helios.widgets.WidgetService.ListSpaces:input_type -> helios.widgets.ListSpacesRequest + 4, // 8: helios.widgets.WidgetService.AddSpace:input_type -> helios.widgets.AddSpaceRequest + 6, // 9: helios.widgets.WidgetService.UpdateSpace:input_type -> helios.widgets.UpdateSpaceRequest + 8, // 10: helios.widgets.WidgetService.DeleteSpace:input_type -> helios.widgets.DeleteSpaceRequest + 10, // 11: helios.widgets.WidgetService.ReorderSpaces:input_type -> helios.widgets.ReorderSpacesRequest + 12, // 12: helios.widgets.WidgetService.CreateWidgetInstance:input_type -> helios.widgets.CreateWidgetInstanceRequest + 14, // 13: helios.widgets.WidgetService.SaveWidgetInstanceData:input_type -> helios.widgets.SaveWidgetInstanceDataRequest + 16, // 14: helios.widgets.WidgetService.MoveWidgetInstanceToSpace:input_type -> helios.widgets.MoveWidgetInstanceToSpaceRequest + 18, // 15: helios.widgets.WidgetService.DeleteWidgetInstance:input_type -> helios.widgets.DeleteWidgetInstanceRequest + 1, // 16: helios.widgets.WidgetService.ListAppContexts:output_type -> helios.widgets.ListAppContextsResponse + 3, // 17: helios.widgets.WidgetService.ListSpaces:output_type -> helios.widgets.ListSpacesResponse + 5, // 18: helios.widgets.WidgetService.AddSpace:output_type -> helios.widgets.AddSpaceResponse + 7, // 19: helios.widgets.WidgetService.UpdateSpace:output_type -> helios.widgets.UpdateSpaceResponse + 9, // 20: helios.widgets.WidgetService.DeleteSpace:output_type -> helios.widgets.DeleteSpaceResponse + 11, // 21: helios.widgets.WidgetService.ReorderSpaces:output_type -> helios.widgets.ReorderSpacesResponse + 13, // 22: helios.widgets.WidgetService.CreateWidgetInstance:output_type -> helios.widgets.CreateWidgetInstanceResponse + 15, // 23: helios.widgets.WidgetService.SaveWidgetInstanceData:output_type -> helios.widgets.SaveWidgetInstanceDataResponse + 17, // 24: helios.widgets.WidgetService.MoveWidgetInstanceToSpace:output_type -> helios.widgets.MoveWidgetInstanceToSpaceResponse + 19, // 25: helios.widgets.WidgetService.DeleteWidgetInstance:output_type -> helios.widgets.DeleteWidgetInstanceResponse + 16, // [16:26] is the sub-list for method output_type + 6, // [6:16] 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_helios_widgets_widgetservice_proto_init() } +func file_helios_widgets_widgetservice_proto_init() { + if File_helios_widgets_widgetservice_proto != nil { + return + } + file_helios_widgets_widgets_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_helios_widgets_widgetservice_proto_rawDesc, + NumEnums: 0, + NumMessages: 20, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_helios_widgets_widgetservice_proto_goTypes, + DependencyIndexes: file_helios_widgets_widgetservice_proto_depIdxs, + MessageInfos: file_helios_widgets_widgetservice_proto_msgTypes, + }.Build() + File_helios_widgets_widgetservice_proto = out.File + file_helios_widgets_widgetservice_proto_rawDesc = nil + file_helios_widgets_widgetservice_proto_goTypes = nil + file_helios_widgets_widgetservice_proto_depIdxs = nil +} diff --git a/go/genproto/helios/widgets/widgetservice_grpc.pb.go b/go/genproto/helios/widgets/widgetservice_grpc.pb.go new file mode 100644 index 0000000..0a34858 --- /dev/null +++ b/go/genproto/helios/widgets/widgetservice_grpc.pb.go @@ -0,0 +1,477 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: helios/widgets/widgetservice.proto + +package pbwidgets + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + WidgetService_ListAppContexts_FullMethodName = "/helios.widgets.WidgetService/ListAppContexts" + WidgetService_ListSpaces_FullMethodName = "/helios.widgets.WidgetService/ListSpaces" + WidgetService_AddSpace_FullMethodName = "/helios.widgets.WidgetService/AddSpace" + WidgetService_UpdateSpace_FullMethodName = "/helios.widgets.WidgetService/UpdateSpace" + WidgetService_DeleteSpace_FullMethodName = "/helios.widgets.WidgetService/DeleteSpace" + WidgetService_ReorderSpaces_FullMethodName = "/helios.widgets.WidgetService/ReorderSpaces" + WidgetService_CreateWidgetInstance_FullMethodName = "/helios.widgets.WidgetService/CreateWidgetInstance" + WidgetService_SaveWidgetInstanceData_FullMethodName = "/helios.widgets.WidgetService/SaveWidgetInstanceData" + WidgetService_MoveWidgetInstanceToSpace_FullMethodName = "/helios.widgets.WidgetService/MoveWidgetInstanceToSpace" + WidgetService_DeleteWidgetInstance_FullMethodName = "/helios.widgets.WidgetService/DeleteWidgetInstance" +) + +// WidgetServiceClient is the client API for WidgetService 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. +// +// Requires authed human. +type WidgetServiceClient interface { + ListAppContexts(ctx context.Context, in *ListAppContextsRequest, opts ...grpc.CallOption) (*ListAppContextsResponse, error) + // All spaces & attached widget instances for the authed human. + ListSpaces(ctx context.Context, in *ListSpacesRequest, opts ...grpc.CallOption) (*ListSpacesResponse, error) + AddSpace(ctx context.Context, in *AddSpaceRequest, opts ...grpc.CallOption) (*AddSpaceResponse, error) + // Authoritative: please define every field, otherwise they will be overwritten as empty. + UpdateSpace(ctx context.Context, in *UpdateSpaceRequest, opts ...grpc.CallOption) (*UpdateSpaceResponse, error) + // Deletes space and all widget instances within. + DeleteSpace(ctx context.Context, in *DeleteSpaceRequest, opts ...grpc.CallOption) (*DeleteSpaceResponse, error) + // All existing spaces for human must be provided. + ReorderSpaces(ctx context.Context, in *ReorderSpacesRequest, opts ...grpc.CallOption) (*ReorderSpacesResponse, error) + // Create a widget instance and set it's initial space + CreateWidgetInstance(ctx context.Context, in *CreateWidgetInstanceRequest, opts ...grpc.CallOption) (*CreateWidgetInstanceResponse, error) + SaveWidgetInstanceData(ctx context.Context, in *SaveWidgetInstanceDataRequest, opts ...grpc.CallOption) (*SaveWidgetInstanceDataResponse, error) + MoveWidgetInstanceToSpace(ctx context.Context, in *MoveWidgetInstanceToSpaceRequest, opts ...grpc.CallOption) (*MoveWidgetInstanceToSpaceResponse, error) + DeleteWidgetInstance(ctx context.Context, in *DeleteWidgetInstanceRequest, opts ...grpc.CallOption) (*DeleteWidgetInstanceResponse, error) +} + +type widgetServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewWidgetServiceClient(cc grpc.ClientConnInterface) WidgetServiceClient { + return &widgetServiceClient{cc} +} + +func (c *widgetServiceClient) ListAppContexts(ctx context.Context, in *ListAppContextsRequest, opts ...grpc.CallOption) (*ListAppContextsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListAppContextsResponse) + err := c.cc.Invoke(ctx, WidgetService_ListAppContexts_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) ListSpaces(ctx context.Context, in *ListSpacesRequest, opts ...grpc.CallOption) (*ListSpacesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListSpacesResponse) + err := c.cc.Invoke(ctx, WidgetService_ListSpaces_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) AddSpace(ctx context.Context, in *AddSpaceRequest, opts ...grpc.CallOption) (*AddSpaceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddSpaceResponse) + err := c.cc.Invoke(ctx, WidgetService_AddSpace_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) UpdateSpace(ctx context.Context, in *UpdateSpaceRequest, opts ...grpc.CallOption) (*UpdateSpaceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSpaceResponse) + err := c.cc.Invoke(ctx, WidgetService_UpdateSpace_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) DeleteSpace(ctx context.Context, in *DeleteSpaceRequest, opts ...grpc.CallOption) (*DeleteSpaceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSpaceResponse) + err := c.cc.Invoke(ctx, WidgetService_DeleteSpace_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) ReorderSpaces(ctx context.Context, in *ReorderSpacesRequest, opts ...grpc.CallOption) (*ReorderSpacesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReorderSpacesResponse) + err := c.cc.Invoke(ctx, WidgetService_ReorderSpaces_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) CreateWidgetInstance(ctx context.Context, in *CreateWidgetInstanceRequest, opts ...grpc.CallOption) (*CreateWidgetInstanceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateWidgetInstanceResponse) + err := c.cc.Invoke(ctx, WidgetService_CreateWidgetInstance_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) SaveWidgetInstanceData(ctx context.Context, in *SaveWidgetInstanceDataRequest, opts ...grpc.CallOption) (*SaveWidgetInstanceDataResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SaveWidgetInstanceDataResponse) + err := c.cc.Invoke(ctx, WidgetService_SaveWidgetInstanceData_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) MoveWidgetInstanceToSpace(ctx context.Context, in *MoveWidgetInstanceToSpaceRequest, opts ...grpc.CallOption) (*MoveWidgetInstanceToSpaceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(MoveWidgetInstanceToSpaceResponse) + err := c.cc.Invoke(ctx, WidgetService_MoveWidgetInstanceToSpace_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *widgetServiceClient) DeleteWidgetInstance(ctx context.Context, in *DeleteWidgetInstanceRequest, opts ...grpc.CallOption) (*DeleteWidgetInstanceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteWidgetInstanceResponse) + err := c.cc.Invoke(ctx, WidgetService_DeleteWidgetInstance_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// WidgetServiceServer is the server API for WidgetService service. +// All implementations must embed UnimplementedWidgetServiceServer +// for forward compatibility. +// +// Requires authed human. +type WidgetServiceServer interface { + ListAppContexts(context.Context, *ListAppContextsRequest) (*ListAppContextsResponse, error) + // All spaces & attached widget instances for the authed human. + ListSpaces(context.Context, *ListSpacesRequest) (*ListSpacesResponse, error) + AddSpace(context.Context, *AddSpaceRequest) (*AddSpaceResponse, error) + // Authoritative: please define every field, otherwise they will be overwritten as empty. + UpdateSpace(context.Context, *UpdateSpaceRequest) (*UpdateSpaceResponse, error) + // Deletes space and all widget instances within. + DeleteSpace(context.Context, *DeleteSpaceRequest) (*DeleteSpaceResponse, error) + // All existing spaces for human must be provided. + ReorderSpaces(context.Context, *ReorderSpacesRequest) (*ReorderSpacesResponse, error) + // Create a widget instance and set it's initial space + CreateWidgetInstance(context.Context, *CreateWidgetInstanceRequest) (*CreateWidgetInstanceResponse, error) + SaveWidgetInstanceData(context.Context, *SaveWidgetInstanceDataRequest) (*SaveWidgetInstanceDataResponse, error) + MoveWidgetInstanceToSpace(context.Context, *MoveWidgetInstanceToSpaceRequest) (*MoveWidgetInstanceToSpaceResponse, error) + DeleteWidgetInstance(context.Context, *DeleteWidgetInstanceRequest) (*DeleteWidgetInstanceResponse, error) + mustEmbedUnimplementedWidgetServiceServer() +} + +// UnimplementedWidgetServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedWidgetServiceServer struct{} + +func (UnimplementedWidgetServiceServer) ListAppContexts(context.Context, *ListAppContextsRequest) (*ListAppContextsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListAppContexts not implemented") +} +func (UnimplementedWidgetServiceServer) ListSpaces(context.Context, *ListSpacesRequest) (*ListSpacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListSpaces not implemented") +} +func (UnimplementedWidgetServiceServer) AddSpace(context.Context, *AddSpaceRequest) (*AddSpaceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddSpace not implemented") +} +func (UnimplementedWidgetServiceServer) UpdateSpace(context.Context, *UpdateSpaceRequest) (*UpdateSpaceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSpace not implemented") +} +func (UnimplementedWidgetServiceServer) DeleteSpace(context.Context, *DeleteSpaceRequest) (*DeleteSpaceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSpace not implemented") +} +func (UnimplementedWidgetServiceServer) ReorderSpaces(context.Context, *ReorderSpacesRequest) (*ReorderSpacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReorderSpaces not implemented") +} +func (UnimplementedWidgetServiceServer) CreateWidgetInstance(context.Context, *CreateWidgetInstanceRequest) (*CreateWidgetInstanceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateWidgetInstance not implemented") +} +func (UnimplementedWidgetServiceServer) SaveWidgetInstanceData(context.Context, *SaveWidgetInstanceDataRequest) (*SaveWidgetInstanceDataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SaveWidgetInstanceData not implemented") +} +func (UnimplementedWidgetServiceServer) MoveWidgetInstanceToSpace(context.Context, *MoveWidgetInstanceToSpaceRequest) (*MoveWidgetInstanceToSpaceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MoveWidgetInstanceToSpace not implemented") +} +func (UnimplementedWidgetServiceServer) DeleteWidgetInstance(context.Context, *DeleteWidgetInstanceRequest) (*DeleteWidgetInstanceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteWidgetInstance not implemented") +} +func (UnimplementedWidgetServiceServer) mustEmbedUnimplementedWidgetServiceServer() {} +func (UnimplementedWidgetServiceServer) testEmbeddedByValue() {} + +// UnsafeWidgetServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to WidgetServiceServer will +// result in compilation errors. +type UnsafeWidgetServiceServer interface { + mustEmbedUnimplementedWidgetServiceServer() +} + +func RegisterWidgetServiceServer(s grpc.ServiceRegistrar, srv WidgetServiceServer) { + // If the following call pancis, it indicates UnimplementedWidgetServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&WidgetService_ServiceDesc, srv) +} + +func _WidgetService_ListAppContexts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListAppContextsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).ListAppContexts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_ListAppContexts_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).ListAppContexts(ctx, req.(*ListAppContextsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_ListSpaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSpacesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).ListSpaces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_ListSpaces_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).ListSpaces(ctx, req.(*ListSpacesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_AddSpace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddSpaceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).AddSpace(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_AddSpace_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).AddSpace(ctx, req.(*AddSpaceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_UpdateSpace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSpaceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).UpdateSpace(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_UpdateSpace_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).UpdateSpace(ctx, req.(*UpdateSpaceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_DeleteSpace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSpaceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).DeleteSpace(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_DeleteSpace_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).DeleteSpace(ctx, req.(*DeleteSpaceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_ReorderSpaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReorderSpacesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).ReorderSpaces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_ReorderSpaces_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).ReorderSpaces(ctx, req.(*ReorderSpacesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_CreateWidgetInstance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateWidgetInstanceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).CreateWidgetInstance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_CreateWidgetInstance_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).CreateWidgetInstance(ctx, req.(*CreateWidgetInstanceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_SaveWidgetInstanceData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SaveWidgetInstanceDataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).SaveWidgetInstanceData(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_SaveWidgetInstanceData_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).SaveWidgetInstanceData(ctx, req.(*SaveWidgetInstanceDataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_MoveWidgetInstanceToSpace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MoveWidgetInstanceToSpaceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).MoveWidgetInstanceToSpace(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_MoveWidgetInstanceToSpace_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).MoveWidgetInstanceToSpace(ctx, req.(*MoveWidgetInstanceToSpaceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WidgetService_DeleteWidgetInstance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteWidgetInstanceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WidgetServiceServer).DeleteWidgetInstance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WidgetService_DeleteWidgetInstance_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WidgetServiceServer).DeleteWidgetInstance(ctx, req.(*DeleteWidgetInstanceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// WidgetService_ServiceDesc is the grpc.ServiceDesc for WidgetService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var WidgetService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "helios.widgets.WidgetService", + HandlerType: (*WidgetServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListAppContexts", + Handler: _WidgetService_ListAppContexts_Handler, + }, + { + MethodName: "ListSpaces", + Handler: _WidgetService_ListSpaces_Handler, + }, + { + MethodName: "AddSpace", + Handler: _WidgetService_AddSpace_Handler, + }, + { + MethodName: "UpdateSpace", + Handler: _WidgetService_UpdateSpace_Handler, + }, + { + MethodName: "DeleteSpace", + Handler: _WidgetService_DeleteSpace_Handler, + }, + { + MethodName: "ReorderSpaces", + Handler: _WidgetService_ReorderSpaces_Handler, + }, + { + MethodName: "CreateWidgetInstance", + Handler: _WidgetService_CreateWidgetInstance_Handler, + }, + { + MethodName: "SaveWidgetInstanceData", + Handler: _WidgetService_SaveWidgetInstanceData_Handler, + }, + { + MethodName: "MoveWidgetInstanceToSpace", + Handler: _WidgetService_MoveWidgetInstanceToSpace_Handler, + }, + { + MethodName: "DeleteWidgetInstance", + Handler: _WidgetService_DeleteWidgetInstance_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helios/widgets/widgetservice.proto", +} diff --git a/go/go.mod b/go/go.mod new file mode 100644 index 0000000..07d9c46 --- /dev/null +++ b/go/go.mod @@ -0,0 +1,108 @@ +module github.com/flowy-live/llink + +go 1.25 + +require ( + cloud.google.com/go/storage v1.59.1 + github.com/golang-migrate/migrate/v4 v4.19.1 + github.com/google/uuid v1.6.0 + github.com/jackc/pgx/v5 v5.7.2 + github.com/redis/go-redis/v9 v9.17.2 + github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.11.1 + github.com/testcontainers/testcontainers-go v0.40.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 + go.jetify.com/typeid v1.3.0 + google.golang.org/grpc v1.78.0 + google.golang.org/protobuf v1.36.11 +) + +require ( + cel.dev/expr v0.24.0 // indirect + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.17.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.5.3 // indirect + cloud.google.com/go/monitoring v1.24.2 // indirect + dario.cat/mergo v1.0.2 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.1+incompatible // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/gofrs/uuid/v5 v5.2.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shirou/gopsutil/v4 v4.25.6 // indirect + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/time v0.14.0 // indirect + google.golang.org/api v0.256.0 // indirect + google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go/go.sum b/go/go.sum new file mode 100644 index 0000000..a97c5d0 --- /dev/null +++ b/go/go.sum @@ -0,0 +1,273 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= +cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= +cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.7.0 h1:FV0+SYF1RIj59gyoWDRi45GiYUMM3K1qO51qoboQT1E= +cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY= +cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= +cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/storage v1.59.1 h1:DXAZLcTimtiXdGqDSnebROVPd9QvRsFVVlptz02Wk58= +cloud.google.com/go/storage v1.59.1/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= +cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= +cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4= +github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= +github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs= +github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= +github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM= +github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= +github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= +github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI= +github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= +github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= +github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0/go.mod h1:h+u/2KoREGTnTl9UwrQ/g+XhasAT8E6dClclAADeXoQ= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.jetify.com/typeid v1.3.0 h1:fuWV7oxO4mSsgpxwhaVpFXgt0IfjogR29p+XAjDCVKY= +go.jetify.com/typeid v1.3.0/go.mod h1:CtVGyt2+TSp4Rq5+ARLvGsJqdNypKBAC6INQ9TLPlmk= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= +go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.256.0 h1:u6Khm8+F9sxbCTYNoBHg6/Hwv0N/i+V94MvkOSor6oI= +google.golang.org/api v0.256.0/go.mod h1:KIgPhksXADEKJlnEoRa9qAII4rXcy40vfI8HRqcU964= +google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 h1:LvZVVaPE0JSqL+ZWb6ErZfnEOKIqqFWUJE2D0fObSmc= +google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9/go.mod h1:QFOrLhdAe2PsTp3vQY4quuLKTi9j3XG3r6JPPaw7MSc= +google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E= +google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +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= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= diff --git a/go/internal/auth/service.go b/go/internal/auth/service.go new file mode 100644 index 0000000..3a1a72e --- /dev/null +++ b/go/internal/auth/service.go @@ -0,0 +1,199 @@ +package auth + +import ( + "context" + "errors" + "fmt" + "log/slog" + "strings" + "time" + + "github.com/flowy-live/llink/genproto/aero" + "github.com/flowy-live/llink/internal/utils" + "github.com/redis/go-redis/v9" + "go.jetify.com/typeid" +) + +const ( + sessionExpiry = time.Hour * 24 * 15 + extendSessionThreshold = time.Hour * 24 * 3 + codeExpiry = time.Minute * 15 +) + +var ( + ErrInvalidCode = errors.New("invalid code") + ErrSessionNotFound = errors.New("session not found") +) + +type sessionTokenPrefix struct{} + +func (sessionTokenPrefix) Prefix() string { return "session" } + +type sessionToken struct { + typeid.TypeID[sessionTokenPrefix] +} + +func newSessionToken() (sessionToken, error) { + return typeid.New[sessionToken]() +} + +type AuthService interface { + // RequestSignInCode generates a code and emails it to the provided email. + // To retrieve a session, client must verify with VerifySignInCode. + RequestSignInCode(ctx context.Context, email string) error + // VerifySignInCode returns ErrInvalidCode if incorrect code + VerifySignInCode(ctx context.Context, email, code string) (sessionToken string, err error) + // GetSession returns ErrSessionNotFound if no valid session + GetSession(ctx context.Context, sessionToken string) (email string, err error) + // ExtendSession returns ErrSessionNotFound if no valid session + ExtendSession(ctx context.Context, sessionToken string) error + SignOut(ctx context.Context, sessionToken string) error + + IsSystemAdmin(ctx context.Context, email string) bool +} + +type authServiceImpl struct { + redisClient *redis.Client + aeroSvc pbaero.PrimaryClient +} + +func NewAuthService(redisClient *redis.Client, aeroSvc pbaero.PrimaryClient) AuthService { + return &authServiceImpl{redisClient: redisClient, aeroSvc: aeroSvc} +} + +func (a *authServiceImpl) IsSystemAdmin(ctx context.Context, email string) bool { + formattedEmail, err := utils.NormalizeEmail(email) + if err != nil { + slog.Error("problem validating email", "error", err) + return false + } + + if strings.Contains(formattedEmail, "@flowylabs.ai") { + return true + } + return false +} + +func (a *authServiceImpl) RequestSignInCode(ctx context.Context, email string) error { + if email == "" { + return errors.New("email is required") + } + + code := utils.RandomStringNumbers(4) + + formattedEmail, err := utils.NormalizeEmail(email) + if err != nil { + return errors.New("email is not valid") + } + + err = a.redisClient.Set(ctx, formattedEmail, code, codeExpiry).Err() + if err != nil { + slog.Error("error setting code in redis", "error", err) + return fmt.Errorf("error storing sign-in code: %w", err) + } + + message := fmt.Sprintf("Here is your one-time code for signing into Flowy: %s\n\nPlease do not share this with anyone.\n\nBest, \nFlowy Team", code) + subject := fmt.Sprintf("Sign In - Your One-Time Code for Flowy.llink") + _, err = a.aeroSvc.ShootEmail(ctx, &pbaero.ShootEmailRequest{ + ToEmails: []string{formattedEmail}, + Subject: subject, + TemplateData: &pbaero.ShootEmailRequest_SimpleTextData{ + SimpleTextData: &pbaero.SimpleTextData{ + Message: message, + }, + }, + }) + if err != nil { + return fmt.Errorf("an error occurred while sending the email: %w", err) + } + + slog.Info("sent sign in code", "email", formattedEmail) + return nil +} + +func (a *authServiceImpl) VerifySignInCode(ctx context.Context, email, code string) (string, error) { + formattedEmail, err := utils.NormalizeEmail(email) + if err != nil { + return "", fmt.Errorf("invalid email: %w", err) + } + + storedCode, err := a.redisClient.Get(ctx, formattedEmail).Result() + if err != nil { + if errors.Is(err, redis.Nil) { + return "", ErrInvalidCode + } + slog.Error("error getting code from redis", "error", err) + return "", fmt.Errorf("error verifying code: %w", err) + } + + if storedCode != code { + return "", ErrInvalidCode + } + + if err := a.redisClient.Del(ctx, formattedEmail).Err(); err != nil { + slog.Error("error deleting code from redis", "error", err) + } + + token, err := a.createSession(ctx, formattedEmail) + if err != nil { + return "", err + } + + return token, nil +} + +func (a *authServiceImpl) GetSession(ctx context.Context, token string) (string, error) { + email, err := a.redisClient.Get(ctx, token).Result() + if err != nil { + if errors.Is(err, redis.Nil) { + return "", ErrSessionNotFound + } + return "", fmt.Errorf("error getting session: %w", err) + } + + return email, nil +} + +func (a *authServiceImpl) ExtendSession(ctx context.Context, token string) error { + ttl, err := a.redisClient.TTL(ctx, token).Result() + if err != nil { + return fmt.Errorf("error checking session TTL: %w", err) + } + + if ttl < 0 { + return ErrSessionNotFound + } + + if ttl < extendSessionThreshold { + if err := a.redisClient.Expire(ctx, token, sessionExpiry).Err(); err != nil { + return fmt.Errorf("error extending session: %w", err) + } + } + + return nil +} + +func (a *authServiceImpl) SignOut(ctx context.Context, token string) error { + if err := a.redisClient.Del(ctx, token).Err(); err != nil { + return fmt.Errorf("error deleting session: %w", err) + } + return nil +} + +func (a *authServiceImpl) createSession(ctx context.Context, email string) (string, error) { + formattedEmail, err := utils.NormalizeEmail(email) + if err != nil { + return "", fmt.Errorf("invalid email: %w", err) + } + + token, err := newSessionToken() + if err != nil { + return "", fmt.Errorf("error generating session token: %w", err) + } + + if err := a.redisClient.Set(ctx, token.String(), formattedEmail, sessionExpiry).Err(); err != nil { + return "", fmt.Errorf("error storing session: %w", err) + } + + return token.String(), nil +} diff --git a/go/internal/db/connect.go b/go/internal/db/connect.go new file mode 100644 index 0000000..672371f --- /dev/null +++ b/go/internal/db/connect.go @@ -0,0 +1,44 @@ +package db + +import ( + "context" + "log/slog" + "os" + + "github.com/jackc/pgx/v5/pgxpool" +) + +var db *pgxpool.Pool + +func Cleanup() { + db.Close() +} + +func Pool() *pgxpool.Pool { + return db +} + +func Init() { + connString := os.Getenv("LLINK_POSTGRES_CONNECTION_URL") + if connString == "" { + slog.Error("must provide LLINK_POSTGRES_CONNECTION_URL in env") + os.Exit(1) + } + + dbpool, err := pgxpool.New(context.Background(), connString) + if err != nil { + slog.Error("unable to create connection pool", "error", err) + os.Exit(1) + } + + var greeting string + err = dbpool.QueryRow(context.Background(), "select 'Hello, world!'").Scan(&greeting) + if err != nil { + slog.Error("queryRow failed", "error", err) + os.Exit(1) + } + + slog.Info("successfully connected to database", "greeting", greeting) + + db = dbpool +} diff --git a/go/internal/depot/errors.go b/go/internal/depot/errors.go new file mode 100644 index 0000000..a866cd6 --- /dev/null +++ b/go/internal/depot/errors.go @@ -0,0 +1,8 @@ +package depot + +import "errors" + +var ( + ErrNotFound = errors.New("object not found") + ErrInvalidInput = errors.New("invalid input") +) diff --git a/go/internal/depot/models.go b/go/internal/depot/models.go new file mode 100644 index 0000000..3f11d1e --- /dev/null +++ b/go/internal/depot/models.go @@ -0,0 +1,38 @@ +package depot + +import "time" + +// Object represents a stored object in the depot +type Object struct { + ID string + Name string + ContentType string + ContentLength int64 + BucketName string + ObjectKey string + ContainsContent bool + CreatedAt time.Time +} + +// PrepareUploadInput represents the input for preparing an upload +type PrepareUploadInput struct { + Prefix string // Optional prefix for organizing objects (e.g., network_id) + Name string + ContentType string + ContentLength int64 +} + +// PrepareUploadResult represents the result of preparing an upload +type PrepareUploadResult struct { + ObjectID string + UploadURL string + UploadHeaders map[string]string +} + +// Config holds configuration for the depot service +type Config struct { + GoogleServiceAccountEmail string + BucketName string + UploadURLExpiry time.Duration + DownloadURLExpiry time.Duration +} diff --git a/go/internal/depot/repository.go b/go/internal/depot/repository.go new file mode 100644 index 0000000..c411f96 --- /dev/null +++ b/go/internal/depot/repository.go @@ -0,0 +1,112 @@ +package depot + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + "go.jetify.com/typeid" +) + +var errNotFound = errors.New("not found") + +type depotIDPrefix struct{} + +func (depotIDPrefix) Prefix() string { return "dpo" } + +type depotID struct { + typeid.TypeID[depotIDPrefix] +} + +func newDepotID() (depotID, error) { + return typeid.New[depotID]() +} + +type repository interface { + create(ctx context.Context, obj *Object) (*Object, error) + getByID(ctx context.Context, id string) (*Object, error) + setContainsContent(ctx context.Context, id string, containsContent bool) error + delete(ctx context.Context, id string) error + exists(ctx context.Context, id string) (bool, error) +} + +type repositoryImpl struct { + pool *pgxpool.Pool +} + +func newRepository(pool *pgxpool.Pool) repository { + return &repositoryImpl{pool: pool} +} + +func (r *repositoryImpl) create(ctx context.Context, obj *Object) (*Object, error) { + id, err := newDepotID() + if err != nil { + return nil, err + } + + var result Object + err = r.pool.QueryRow(ctx, + `INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id, name, content_type, content_length, bucket_name, object_key, contains_content, created_at`, + id.String(), obj.Name, obj.ContentType, obj.ContentLength, obj.BucketName, obj.ObjectKey, obj.ContainsContent, + ).Scan(&result.ID, &result.Name, &result.ContentType, &result.ContentLength, + &result.BucketName, &result.ObjectKey, &result.ContainsContent, &result.CreatedAt) + if err != nil { + return nil, err + } + + return &result, nil +} + +func (r *repositoryImpl) getByID(ctx context.Context, id string) (*Object, error) { + var obj Object + err := r.pool.QueryRow(ctx, + `SELECT id, name, content_type, content_length, bucket_name, object_key, contains_content, created_at + FROM depot_objects WHERE id = $1`, + id, + ).Scan(&obj.ID, &obj.Name, &obj.ContentType, &obj.ContentLength, + &obj.BucketName, &obj.ObjectKey, &obj.ContainsContent, &obj.CreatedAt) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, errNotFound + } + return nil, err + } + return &obj, nil +} + +func (r *repositoryImpl) setContainsContent(ctx context.Context, id string, containsContent bool) error { + result, err := r.pool.Exec(ctx, + `UPDATE depot_objects SET contains_content = $1 WHERE id = $2`, + containsContent, id, + ) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) delete(ctx context.Context, id string) error { + result, err := r.pool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) exists(ctx context.Context, id string) (bool, error) { + var exists bool + err := r.pool.QueryRow(ctx, + `SELECT EXISTS(SELECT 1 FROM depot_objects WHERE id = $1)`, + id, + ).Scan(&exists) + return exists, err +} diff --git a/go/internal/depot/service.go b/go/internal/depot/service.go new file mode 100644 index 0000000..a9c1290 --- /dev/null +++ b/go/internal/depot/service.go @@ -0,0 +1,221 @@ +package depot + +import ( + "context" + "errors" + "fmt" + "log/slog" + "time" + + "cloud.google.com/go/storage" + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgxpool" +) + +const ( + defaultUploadURLExpiry = 15 * time.Minute + defaultDownloadURLExpiry = 24 * time.Hour +) + +type Service interface { + PrepareUpload(ctx context.Context, input PrepareUploadInput) (*PrepareUploadResult, error) + ConfirmUpload(ctx context.Context, objectID string) (*Object, error) + GetByID(ctx context.Context, objectID string) (*Object, error) + GetDownloadURL(ctx context.Context, objectID string) (string, error) + Delete(ctx context.Context, objectID string) error + Exists(ctx context.Context, objectID string) (bool, error) +} + +type serviceImpl struct { + repo repository + storageClient *storage.Client + bucketName string + uploadURLExpiry time.Duration + downloadURLExpiry time.Duration + googleServiceAccountEmail string +} + +func NewService(pool *pgxpool.Pool, storageClient *storage.Client, config Config) Service { + uploadExpiry := config.UploadURLExpiry + if uploadExpiry == 0 { + uploadExpiry = defaultUploadURLExpiry + } + + downloadExpiry := config.DownloadURLExpiry + if downloadExpiry == 0 { + downloadExpiry = defaultDownloadURLExpiry + } + + if config.GoogleServiceAccountEmail == "" { + slog.Error("GoogleServiceAccountEmail is not set in config. Signed URLs may not work if the storage client is not properly authenticated with a service account.") + panic("GoogleServiceAccountEmail is required for signed URL generation") + } + + return &serviceImpl{ + repo: newRepository(pool), + storageClient: storageClient, + bucketName: config.BucketName, + uploadURLExpiry: uploadExpiry, + downloadURLExpiry: downloadExpiry, + googleServiceAccountEmail: config.GoogleServiceAccountEmail, + } +} + +func (s *serviceImpl) PrepareUpload(ctx context.Context, input PrepareUploadInput) (*PrepareUploadResult, error) { + if input.Name == "" { + return nil, errors.Join(ErrInvalidInput, errors.New("name is required")) + } + if input.ContentType == "" { + return nil, errors.Join(ErrInvalidInput, errors.New("content_type is required")) + } + if input.ContentLength <= 0 { + return nil, errors.Join(ErrInvalidInput, errors.New("content_length must be positive")) + } + + // Generate object key: {prefix}/{uuid}/{filename} + objectKey := fmt.Sprintf("%s/%s/%s", input.Prefix, uuid.New().String(), input.Name) + + // Create the database record (contains_content = false initially) + obj := &Object{ + Name: input.Name, + ContentType: input.ContentType, + ContentLength: input.ContentLength, + BucketName: s.bucketName, + ObjectKey: objectKey, + ContainsContent: false, + } + + created, err := s.repo.create(ctx, obj) + if err != nil { + return nil, err + } + + // Generate a signed URL for uploading with Content-Length enforcement + // The Headers field specifies headers that MUST be included in the upload request + contentLengthHeader := fmt.Sprintf("Content-Length:%d", input.ContentLength) + uploadURL, err := s.storageClient.Bucket(s.bucketName).SignedURL(objectKey, &storage.SignedURLOptions{ + GoogleAccessID: s.googleServiceAccountEmail, + Method: "PUT", + Expires: time.Now().Add(s.uploadURLExpiry), + ContentType: input.ContentType, + Headers: []string{contentLengthHeader}, + }) + if err != nil { + slog.Error("failed to generate signed upload URL", "error", err, "bucket", s.bucketName, "object_key", objectKey) + // Clean up the database record if we can't generate the URL + if delErr := s.repo.delete(ctx, created.ID); delErr != nil { + slog.Warn("failed to cleanup db record after signed URL failure", "error", delErr, "object_id", created.ID) + } + return nil, err + } + + return &PrepareUploadResult{ + ObjectID: created.ID, + UploadURL: uploadURL, + UploadHeaders: map[string]string{ + "Content-Type": input.ContentType, + "Content-Length": fmt.Sprintf("%d", input.ContentLength), + }, + }, nil +} + +func (s *serviceImpl) ConfirmUpload(ctx context.Context, objectID string) (*Object, error) { + obj, err := s.repo.getByID(ctx, objectID) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + + // Verify the object exists in GCS and check its size matches expected + attrs, err := s.storageClient.Bucket(obj.BucketName).Object(obj.ObjectKey).Attrs(ctx) + if err != nil { + if errors.Is(err, storage.ErrObjectNotExist) { + return nil, errors.Join(ErrNotFound, errors.New("object not found in storage")) + } + slog.Error("failed to get GCS object attrs", "error", err, "bucket", obj.BucketName, "object_key", obj.ObjectKey) + return nil, err + } + + // Verify content length matches what was declared + if attrs.Size != obj.ContentLength { + return nil, errors.Join(ErrInvalidInput, fmt.Errorf("content length mismatch: expected %d, got %d", obj.ContentLength, attrs.Size)) + } + + // Mark as containing content + if err := s.repo.setContainsContent(ctx, objectID, true); err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + + // Fetch and return the updated object + return s.repo.getByID(ctx, objectID) +} + +func (s *serviceImpl) GetByID(ctx context.Context, objectID string) (*Object, error) { + obj, err := s.repo.getByID(ctx, objectID) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + return obj, nil +} + +func (s *serviceImpl) GetDownloadURL(ctx context.Context, objectID string) (string, error) { + obj, err := s.repo.getByID(ctx, objectID) + if err != nil { + if errors.Is(err, errNotFound) { + return "", ErrNotFound + } + return "", err + } + + // Generate a signed URL for downloading + downloadURL, err := s.storageClient.Bucket(obj.BucketName).SignedURL(obj.ObjectKey, &storage.SignedURLOptions{ + GoogleAccessID: s.googleServiceAccountEmail, + Method: "GET", + Expires: time.Now().Add(s.downloadURLExpiry), + }) + if err != nil { + slog.Error("failed to generate signed download URL", "error", err, "bucket", obj.BucketName, "object_key", obj.ObjectKey) + return "", err + } + + return downloadURL, nil +} + +func (s *serviceImpl) Delete(ctx context.Context, objectID string) error { + obj, err := s.repo.getByID(ctx, objectID) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + // Delete from GCS (ignore not found errors) + gcsErr := s.storageClient.Bucket(obj.BucketName).Object(obj.ObjectKey).Delete(ctx) + if gcsErr != nil && !errors.Is(gcsErr, storage.ErrObjectNotExist) { + slog.Error("failed to delete object from GCS", "error", gcsErr, "bucket", obj.BucketName, "object_key", obj.ObjectKey) + return gcsErr + } + + // Delete from database + if err := s.repo.delete(ctx, objectID); err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + return nil +} + +func (s *serviceImpl) Exists(ctx context.Context, objectID string) (bool, error) { + return s.repo.exists(ctx, objectID) +} diff --git a/go/internal/depot/service_test.go b/go/internal/depot/service_test.go new file mode 100644 index 0000000..650ba63 --- /dev/null +++ b/go/internal/depot/service_test.go @@ -0,0 +1,250 @@ +package depot_test + +import ( + "context" + "os" + "testing" + "time" + + "github.com/flowy-live/llink/internal/depot" + "github.com/flowy-live/llink/internal/testhelper" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/stretchr/testify/assert" +) + +var dbPool *pgxpool.Pool + +func TestMain(m *testing.M) { + dbPool = testhelper.SetupTestDB() + defer testhelper.TeardownTestDB() + + ret := m.Run() + os.Exit(ret) +} + +// TestDepotRepository tests the repository layer directly +// These tests can run without GCS since they only test database operations +func TestDepotRepository_CreateAndGet(t *testing.T) { + ctx := context.Background() + + // Create a depot object directly in the database for testing + var id string + err := dbPool.QueryRow(ctx, + `INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id`, + "dpo_test123", "test-file.txt", "text/plain", int64(1024), "test-bucket", "test-key-123", false, + ).Scan(&id) + assert.NoError(t, err) + assert.Equal(t, "dpo_test123", id) + + // Query the object back + var obj struct { + ID string + Name string + ContentType string + ContentLength int64 + BucketName string + ObjectKey string + ContainsContent bool + CreatedAt time.Time + } + err = dbPool.QueryRow(ctx, + `SELECT id, name, content_type, content_length, bucket_name, object_key, contains_content, created_at + FROM depot_objects WHERE id = $1`, + id, + ).Scan(&obj.ID, &obj.Name, &obj.ContentType, &obj.ContentLength, + &obj.BucketName, &obj.ObjectKey, &obj.ContainsContent, &obj.CreatedAt) + assert.NoError(t, err) + assert.Equal(t, "test-file.txt", obj.Name) + assert.Equal(t, "text/plain", obj.ContentType) + assert.Equal(t, int64(1024), obj.ContentLength) + assert.Equal(t, "test-bucket", obj.BucketName) + assert.Equal(t, "test-key-123", obj.ObjectKey) + assert.False(t, obj.ContainsContent) + assert.False(t, obj.CreatedAt.IsZero()) + + // Clean up + _, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id) + assert.NoError(t, err) +} + +func TestDepotRepository_ConfirmUpload(t *testing.T) { + ctx := context.Background() + + // Create a depot object + var id string + err := dbPool.QueryRow(ctx, + `INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id`, + "dpo_confirm123", "confirm-file.txt", "text/plain", int64(2048), "test-bucket", "confirm-key", false, + ).Scan(&id) + assert.NoError(t, err) + + // Verify it starts with contains_content = false + var containsContent bool + err = dbPool.QueryRow(ctx, + `SELECT contains_content FROM depot_objects WHERE id = $1`, + id, + ).Scan(&containsContent) + assert.NoError(t, err) + assert.False(t, containsContent) + + // Confirm upload + _, err = dbPool.Exec(ctx, + `UPDATE depot_objects SET contains_content = TRUE WHERE id = $1`, + id, + ) + assert.NoError(t, err) + + // Verify it's now true + err = dbPool.QueryRow(ctx, + `SELECT contains_content FROM depot_objects WHERE id = $1`, + id, + ).Scan(&containsContent) + assert.NoError(t, err) + assert.True(t, containsContent) + + // Clean up + _, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id) + assert.NoError(t, err) +} + +func TestDepotRepository_Delete(t *testing.T) { + ctx := context.Background() + + // Create a depot object + var id string + err := dbPool.QueryRow(ctx, + `INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id`, + "dpo_delete123", "delete-file.txt", "text/plain", int64(512), "test-bucket", "delete-key", false, + ).Scan(&id) + assert.NoError(t, err) + + // Delete it + result, err := dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id) + assert.NoError(t, err) + assert.Equal(t, int64(1), result.RowsAffected()) + + // Verify it's gone + var count int + err = dbPool.QueryRow(ctx, + `SELECT COUNT(*) FROM depot_objects WHERE id = $1`, + id, + ).Scan(&count) + assert.NoError(t, err) + assert.Equal(t, 0, count) +} + +func TestDepotRepository_Exists(t *testing.T) { + ctx := context.Background() + + // Create a depot object + var id string + err := dbPool.QueryRow(ctx, + `INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id`, + "dpo_exists123", "exists-file.txt", "text/plain", int64(256), "test-bucket", "exists-key", true, + ).Scan(&id) + assert.NoError(t, err) + + // Check exists + var exists bool + err = dbPool.QueryRow(ctx, + `SELECT EXISTS(SELECT 1 FROM depot_objects WHERE id = $1)`, + id, + ).Scan(&exists) + assert.NoError(t, err) + assert.True(t, exists) + + // Check non-existent + err = dbPool.QueryRow(ctx, + `SELECT EXISTS(SELECT 1 FROM depot_objects WHERE id = $1)`, + "dpo_nonexistent", + ).Scan(&exists) + assert.NoError(t, err) + assert.False(t, exists) + + // Clean up + _, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id) + assert.NoError(t, err) +} + +func TestDepotRepository_OrphanedIndex(t *testing.T) { + ctx := context.Background() + + // Create an orphaned object (contains_content = false) + var orphanID string + err := dbPool.QueryRow(ctx, + `INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id`, + "dpo_orphan123", "orphan-file.txt", "text/plain", int64(128), "test-bucket", "orphan-key", false, + ).Scan(&orphanID) + assert.NoError(t, err) + + // Create a confirmed object (contains_content = true) + var confirmedID string + err = dbPool.QueryRow(ctx, + `INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id`, + "dpo_confirmed123", "confirmed-file.txt", "text/plain", int64(128), "test-bucket", "confirmed-key", true, + ).Scan(&confirmedID) + assert.NoError(t, err) + + // Query orphaned objects using the index + rows, err := dbPool.Query(ctx, + `SELECT id FROM depot_objects WHERE contains_content = FALSE`) + assert.NoError(t, err) + defer rows.Close() + + var orphanedIDs []string + for rows.Next() { + var id string + err := rows.Scan(&id) + assert.NoError(t, err) + orphanedIDs = append(orphanedIDs, id) + } + + // Our orphan should be in the list + assert.Contains(t, orphanedIDs, orphanID) + assert.NotContains(t, orphanedIDs, confirmedID) + + // Clean up + _, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id IN ($1, $2)`, orphanID, confirmedID) + assert.NoError(t, err) +} + +// TestDepotModels tests the model structures +func TestDepotModels(t *testing.T) { + // Test Config defaults + config := depot.Config{ + BucketName: "test-bucket", + } + assert.Equal(t, "test-bucket", config.BucketName) + assert.Equal(t, time.Duration(0), config.UploadURLExpiry) + assert.Equal(t, time.Duration(0), config.DownloadURLExpiry) + + // Test with explicit values + config = depot.Config{ + BucketName: "custom-bucket", + UploadURLExpiry: 10 * time.Minute, + DownloadURLExpiry: 12 * time.Hour, + } + assert.Equal(t, "custom-bucket", config.BucketName) + assert.Equal(t, 10*time.Minute, config.UploadURLExpiry) + assert.Equal(t, 12*time.Hour, config.DownloadURLExpiry) +} + +// TestDepotErrors tests the error definitions +func TestDepotErrors(t *testing.T) { + assert.Error(t, depot.ErrNotFound) + assert.Error(t, depot.ErrInvalidInput) + assert.Equal(t, "object not found", depot.ErrNotFound.Error()) + assert.Equal(t, "invalid input", depot.ErrInvalidInput.Error()) +} diff --git a/go/internal/handler/handler.go b/go/internal/handler/handler.go new file mode 100644 index 0000000..e1f2e37 --- /dev/null +++ b/go/internal/handler/handler.go @@ -0,0 +1,2053 @@ +package handler + +import ( + "context" + "encoding/json" + "errors" + "log/slog" + "net/http" + "strings" + "time" + + "github.com/flowy-live/llink/internal/auth" + "github.com/flowy-live/llink/internal/depot" + "github.com/flowy-live/llink/internal/human" + "github.com/flowy-live/llink/internal/middleware" + "github.com/flowy-live/llink/internal/network" + "github.com/flowy-live/llink/internal/particle" + "github.com/flowy-live/llink/internal/utils" +) + +type Handler struct { + authSvc auth.AuthService + humanSvc human.Service + networkSvc network.Service + particleSvc particle.Service + depotSvc depot.Service +} + +func NewHandler(authSvc auth.AuthService, humanSvc human.Service, networkSvc network.Service, particleSvc particle.Service, depotSvc depot.Service) *Handler { + return &Handler{ + authSvc: authSvc, + humanSvc: humanSvc, + networkSvc: networkSvc, + particleSvc: particleSvc, + depotSvc: depotSvc, + } +} + +// Response DTOs + +type Human struct { + // Id will be nil if this human is not registered + Id *string `json:"id"` + Email string `json:"email"` + EmailPrefix string `json:"email_prefix"` + CreatedAt *time.Time `json:"created_at"` +} + +type Network struct { + Id string `json:"id"` + Name string `json:"name"` + AdminHuman Human `json:"admin_human"` + Humans []Human `json:"humans"` + OpenStreamCount int `json:"open_stream_count"` + OpenStreamCapacity int `json:"open_stream_capacity"` + CreatedAt time.Time `json:"created_at"` +} + +type StreamParticle struct { + Id string `json:"id"` + Type string `json:"type"` + Data json.RawMessage `json:"data"` + CreatedByEmail string `json:"created_by_email"` + Seen bool `json:"seen"` + Acks []*AckInfo `json:"acks"` + UpdatedAt time.Time `json:"updated_at"` + CreatedAt time.Time `json:"created_at"` +} + +type Particle struct { + Id string `json:"id"` + Type string `json:"type"` + Data json.RawMessage `json:"data"` + CreatedByEmail string `json:"created_by_email"` + Visibility string `json:"visibility"` + Members []string `json:"members,omitempty"` + StreamStatus *string `json:"stream_status,omitempty"` + Seen bool `json:"seen,omitempty"` + Acks []*AckInfo `json:"acks,omitempty"` + UnseenCount *int `json:"unseen_count,omitempty"` + UpdatedAt time.Time `json:"updated_at"` + CreatedAt time.Time `json:"created_at"` +} + +type Stream struct { + Id string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Status StreamStatus `json:"status"` + // The emails of the members in this stream + Members []string `json:"members,omitempty"` + Particles []*StreamParticle `json:"particles"` + UnseenCount int `json:"unseen_count"` +} + +type StreamStatus string + +const ( + STREAM_STATUS_OPEN StreamStatus = "open" + STREAM_STATUS_CLOSED StreamStatus = "closed" + STREAM_STATUS_UNSPECIFIED StreamStatus = "unspecified" +) + +type NetworkWithStreams struct { + Network + Streams []*Stream `json:"streams"` +} + +type StartData struct { + Networks []*NetworkWithStreams `json:"networks"` +} + +type AckInfo struct { + Email string `json:"email"` + AckedAt time.Time `json:"acked_at"` +} + +type ParticleList struct { + Particles []Particle `json:"particles"` + HasMore bool `json:"has_more"` + NextCursor *string `json:"next_cursor,omitempty"` + PrevCursor *string `json:"prev_cursor,omitempty"` +} + +// Auth Request/Response DTOs + +type RequestSignInCodeRequest struct { + Email string `json:"email"` +} + +type SignInRequest struct { + Email string `json:"email"` + Code string `json:"code"` +} + +type SignInResponse struct { + Human Human `json:"human"` + Token string `json:"token"` +} + +// Network Request DTOs + +type CreateNetworkRequest struct { + Name string `json:"name"` +} + +type AddMembersToNetworkRequest struct { + EmailAddresses []string `json:"email_addresses"` +} + +type SetOpenStreamCapacityRequest struct { + Capacity int `json:"capacity"` +} + +// Particle Request DTOs + +type CreateStreamParticleRequest struct { + Type string `json:"type"` + Data json.RawMessage `json:"data"` +} + +type CreateStreamRequest struct { + Name string `json:"name"` + Description string `json:"description"` + Visibility string `json:"visibility"` + Members []string `json:"members"` +} + +type UpdateStreamRequest struct { + Name *string `json:"name"` + Description *string `json:"description"` +} + +type UpdateParticleRequest struct { + Data json.RawMessage `json:"data"` +} + +type MembersRequest struct { + Emails []string `json:"emails"` +} + +type MarkSeenBatchRequest struct { + ParticleIDs []string `json:"particle_ids"` +} + +// Depot DTOs + +type PrepareUploadRequest struct { + NetworkId string `json:"network_id"` + Name string `json:"name"` + ContentType string `json:"content_type"` + ContentLength int64 `json:"content_length"` +} + +type PrepareUploadResponse struct { + ObjectID string `json:"object_id"` + UploadURL string `json:"upload_url"` + UploadHeaders map[string]string `json:"upload_headers"` +} + +type DepotObject struct { + ID string `json:"id"` + Name string `json:"name"` + ContentType string `json:"content_type"` + ContentLength int64 `json:"content_length"` + ContainsContent bool `json:"contains_content"` + DownloadURL string `json:"download_url,omitempty"` + CreatedAt time.Time `json:"created_at"` +} + +// ============================================================================ +// Auth Handlers +// ============================================================================ + +// RequestSignInCode creates a human account if not already existent and sends a sign-in code +func (h *Handler) RequestSignInCode(w http.ResponseWriter, r *http.Request) { + var req RequestSignInCodeRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if req.Email == "" { + http.Error(w, "email is required", http.StatusBadRequest) + return + } + + // Auto-create human if doesn't exist + _, err := h.humanSvc.GetOrCreateByEmail(r.Context(), req.Email) + if err != nil { + slog.Error("failed to get or create human", "error", err, "email", req.Email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Request sign-in code + if err := h.authSvc.RequestSignInCode(r.Context(), req.Email); err != nil { + slog.Error("failed to request sign-in code", "error", err, "email", req.Email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// SignIn verifies the code and returns a session token +func (h *Handler) SignIn(w http.ResponseWriter, r *http.Request) { + var req SignInRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if req.Email == "" || req.Code == "" { + http.Error(w, "email and code are required", http.StatusBadRequest) + return + } + + token, err := h.authSvc.VerifySignInCode(r.Context(), req.Email, req.Code) + if err != nil { + if errors.Is(err, auth.ErrInvalidCode) { + http.Error(w, "invalid code", http.StatusUnauthorized) + return + } + slog.Error("failed to verify sign-in code", "error", err, "email", req.Email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Get the human + hum, err := h.humanSvc.GetByEmail(r.Context(), req.Email) + if err != nil { + slog.Error("failed to get human after sign-in", "error", err, "email", req.Email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp := SignInResponse{ + Human: humanToDTO(hum), + Token: token, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// SignOut deletes the session from the token in headers +func (h *Handler) SignOut(w http.ResponseWriter, r *http.Request) { + token := extractBearerToken(r) + if token == "" { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + if err := h.authSvc.SignOut(r.Context(), token); err != nil { + slog.Error("failed to sign out", "error", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) StartupData(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networks, err := h.networkSvc.ListForEmail(r.Context(), email) + if err != nil { + http.Error(w, "unable to fetch networks", http.StatusInternalServerError) + return + } + + data := StartData{ + Networks: make([]*NetworkWithStreams, 0, len(networks)), + } + + streamFilter := particle.ListFilter{ + Types: []particle.ParticleType{particle.TypeStream}, + } + + for _, net := range networks { + networkDTO, err := h.networkToDTO(r.Context(), net) + if err != nil { + slog.Error("unable to convert db network to dto", "error", err, "network_id", net.ID) + continue + } + + nws := &NetworkWithStreams{ + Network: networkDTO, + } + + // Fetch all top-level streams for this network + streams, err := h.listAllParticles(r.Context(), net.ID, nil, email, streamFilter) + if err != nil { + slog.Error("unable to list streams for network", "error", err, "network_id", net.ID) + data.Networks = append(data.Networks, nws) + continue + } + + // Collect stream IDs for unseen counts + streamIDs := make([]string, len(streams)) + for i, s := range streams { + streamIDs[i] = s.ID + } + + // Get unseen counts and members for all streams in this network + var unseenCounts map[string]int + var streamMembersMap map[string][]string + if len(streamIDs) > 0 { + unseenCounts, err = h.particleSvc.GetUnseenCounts(r.Context(), net.ID, streamIDs, email) + if err != nil { + slog.Warn("failed to get unseen counts for streams", "error", err, "network_id", net.ID) + unseenCounts = make(map[string]int) + } + + streamMembersMap, err = h.particleSvc.GetMembersMap(r.Context(), streamIDs) + if err != nil { + slog.Warn("failed to get members map for streams", "error", err, "network_id", net.ID) + streamMembersMap = make(map[string][]string) + } + } + + nws.Streams = make([]*Stream, 0, len(streams)) + for _, sp := range streams { + // Parse stream metadata from particle data + var streamData particle.StreamData + if err := json.Unmarshal(sp.Data, &streamData); err != nil { + slog.Warn("failed to parse stream data", "error", err, "particle_id", sp.ID) + } + + status := parseStreamStatus(streamData.Status) + + stream := &Stream{ + Id: sp.ID, + Name: streamData.Name, + Description: utils.OptionalString(streamData.Description), + Status: status, + Members: h.getStreamMembers(r.Context(), sp, streamMembersMap), + UnseenCount: unseenCounts[sp.ID], + } + + // Fetch child particles for this stream + children, err := h.listAllParticles(r.Context(), net.ID, &sp.ID, email, particle.ListFilter{}) + if err != nil { + slog.Error("unable to list particles for stream", "error", err, "stream_id", sp.ID) + nws.Streams = append(nws.Streams, stream) + continue + } + + // Collect child particle IDs for bulk enrichment + childIDs := make([]string, len(children)) + for i, p := range children { + childIDs[i] = p.ID + } + + seenMap, err := h.particleSvc.GetSeenMap(r.Context(), childIDs, email) + if err != nil { + slog.Warn("failed to get seen map", "error", err) + seenMap = make(map[string]bool) + } + + acksMap, err := h.particleSvc.GetAcksMap(r.Context(), childIDs) + if err != nil { + slog.Warn("failed to get acks map", "error", err) + acksMap = make(map[string][]particle.AckInfo) + } + + // Build enriched particle DTOs + stream.Particles = make([]*StreamParticle, 0, len(children)) + for _, p := range children { + dto := h.streamParticleToDTO(r.Context(), p) + + if seen, ok := seenMap[p.ID]; ok { + dto.Seen = seen + } + + if acks, ok := acksMap[p.ID]; ok && len(acks) > 0 { + dto.Acks = make([]*AckInfo, len(acks)) + for i, a := range acks { + dto.Acks[i] = &AckInfo{Email: a.Email, AckedAt: a.AckedAt} + } + } else { + dto.Acks = []*AckInfo{} + } + + stream.Particles = append(stream.Particles, &dto) + } + + nws.Streams = append(nws.Streams, stream) + } + + data.Networks = append(data.Networks, nws) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(data) +} + +func (h *Handler) CreateStream(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networkID := r.PathValue("network_id") + if networkID == "" { + http.Error(w, "network_id is required", http.StatusBadRequest) + return + } + + // Check network membership + isMember, err := h.networkSvc.IsMember(r.Context(), networkID, email) + if err != nil { + slog.Error("failed to check network membership", "error", err, "network_id", networkID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !isMember { + http.Error(w, "access denied", http.StatusForbidden) + return + } + + var req CreateStreamRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if req.Name == "" { + http.Error(w, "name is required", http.StatusBadRequest) + return + } + + streamData := &particle.StreamData{ + Name: req.Name, + Description: utils.CreateOptionalString(req.Description), + Status: string(particle.StreamStatusOpen), + } + data, err := json.Marshal(streamData) + if err != nil { + slog.Error("failed to marshal stream data", "error", err, "stream_name", req.Name) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + visibilityMode, err := particle.ParseVisibilityMode(req.Visibility) + if err != nil { + slog.Error("invalid visibility mode", "error", err, "visibility", req.Visibility) + http.Error(w, "invalid visibility mode", http.StatusBadRequest) + return + } + params := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: networkID, + ParentID: nil, + Data: data, + Members: req.Members, + Visibility: visibilityMode, + } + created, err := h.particleSvc.Create(r.Context(), params, email) + if err != nil { + if errors.Is(err, particle.ErrMembersRequired) { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if errors.Is(err, particle.ErrCapacityExceeded) { + http.Error(w, "stream capacity exceeded", http.StatusConflict) + return + } + if errors.Is(err, particle.ErrInvalidData) { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + slog.Error("failed to create stream particle", "error", err, "stream_name", req.Name, "network_id", networkID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Get members for the created stream + membersMap, _ := h.particleSvc.GetMembersMap(r.Context(), []string{created.ID}) + + var parsedData particle.StreamData + _ = json.Unmarshal(created.Data, &parsedData) + + resp := Stream{ + Id: created.ID, + Name: parsedData.Name, + Description: utils.OptionalString(parsedData.Description), + Status: parseStreamStatus(parsedData.Status), + Members: h.getStreamMembers(r.Context(), created, membersMap), + Particles: []*StreamParticle{}, + UnseenCount: 0, + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(resp) +} + +// GetStream returns a stream with its child particles, members, and unseen count +func (h *Handler) GetStream(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + streamID := r.PathValue("id") + if streamID == "" { + http.Error(w, "stream id is required", http.StatusBadRequest) + return + } + + // Get the stream particle and verify access + sp, err := h.particleSvc.GetByID(r.Context(), streamID, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "stream not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to get stream", "error", err, "stream_id", streamID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + if sp.Type != particle.TypeStream { + http.Error(w, "particle is not a stream", http.StatusBadRequest) + return + } + + // Parse stream data + var streamData particle.StreamData + if err := json.Unmarshal(sp.Data, &streamData); err != nil { + slog.Warn("failed to parse stream data", "error", err, "stream_id", streamID) + } + + // Get members + membersMap, err := h.particleSvc.GetMembersMap(r.Context(), []string{streamID}) + if err != nil { + slog.Warn("failed to get members for stream", "error", err, "stream_id", streamID) + membersMap = make(map[string][]string) + } + + // Get unseen count + unseenCounts, err := h.particleSvc.GetUnseenCounts(r.Context(), sp.NetworkID, []string{streamID}, email) + if err != nil { + slog.Warn("failed to get unseen counts", "error", err, "stream_id", streamID) + unseenCounts = make(map[string]int) + } + + stream := &Stream{ + Id: sp.ID, + Name: streamData.Name, + Description: utils.OptionalString(streamData.Description), + Status: parseStreamStatus(streamData.Status), + Members: h.getStreamMembers(r.Context(), sp, membersMap), + UnseenCount: unseenCounts[sp.ID], + } + + // Fetch child particles + children, err := h.listAllParticles(r.Context(), sp.NetworkID, &sp.ID, email, particle.ListFilter{}) + if err != nil { + slog.Error("unable to list particles for stream", "error", err, "stream_id", sp.ID) + stream.Particles = []*StreamParticle{} + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(stream) + return + } + + // Collect child IDs for bulk enrichment + childIDs := make([]string, len(children)) + for i, p := range children { + childIDs[i] = p.ID + } + + seenMap, err := h.particleSvc.GetSeenMap(r.Context(), childIDs, email) + if err != nil { + slog.Warn("failed to get seen map", "error", err) + seenMap = make(map[string]bool) + } + + acksMap, err := h.particleSvc.GetAcksMap(r.Context(), childIDs) + if err != nil { + slog.Warn("failed to get acks map", "error", err) + acksMap = make(map[string][]particle.AckInfo) + } + + stream.Particles = make([]*StreamParticle, 0, len(children)) + for _, p := range children { + dto := h.streamParticleToDTO(r.Context(), p) + + if seen, ok := seenMap[p.ID]; ok { + dto.Seen = seen + } + + if acks, ok := acksMap[p.ID]; ok && len(acks) > 0 { + dto.Acks = make([]*AckInfo, len(acks)) + for i, a := range acks { + dto.Acks[i] = &AckInfo{Email: a.Email, AckedAt: a.AckedAt} + } + } else { + dto.Acks = []*AckInfo{} + } + + stream.Particles = append(stream.Particles, &dto) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(stream) +} + +// UpdateStream updates a stream's name and/or description (not status) +func (h *Handler) UpdateStream(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + streamID := r.PathValue("id") + if streamID == "" { + http.Error(w, "stream id is required", http.StatusBadRequest) + return + } + + var req UpdateStreamRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + // Get the existing stream to preserve status and merge fields + sp, err := h.particleSvc.GetByID(r.Context(), streamID, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "stream not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to get stream for update", "error", err, "stream_id", streamID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + if sp.Type != particle.TypeStream { + http.Error(w, "particle is not a stream", http.StatusBadRequest) + return + } + + // Parse existing data to preserve status + var existing particle.StreamData + if err := json.Unmarshal(sp.Data, &existing); err != nil { + slog.Error("failed to parse existing stream data", "error", err, "stream_id", streamID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Merge: only update fields that were provided + if req.Name != nil { + if *req.Name == "" { + http.Error(w, "name cannot be empty", http.StatusBadRequest) + return + } + existing.Name = *req.Name + } + if req.Description != nil { + existing.Description = utils.CreateOptionalString(*req.Description) + } + + newData, err := json.Marshal(existing) + if err != nil { + slog.Error("failed to marshal updated stream data", "error", err, "stream_id", streamID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + updated, err := h.particleSvc.Update(r.Context(), streamID, newData, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "stream not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + if errors.Is(err, particle.ErrInvalidData) { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + slog.Error("failed to update stream", "error", err, "stream_id", streamID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Build response + var parsedData particle.StreamData + _ = json.Unmarshal(updated.Data, &parsedData) + + membersMap, _ := h.particleSvc.GetMembersMap(r.Context(), []string{updated.ID}) + + unseenCounts, _ := h.particleSvc.GetUnseenCounts(r.Context(), updated.NetworkID, []string{updated.ID}, email) + + resp := Stream{ + Id: updated.ID, + Name: parsedData.Name, + Description: utils.OptionalString(parsedData.Description), + Status: parseStreamStatus(parsedData.Status), + Members: h.getStreamMembers(r.Context(), updated, membersMap), + Particles: []*StreamParticle{}, + UnseenCount: unseenCounts[updated.ID], + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// CreateStreamParticle creates a particle inside a stream +func (h *Handler) CreateStreamParticle(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + streamID := r.PathValue("id") + if streamID == "" { + http.Error(w, "stream id is required", http.StatusBadRequest) + return + } + + var req CreateStreamParticleRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + // Get the stream to find NetworkID and verify it's a stream + stream, err := h.particleSvc.GetByID(r.Context(), streamID, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "stream not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to get stream for particle creation", "error", err, "stream_id", streamID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + if stream.Type != particle.TypeStream { + http.Error(w, "particle is not a stream", http.StatusBadRequest) + return + } + + // Parse and validate particle type + particleType, err := particle.ParseParticleType(req.Type) + if err != nil { + http.Error(w, "invalid particle type", http.StatusBadRequest) + return + } + + // Reject streams and folders as children + if particleType == particle.TypeStream || particleType == particle.TypeFolder { + http.Error(w, "cannot create streams or folders inside a stream", http.StatusBadRequest) + return + } + + // For media/file types, validate object_id exists in depot + if req.Type == "media" || req.Type == "file" { + var data struct { + ObjectID string `json:"object_id"` + } + if err := json.Unmarshal(req.Data, &data); err == nil && data.ObjectID != "" { + exists, err := h.depotSvc.Exists(r.Context(), data.ObjectID) + if err != nil { + slog.Error("failed to check depot object existence", "error", err, "object_id", data.ObjectID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !exists { + http.Error(w, "object_id does not exist in depot", http.StatusBadRequest) + return + } + } + } + + // Service will force inherited visibility and nil members + input := particle.CreateInput{ + Type: particleType, + NetworkID: stream.NetworkID, + ParentID: &streamID, + Data: req.Data, + } + + created, err := h.particleSvc.Create(r.Context(), input, email) + if err != nil { + if errors.Is(err, particle.ErrInvalidType) || errors.Is(err, particle.ErrInvalidData) || errors.Is(err, particle.ErrInvalidParent) { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to create stream particle", "error", err, "stream_id", streamID, "type", req.Type, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp := h.streamParticleToDTO(r.Context(), created) + resp.Acks = []*AckInfo{} + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(resp) +} + +// GetCurrentHuman returns the authenticated human +func (h *Handler) GetCurrentHuman(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + hum, err := h.humanSvc.GetByEmail(r.Context(), email) + if err != nil { + if errors.Is(err, human.ErrNotFound) { + http.Error(w, "human not found", http.StatusNotFound) + return + } + slog.Error("failed to get current human", "error", err, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + dto := humanToDTO(hum) + json.NewEncoder(w).Encode(dto) +} + +// ============================================================================ +// Network Handlers +// ============================================================================ + +// CreateNetwork creates a new network +func (h *Handler) CreateNetwork(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + var req CreateNetworkRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + net, err := h.networkSvc.Create(r.Context(), req.Name, email) + if err != nil { + if errors.Is(err, network.ErrInvalidName) { + http.Error(w, "name cannot be empty", http.StatusBadRequest) + return + } + slog.Error("failed to create network", "error", err, "email", email, "name", req.Name) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp, err := h.networkToDTO(r.Context(), net) + if err != nil { + slog.Error("failed to convert network to DTO", "error", err, "network_id", net.ID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(resp) +} + +// ListNetworks retrieves networks for the authenticated human +func (h *Handler) ListNetworks(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networks, err := h.networkSvc.ListForEmail(r.Context(), email) + if err != nil { + slog.Error("failed to list networks", "error", err, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp := make([]Network, 0, len(networks)) + for _, net := range networks { + dto, err := h.networkToDTO(r.Context(), net) + if err != nil { + slog.Warn("failed to convert network to DTO in list", "error", err, "network_id", net.ID) + continue + } + resp = append(resp, dto) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// GetNetwork retrieves a specific network +func (h *Handler) GetNetwork(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networkID := r.PathValue("id") + if networkID == "" { + http.Error(w, "network id is required", http.StatusBadRequest) + return + } + + // Check membership + isMember, err := h.networkSvc.IsMember(r.Context(), networkID, email) + if err != nil { + slog.Error("failed to check network membership", "error", err, "network_id", networkID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !isMember { + http.Error(w, "access denied", http.StatusForbidden) + return + } + + net, err := h.networkSvc.GetByID(r.Context(), networkID) + if err != nil { + if errors.Is(err, network.ErrNotFound) { + http.Error(w, "network not found", http.StatusNotFound) + return + } + slog.Error("failed to get network", "error", err, "network_id", networkID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp, err := h.networkToDTO(r.Context(), net) + if err != nil { + slog.Error("failed to convert network to DTO", "error", err, "network_id", networkID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// AddMembersToNetwork adds members to a network +func (h *Handler) AddMembersToNetwork(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networkID := r.PathValue("id") + if networkID == "" { + http.Error(w, "network id is required", http.StatusBadRequest) + return + } + + // Check membership + isMember, err := h.networkSvc.IsMember(r.Context(), networkID, email) + if err != nil { + slog.Error("failed to check network membership", "error", err, "network_id", networkID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !isMember { + http.Error(w, "access denied", http.StatusForbidden) + return + } + + var req AddMembersToNetworkRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if len(req.EmailAddresses) == 0 { + http.Error(w, "email addresses are required", http.StatusBadRequest) + return + } + + if err := h.networkSvc.AddMembers(r.Context(), networkID, req.EmailAddresses); err != nil { + slog.Error("failed to add members to network", "error", err, "network_id", networkID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Return updated network + net, err := h.networkSvc.GetByID(r.Context(), networkID) + if err != nil { + slog.Error("failed to get network after adding members", "error", err, "network_id", networkID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp, err := h.networkToDTO(r.Context(), net) + if err != nil { + slog.Error("failed to convert network to DTO", "error", err, "network_id", networkID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// RemoveMemberFromNetwork removes a member from a network +func (h *Handler) RemoveMemberFromNetwork(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networkID := r.PathValue("id") + memberEmail := r.PathValue("email") + if networkID == "" || memberEmail == "" { + http.Error(w, "network id and member email are required", http.StatusBadRequest) + return + } + + // Check membership + isMember, err := h.networkSvc.IsMember(r.Context(), networkID, email) + if err != nil { + slog.Error("failed to check network membership", "error", err, "network_id", networkID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !isMember { + http.Error(w, "access denied", http.StatusForbidden) + return + } + + if err := h.networkSvc.RemoveMember(r.Context(), networkID, memberEmail); err != nil { + slog.Error("failed to remove member from network", "error", err, "network_id", networkID, "member_email", memberEmail) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// SetOpenStreamCapacity sets the open stream capacity for a network +func (h *Handler) SetOpenStreamCapacity(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networkID := r.PathValue("id") + if networkID == "" { + http.Error(w, "network id is required", http.StatusBadRequest) + return + } + + // Get network to check admin + net, err := h.networkSvc.GetByID(r.Context(), networkID) + if err != nil { + if errors.Is(err, network.ErrNotFound) { + http.Error(w, "network not found", http.StatusNotFound) + return + } + slog.Error("failed to get network for capacity update", "error", err, "network_id", networkID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Only admin can set capacity + if net.AdminEmail != email { + http.Error(w, "only admin can set capacity", http.StatusForbidden) + return + } + + var req SetOpenStreamCapacityRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if err := h.networkSvc.SetOpenStreamCapacity(r.Context(), networkID, req.Capacity); err != nil { + if errors.Is(err, network.ErrNotFound) { + http.Error(w, "network not found", http.StatusNotFound) + return + } + slog.Error("failed to set open stream capacity", "error", err, "network_id", networkID, "capacity", req.Capacity) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// ============================================================================ +// Particle Handlers +// ============================================================================ + +// ListParticles returns particles in a network +func (h *Handler) ListParticles(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + networkID := r.PathValue("network_id") + if networkID == "" { + http.Error(w, "network id is required", http.StatusBadRequest) + return + } + + // Check network membership + isMember, err := h.networkSvc.IsMember(r.Context(), networkID, email) + if err != nil { + slog.Error("failed to check network membership", "error", err, "network_id", networkID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !isMember { + http.Error(w, "access denied", http.StatusForbidden) + return + } + + // Parse query parameters + parentID := r.URL.Query().Get("parent_id") + var parentIDPtr *string + if parentID != "" { + parentIDPtr = &parentID + } + + // Parse cursor + var cursor *particle.Cursor + cursorStr := r.URL.Query().Get("cursor") + direction := r.URL.Query().Get("direction") + if cursorStr != "" { + cursor = &particle.Cursor{ + Position: cursorStr, + Direction: direction, + } + if cursor.Direction == "" { + cursor.Direction = "after" + } + } + + // Parse type filter + filter := particle.ListFilter{} + typeFilter := r.URL.Query()["type"] + for _, t := range typeFilter { + pt, err := particle.ParseParticleType(t) + if err != nil { + http.Error(w, "invalid particle type: "+t, http.StatusBadRequest) + return + } + filter.Types = append(filter.Types, pt) + } + + list, err := h.particleSvc.List(r.Context(), networkID, parentIDPtr, email, filter, cursor, 50) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "parent not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to list particles", "error", err, "network_id", networkID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Extract particle IDs for enrichment + particleIDs := make([]string, len(list.Particles)) + streamIDs := make([]string, 0) + for i, p := range list.Particles { + particleIDs[i] = p.ID + if p.Type == particle.TypeStream { + streamIDs = append(streamIDs, p.ID) + } + } + + // Get seen map for enrichment + seenMap, err := h.particleSvc.GetSeenMap(r.Context(), particleIDs, email) + if err != nil { + slog.Warn("failed to get seen map", "error", err) + seenMap = make(map[string]bool) + } + + // Get acks map for enrichment + acksMap, err := h.particleSvc.GetAcksMap(r.Context(), particleIDs) + if err != nil { + slog.Warn("failed to get acks map", "error", err) + acksMap = make(map[string][]particle.AckInfo) + } + + // Get members map for enrichment + membersMap, err := h.particleSvc.GetMembersMap(r.Context(), particleIDs) + if err != nil { + slog.Warn("failed to get members map", "error", err) + membersMap = make(map[string][]string) + } + + // Get unseen counts for streams + var unseenCounts map[string]int + if len(streamIDs) > 0 { + unseenCounts, err = h.particleSvc.GetUnseenCounts(r.Context(), networkID, streamIDs, email) + if err != nil { + slog.Warn("failed to get unseen counts", "error", err) + unseenCounts = make(map[string]int) + } + } + + resp := ParticleList{ + Particles: make([]Particle, 0, len(list.Particles)), + HasMore: list.HasMore, + } + + for _, p := range list.Particles { + dto := h.particleToDTO(r.Context(), p) + + // Enrich with seen status + seen, ok := seenMap[p.ID] + if ok { + dto.Seen = seen + } + + // Enrich with acks + if acks, ok := acksMap[p.ID]; ok && len(acks) > 0 { + dto.Acks = make([]*AckInfo, len(acks)) + for i, a := range acks { + dto.Acks[i] = &AckInfo{Email: a.Email, AckedAt: a.AckedAt} + } + } + + // Enrich with members + if members, ok := membersMap[p.ID]; ok && len(members) > 0 { + dto.Members = members + } + + // Enrich with unseen count for streams + if p.Type == particle.TypeStream { + count := unseenCounts[p.ID] + dto.UnseenCount = &count + } + + resp.Particles = append(resp.Particles, dto) + } + + if list.NextCursor != nil { + encoded := list.NextCursor.Position + ":" + list.NextCursor.Direction + resp.NextCursor = &encoded + } + if list.PrevCursor != nil { + encoded := list.PrevCursor.Position + ":" + list.PrevCursor.Direction + resp.PrevCursor = &encoded + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// GetParticle gets the details of a particle +func (h *Handler) GetParticle(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + p, err := h.particleSvc.GetByID(r.Context(), particleID, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to get particle", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Verify network membership + isMember, err := h.networkSvc.IsMember(r.Context(), p.NetworkID, email) + if err != nil { + slog.Error("failed to check network membership", "error", err, "network_id", p.NetworkID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !isMember { + http.Error(w, "access denied", http.StatusForbidden) + return + } + + resp := h.particleToDTO(r.Context(), p) + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// UpdateParticle updates the data of a particle +func (h *Handler) UpdateParticle(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + var req UpdateParticleRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + updated, err := h.particleSvc.Update(r.Context(), particleID, req.Data, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + if errors.Is(err, particle.ErrInvalidData) { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + slog.Error("failed to update particle", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp := h.particleToDTO(r.Context(), updated) + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// DeleteParticle deletes a particle and cascades to depot if applicable +func (h *Handler) DeleteParticle(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + // Get particle first to check for object_id (for cascade delete) + p, err := h.particleSvc.GetByID(r.Context(), particleID, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to get particle for deletion", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Extract object_id if media/file + objectID := extractObjectID(p) + + // Delete particle + if err := h.particleSvc.Delete(r.Context(), particleID, email); err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to delete particle", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Cascade delete depot object if applicable + if objectID != "" { + if err := h.depotSvc.Delete(r.Context(), objectID); err != nil { + slog.Warn("failed to cascade delete depot object", "error", err, "object_id", objectID, "particle_id", particleID) + } + } + + w.WriteHeader(http.StatusNoContent) +} + +// OpenStream opens a stream particle +func (h *Handler) OpenStream(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + if err := h.particleSvc.OpenStream(r.Context(), particleID, email); err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + if errors.Is(err, particle.ErrNotAStream) { + http.Error(w, "particle is not a stream", http.StatusBadRequest) + return + } + if errors.Is(err, particle.ErrStreamAlreadyOpen) { + http.Error(w, "stream is already open", http.StatusConflict) + return + } + if errors.Is(err, particle.ErrCapacityExceeded) { + http.Error(w, "stream capacity exceeded", http.StatusConflict) + return + } + slog.Error("failed to open stream", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// CloseStream closes a stream particle +func (h *Handler) CloseStream(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + if err := h.particleSvc.CloseStream(r.Context(), particleID, email); err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + if errors.Is(err, particle.ErrNotAStream) { + http.Error(w, "particle is not a stream", http.StatusBadRequest) + return + } + if errors.Is(err, particle.ErrStreamAlreadyClosed) { + http.Error(w, "stream is already closed", http.StatusConflict) + return + } + slog.Error("failed to close stream", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// AddMembers adds members to a particle with custom visibility +func (h *Handler) AddMembers(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + var req MembersRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if len(req.Emails) == 0 { + http.Error(w, "emails are required", http.StatusBadRequest) + return + } + + if err := h.particleSvc.AddMembers(r.Context(), particleID, req.Emails, email); err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + if errors.Is(err, particle.ErrNotAContainer) { + http.Error(w, "only streams can have members", http.StatusBadRequest) + return + } + slog.Error("failed to add members to particle", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// RemoveMembers removes members from a particle with custom visibility +func (h *Handler) RemoveMembers(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + var req MembersRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if len(req.Emails) == 0 { + http.Error(w, "emails are required", http.StatusBadRequest) + return + } + + if err := h.particleSvc.RemoveMembers(r.Context(), particleID, req.Emails, email); err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + if errors.Is(err, particle.ErrNotAContainer) { + http.Error(w, "only streams can have members", http.StatusBadRequest) + return + } + slog.Error("failed to remove members from particle", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// MarkSeen marks a particle as seen by the requester +func (h *Handler) MarkSeen(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + if err := h.particleSvc.MarkSeen(r.Context(), particleID, email); err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to mark particle as seen", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// MarkSeenBatch marks multiple particles as seen by the requester +func (h *Handler) MarkSeenBatch(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + var req MarkSeenBatchRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if len(req.ParticleIDs) == 0 { + http.Error(w, "particle_ids are required", http.StatusBadRequest) + return + } + + if err := h.particleSvc.MarkSeenBatch(r.Context(), req.ParticleIDs, email); err != nil { + slog.Error("failed to mark particles as seen", "error", err, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// AckParticle acknowledges a particle (public, permanent) +func (h *Handler) AckParticle(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + if err := h.particleSvc.Ack(r.Context(), particleID, email); err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to ack particle", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// DownloadParticle redirects to a fresh signed download URL for media/file particles +func (h *Handler) DownloadParticle(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + particleID := r.PathValue("id") + if particleID == "" { + http.Error(w, "particle id is required", http.StatusBadRequest) + return + } + + p, err := h.particleSvc.GetByID(r.Context(), particleID, email) + if err != nil { + if errors.Is(err, particle.ErrNotFound) { + http.Error(w, "particle not found", http.StatusNotFound) + return + } + if errors.Is(err, particle.ErrAccessDenied) { + http.Error(w, "access denied", http.StatusForbidden) + return + } + slog.Error("failed to get particle for download", "error", err, "particle_id", particleID, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + objectID := extractObjectID(p) + if objectID == "" { + http.Error(w, "particle has no downloadable content", http.StatusBadRequest) + return + } + + downloadURL, err := h.depotSvc.GetDownloadURL(r.Context(), objectID) + if err != nil { + slog.Error("failed to get download URL", "error", err, "object_id", objectID, "particle_id", particleID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + http.Redirect(w, r, downloadURL, http.StatusFound) +} + +// ============================================================================ +// Depot Handlers +// ============================================================================ + +// PrepareUpload prepares an upload and returns a signed URL for direct upload to GCS +func (h *Handler) PrepareUpload(w http.ResponseWriter, r *http.Request) { + email, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + var req PrepareUploadRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if req.NetworkId == "" { + http.Error(w, "network_id is required", http.StatusBadRequest) + return + } + + // Check network membership + isMember, err := h.networkSvc.IsMember(r.Context(), req.NetworkId, email) + if err != nil { + slog.Error("failed to check network membership", "error", err, "network_id", req.NetworkId, "email", email) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if !isMember { + http.Error(w, "access denied", http.StatusForbidden) + return + } + + input := depot.PrepareUploadInput{ + Prefix: req.NetworkId, + Name: req.Name, + ContentType: req.ContentType, + ContentLength: req.ContentLength, + } + + result, err := h.depotSvc.PrepareUpload(r.Context(), input) + if err != nil { + if errors.Is(err, depot.ErrInvalidInput) { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + slog.Error("failed to prepare upload", "error", err, "network_id", req.NetworkId, "name", req.Name) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp := PrepareUploadResponse{ + ObjectID: result.ObjectID, + UploadURL: result.UploadURL, + UploadHeaders: result.UploadHeaders, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// ConfirmUpload confirms that an upload has been completed +func (h *Handler) ConfirmUpload(w http.ResponseWriter, r *http.Request) { + _, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + objectID := r.PathValue("id") + if objectID == "" { + http.Error(w, "object id is required", http.StatusBadRequest) + return + } + + obj, err := h.depotSvc.ConfirmUpload(r.Context(), objectID) + if err != nil { + if errors.Is(err, depot.ErrNotFound) { + http.Error(w, "object not found", http.StatusNotFound) + return + } + if errors.Is(err, depot.ErrInvalidInput) { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + slog.Error("failed to confirm upload", "error", err, "object_id", objectID) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + resp := DepotObject{ + ID: obj.ID, + Name: obj.Name, + ContentType: obj.ContentType, + ContentLength: obj.ContentLength, + ContainsContent: obj.ContainsContent, + CreatedAt: obj.CreatedAt, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) +} + +// ============================================================================ +// Helper Functions +// ============================================================================ + +const listAllBatchSize = 100 + +// listAllParticles fetches all particles matching the query by paginating in batches. +// This keeps the particle service pagination contract intact. +func (h *Handler) listAllParticles(ctx context.Context, networkID string, parentID *string, email string, filter particle.ListFilter) ([]*particle.Particle, error) { + var all []*particle.Particle + var cursor *particle.Cursor + + for { + page, err := h.particleSvc.List(ctx, networkID, parentID, email, filter, cursor, listAllBatchSize) + if err != nil { + return nil, err + } + + all = append(all, page.Particles...) + + if !page.HasMore || page.NextCursor == nil { + break + } + cursor = page.NextCursor + } + + return all, nil +} + +// getStreamMembers returns the effective members for a stream. +// For custom visibility, returns particle_members. For network_all, returns all network members. +func (h *Handler) getStreamMembers(ctx context.Context, sp *particle.Particle, membersMap map[string][]string) []string { + if sp.Visibility == particle.VisibilityCustom { + return membersMap[sp.ID] + } + // network_all — return all network members + net, err := h.networkSvc.GetByID(ctx, sp.NetworkID) + if err != nil { + slog.Warn("failed to get network for stream members", "error", err, "network_id", sp.NetworkID) + return nil + } + return net.MemberEmails +} + +func humanToDTO(h *human.Human) Human { + return Human{ + Id: utils.CreateOptionalString(h.ID), + Email: h.Email, + EmailPrefix: h.EmailPrefix, + CreatedAt: &h.CreatedAt, + } +} + +func emailPrefix(email string) string { + return strings.Split(email, "@")[0] +} +func (h *Handler) networkToDTO(ctx context.Context, n *network.Network) (Network, error) { + adminHuman, err := h.humanSvc.GetByEmail(ctx, n.AdminEmail) + if err != nil { + return Network{}, err + } + + // Get member humans + humans := make([]Human, 0, len(n.MemberEmails)) + for _, email := range n.MemberEmails { + hum, err := h.humanSvc.GetByEmail(ctx, email) + if err != nil { + if err == human.ErrNotFound { + humans = append(humans, Human{ + Id: nil, + CreatedAt: nil, + Email: email, + EmailPrefix: emailPrefix(email), + }) + } + continue + } else { + humans = append(humans, humanToDTO(hum)) + } + } + + return Network{ + Id: n.ID, + Name: n.Name, + AdminHuman: humanToDTO(adminHuman), + Humans: humans, + OpenStreamCount: n.OpenStreamCount, + OpenStreamCapacity: n.OpenStreamCapacity, + CreatedAt: n.CreatedAt, + }, nil +} + +func (h *Handler) particleToDTO(ctx context.Context, p *particle.Particle) Particle { + dto := Particle{ + Id: p.ID, + Type: string(p.Type), + CreatedByEmail: p.CreatedByEmail, + Data: p.Data, + UpdatedAt: p.UpdatedAt, + CreatedAt: p.CreatedAt, + Visibility: string(p.Visibility), + Seen: false, + Acks: []*AckInfo{}, + } + + return dto +} + +func (h *Handler) streamParticleToDTO(ctx context.Context, p *particle.Particle) StreamParticle { + dto := StreamParticle{ + Id: p.ID, + Type: string(p.Type), + CreatedByEmail: p.CreatedByEmail, + Data: p.Data, + UpdatedAt: p.UpdatedAt, + CreatedAt: p.CreatedAt, + } + + return dto +} + +func parseStreamStatus(s string) StreamStatus { + switch s { + case "open": + return STREAM_STATUS_OPEN + case "closed": + return STREAM_STATUS_CLOSED + default: + return STREAM_STATUS_UNSPECIFIED + } +} + +func extractObjectID(p *particle.Particle) string { + if p.Type != particle.TypeMedia && p.Type != particle.TypeFile { + return "" + } + + var data struct { + ObjectID string `json:"object_id"` + } + if err := json.Unmarshal(p.Data, &data); err == nil { + return data.ObjectID + } + return "" +} + +func extractBearerToken(r *http.Request) string { + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + return "" + } + + const prefix = "Bearer " + if len(authHeader) > len(prefix) && authHeader[:len(prefix)] == prefix { + return authHeader[len(prefix):] + } + return "" +} diff --git a/go/internal/human/models.go b/go/internal/human/models.go new file mode 100644 index 0000000..66b3d08 --- /dev/null +++ b/go/internal/human/models.go @@ -0,0 +1,10 @@ +package human + +import "time" + +type Human struct { + ID string + Email string + EmailPrefix string + CreatedAt time.Time +} diff --git a/go/internal/human/repository.go b/go/internal/human/repository.go new file mode 100644 index 0000000..9314ab4 --- /dev/null +++ b/go/internal/human/repository.go @@ -0,0 +1,108 @@ +package human + +import ( + "context" + "errors" + "strings" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + "go.jetify.com/typeid" +) + +var errNotFound = errors.New("not found") + +type humanIDPrefix struct{} + +func (humanIDPrefix) Prefix() string { return "human" } + +type humanID struct { + typeid.TypeID[humanIDPrefix] +} + +func newHumanID() (humanID, error) { + return typeid.New[humanID]() +} + +func emailPrefix(email string) string { + return strings.Split(email, "@")[0] +} + +type repository interface { + getByEmail(ctx context.Context, email string) (*Human, error) + getByID(ctx context.Context, id string) (*Human, error) + create(ctx context.Context, email string) (*Human, error) + exists(ctx context.Context, email string) (bool, error) +} + +type repositoryImpl struct { + pool *pgxpool.Pool +} + +func newRepository(pool *pgxpool.Pool) repository { + return &repositoryImpl{pool: pool} +} + +func (r *repositoryImpl) getByEmail(ctx context.Context, email string) (*Human, error) { + var h Human + err := r.pool.QueryRow(ctx, + `SELECT id, email, created_at FROM humans WHERE email = $1`, + email, + ).Scan(&h.ID, &h.Email, &h.CreatedAt) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, errNotFound + } + return nil, err + } + h.EmailPrefix = emailPrefix(h.Email) + return &h, nil +} + +func (r *repositoryImpl) getByID(ctx context.Context, id string) (*Human, error) { + var h Human + err := r.pool.QueryRow(ctx, + `SELECT id, email, created_at FROM humans WHERE id = $1`, + id, + ).Scan(&h.ID, &h.Email, &h.CreatedAt) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, errNotFound + } + return nil, err + } + h.EmailPrefix = emailPrefix(h.Email) + return &h, nil +} + +func (r *repositoryImpl) create(ctx context.Context, email string) (*Human, error) { + id, err := newHumanID() + if err != nil { + return nil, err + } + + var h Human + err = r.pool.QueryRow(ctx, + `INSERT INTO humans (id, email) VALUES ($1, $2) + RETURNING id, email, created_at`, + id.String(), email, + ).Scan(&h.ID, &h.Email, &h.CreatedAt) + if err != nil { + return nil, err + } + + h.EmailPrefix = emailPrefix(h.Email) + return &h, nil +} + +func (r *repositoryImpl) exists(ctx context.Context, email string) (bool, error) { + var exists bool + err := r.pool.QueryRow(ctx, + `SELECT EXISTS(SELECT 1 FROM humans WHERE email = $1)`, + email, + ).Scan(&exists) + if err != nil { + return false, err + } + return exists, nil +} diff --git a/go/internal/human/service.go b/go/internal/human/service.go new file mode 100644 index 0000000..e894686 --- /dev/null +++ b/go/internal/human/service.go @@ -0,0 +1,54 @@ +package human + +import ( + "context" + "errors" + + "github.com/flowy-live/llink/internal/utils" + "github.com/jackc/pgx/v5/pgxpool" +) + +var ErrNotFound = errors.New("human not found") + +type Service interface { + GetOrCreateByEmail(ctx context.Context, email string) (*Human, error) + // GetByEmail returns ErrNotFound if no human found + GetByEmail(ctx context.Context, email string) (*Human, error) +} + +type serviceImpl struct { + repo repository +} + +func NewService(pool *pgxpool.Pool) Service { + return &serviceImpl{repo: newRepository(pool)} +} + +func (s *serviceImpl) GetOrCreateByEmail(ctx context.Context, email string) (*Human, error) { + email, err := utils.NormalizeEmail(email) + if err != nil { + return nil, err + } + + h, err := s.repo.getByEmail(ctx, email) + if err != nil { + if errors.Is(err, errNotFound) { + return s.repo.create(ctx, email) + } + return nil, err + } + return h, nil +} + +func (s *serviceImpl) GetByEmail(ctx context.Context, email string) (*Human, error) { + email, err := utils.NormalizeEmail(email) + if err != nil { + return nil, err + } + + h, err := s.repo.getByEmail(ctx, email) + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return h, err +} diff --git a/go/internal/human/service_test.go b/go/internal/human/service_test.go new file mode 100644 index 0000000..89154a6 --- /dev/null +++ b/go/internal/human/service_test.go @@ -0,0 +1,59 @@ +package human_test + +import ( + "context" + "os" + "testing" + + "github.com/flowy-live/llink/internal/human" + "github.com/flowy-live/llink/internal/testhelper" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/stretchr/testify/assert" +) + +var dbPool *pgxpool.Pool + +func TestMain(m *testing.M) { + dbPool = testhelper.SetupTestDB() + defer testhelper.TeardownTestDB() + + ret := m.Run() + os.Exit(ret) +} + +func TestHumanService(t *testing.T) { + ctx := context.Background() + svc := human.NewService(dbPool) + + // Test GetByEmail with non-existent email + _, err := svc.GetByEmail(ctx, "newuser@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, human.ErrNotFound) + + // Test GetOrCreateByEmail creates new human + createdHuman, err := svc.GetOrCreateByEmail(ctx, "newuser@example.com") + assert.NoError(t, err) + assert.NotEmpty(t, createdHuman.ID) + assert.Equal(t, "newuser@example.com", createdHuman.Email) + assert.Equal(t, "newuser", createdHuman.EmailPrefix) + assert.NotZero(t, createdHuman.CreatedAt) + + // Test GetOrCreateByEmail returns existing human + existingHuman, err := svc.GetOrCreateByEmail(ctx, "newuser@example.com") + assert.NoError(t, err) + assert.Equal(t, createdHuman.ID, existingHuman.ID) + assert.Equal(t, createdHuman.Email, existingHuman.Email) + + // Test GetByEmail with existing email + foundHuman, err := svc.GetByEmail(ctx, "newuser@example.com") + assert.NoError(t, err) + assert.Equal(t, createdHuman.ID, foundHuman.ID) + assert.Equal(t, createdHuman.Email, foundHuman.Email) + + // Test with another email + anotherHuman, err := svc.GetOrCreateByEmail(ctx, "another@example.com") + assert.NoError(t, err) + assert.NotEqual(t, createdHuman.ID, anotherHuman.ID) + assert.Equal(t, "another@example.com", anotherHuman.Email) + assert.Equal(t, "another", anotherHuman.EmailPrefix) +} diff --git a/go/internal/middleware/auth.go b/go/internal/middleware/auth.go new file mode 100644 index 0000000..330c6bb --- /dev/null +++ b/go/internal/middleware/auth.go @@ -0,0 +1,67 @@ +package middleware + +import ( + "context" + "log/slog" + "net/http" + "strings" + + "github.com/flowy-live/llink/internal/auth" +) + +type contextKey string + +const emailContextKey contextKey = "email" + +// WithEmail adds the email to the context +func WithEmail(ctx context.Context, email string) context.Context { + return context.WithValue(ctx, emailContextKey, email) +} + +// EmailFromContext extracts the email from the context +func EmailFromContext(ctx context.Context) (string, bool) { + email, ok := ctx.Value(emailContextKey).(string) + return email, ok +} + +// Auth returns a middleware that validates the session token and adds the email to the context +func Auth(authSvc auth.AuthService) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token := extractBearerToken(r) + if token == "" { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + email, err := authSvc.GetSession(r.Context(), token) + if err != nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + // Auto-extend session + if err := authSvc.ExtendSession(r.Context(), token); err != nil { + slog.Warn("failed to extend session", "error", err) + } + + ctx := WithEmail(r.Context(), email) + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} + +// extractBearerToken extracts the token from the Authorization header +func extractBearerToken(r *http.Request) string { + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + return "" + } + + parts := strings.SplitN(authHeader, " ", 2) + if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") { + return "" + } + + return parts[1] +} diff --git a/go/internal/network/models.go b/go/internal/network/models.go new file mode 100644 index 0000000..3523ddc --- /dev/null +++ b/go/internal/network/models.go @@ -0,0 +1,13 @@ +package network + +import "time" + +type Network struct { + ID string + Name string + AdminEmail string + MemberEmails []string + OpenStreamCapacity int + OpenStreamCount int + CreatedAt time.Time +} diff --git a/go/internal/network/repository.go b/go/internal/network/repository.go new file mode 100644 index 0000000..a03d75e --- /dev/null +++ b/go/internal/network/repository.go @@ -0,0 +1,252 @@ +package network + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + "go.jetify.com/typeid" +) + +var errNotFound = errors.New("not found") + +type networkIDPrefix struct{} + +func (networkIDPrefix) Prefix() string { return "net" } + +type networkID struct { + typeid.TypeID[networkIDPrefix] +} + +func newNetworkID() (networkID, error) { + return typeid.New[networkID]() +} + +var errCapacityExceeded = errors.New("capacity exceeded") + +type repository interface { + create(ctx context.Context, name, adminEmail string) (*Network, error) + getByID(ctx context.Context, id string) (*Network, error) + updateName(ctx context.Context, id, name string) error + delete(ctx context.Context, id string) error + addMember(ctx context.Context, networkID, email string) error + removeMember(ctx context.Context, networkID, email string) error + getMemberEmails(ctx context.Context, networkID string) ([]string, error) + getNetworksForEmail(ctx context.Context, email string) ([]*Network, error) + isMember(ctx context.Context, networkID, email string) (bool, error) + setOpenStreamCapacity(ctx context.Context, id string, capacity int) error + incrementOpenStreamCount(ctx context.Context, id string) error + decrementOpenStreamCount(ctx context.Context, id string) error +} + +type repositoryImpl struct { + pool *pgxpool.Pool +} + +func newRepository(pool *pgxpool.Pool) repository { + return &repositoryImpl{pool: pool} +} + +func (r *repositoryImpl) create(ctx context.Context, name, adminEmail string) (*Network, error) { + id, err := newNetworkID() + if err != nil { + return nil, err + } + + var n Network + err = r.pool.QueryRow(ctx, + `INSERT INTO networks (id, name, admin_email) VALUES ($1, $2, $3) + RETURNING id, name, admin_email, open_stream_capacity, open_stream_count, created_at`, + id.String(), name, adminEmail, + ).Scan(&n.ID, &n.Name, &n.AdminEmail, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt) + if err != nil { + return nil, err + } + + n.MemberEmails = []string{} + return &n, nil +} + +func (r *repositoryImpl) getByID(ctx context.Context, id string) (*Network, error) { + var n Network + err := r.pool.QueryRow(ctx, + `SELECT id, name, admin_email, open_stream_capacity, open_stream_count, created_at FROM networks WHERE id = $1`, + id, + ).Scan(&n.ID, &n.Name, &n.AdminEmail, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, errNotFound + } + return nil, err + } + + n.MemberEmails, err = r.getMemberEmails(ctx, id) + if err != nil { + return nil, err + } + + return &n, nil +} + +func (r *repositoryImpl) updateName(ctx context.Context, id, name string) error { + result, err := r.pool.Exec(ctx, + `UPDATE networks SET name = $1 WHERE id = $2`, + name, id, + ) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) delete(ctx context.Context, id string) error { + result, err := r.pool.Exec(ctx, `DELETE FROM networks WHERE id = $1`, id) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) addMember(ctx context.Context, networkID, email string) error { + _, err := r.pool.Exec(ctx, + `INSERT INTO network_members (network_id, email) VALUES ($1, $2) + ON CONFLICT (network_id, email) DO NOTHING`, + networkID, email, + ) + return err +} + +func (r *repositoryImpl) removeMember(ctx context.Context, networkID, email string) error { + _, err := r.pool.Exec(ctx, + `DELETE FROM network_members WHERE network_id = $1 AND email = $2`, + networkID, email, + ) + return err +} + +func (r *repositoryImpl) getMemberEmails(ctx context.Context, networkID string) ([]string, error) { + rows, err := r.pool.Query(ctx, + `SELECT email FROM network_members WHERE network_id = $1`, + networkID, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + var emails []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + emails = append(emails, email) + } + return emails, rows.Err() +} + +func (r *repositoryImpl) getNetworksForEmail(ctx context.Context, email string) ([]*Network, error) { + rows, err := r.pool.Query(ctx, + `SELECT n.id, n.name, n.admin_email, n.open_stream_capacity, n.open_stream_count, n.created_at + FROM networks n + WHERE n.admin_email = $1 + OR EXISTS (SELECT 1 FROM network_members nm WHERE nm.network_id = n.id AND nm.email = $1)`, + email, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + var networks []*Network + for rows.Next() { + var n Network + if err := rows.Scan(&n.ID, &n.Name, &n.AdminEmail, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt); err != nil { + return nil, err + } + networks = append(networks, &n) + } + if err := rows.Err(); err != nil { + return nil, err + } + + for _, n := range networks { + n.MemberEmails, err = r.getMemberEmails(ctx, n.ID) + if err != nil { + return nil, err + } + } + + return networks, nil +} + +func (r *repositoryImpl) isMember(ctx context.Context, networkID, email string) (bool, error) { + var isMember bool + err := r.pool.QueryRow(ctx, ` + SELECT EXISTS( + SELECT 1 FROM networks n + LEFT JOIN network_members nm ON nm.network_id = n.id AND nm.email = $2 + WHERE n.id = $1 AND (n.admin_email = $2 OR nm.email IS NOT NULL) + ) + `, networkID, email).Scan(&isMember) + return isMember, err +} + +func (r *repositoryImpl) setOpenStreamCapacity(ctx context.Context, id string, capacity int) error { + result, err := r.pool.Exec(ctx, + `UPDATE networks SET open_stream_capacity = $1 WHERE id = $2`, + capacity, id, + ) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) incrementOpenStreamCount(ctx context.Context, id string) error { + result, err := r.pool.Exec(ctx, + `UPDATE networks SET open_stream_count = open_stream_count + 1 + WHERE id = $1 AND open_stream_count < open_stream_capacity`, + id, + ) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + // Check if network exists vs capacity exceeded + var exists bool + err := r.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM networks WHERE id = $1)`, id).Scan(&exists) + if err != nil { + return err + } + if !exists { + return errNotFound + } + return errCapacityExceeded + } + return nil +} + +func (r *repositoryImpl) decrementOpenStreamCount(ctx context.Context, id string) error { + result, err := r.pool.Exec(ctx, + `UPDATE networks SET open_stream_count = GREATEST(0, open_stream_count - 1) WHERE id = $1`, + id, + ) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} diff --git a/go/internal/network/service.go b/go/internal/network/service.go new file mode 100644 index 0000000..f35a51e --- /dev/null +++ b/go/internal/network/service.go @@ -0,0 +1,155 @@ +package network + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/flowy-live/llink/internal/utils" + "github.com/jackc/pgx/v5/pgxpool" +) + +var ErrNotFound = errors.New("network not found") +var ErrInvalidName = errors.New("name cannot be empty") +var ErrCapacityExceeded = errors.New("active stream capacity exceeded") + +type Service interface { + // Create creates a network and adds adminEmail as the first member. Returns ErrInvalidName if name is empty. + Create(ctx context.Context, name, adminEmail string) (*Network, error) + // GetByID returns ErrNotFound if network doesn't exist. + GetByID(ctx context.Context, id string) (*Network, error) + // SetName returns ErrNotFound or ErrInvalidName. + SetName(ctx context.Context, id, name string) error + AddMembers(ctx context.Context, networkID string, emails []string) error + RemoveMember(ctx context.Context, networkID, email string) error + ListForEmail(ctx context.Context, email string) ([]*Network, error) + IsMember(ctx context.Context, networkID, email string) (bool, error) + + // SetOpenStreamCapacity sets the max open streams for a network. Returns ErrNotFound. + SetOpenStreamCapacity(ctx context.Context, networkID string, capacity int) error + // IncrementOpenStreamCount returns ErrNotFound or ErrCapacityExceeded. + IncrementOpenStreamCount(ctx context.Context, networkID string) error + // DecrementOpenStreamCount returns ErrNotFound. + DecrementOpenStreamCount(ctx context.Context, networkID string) error +} + +type serviceImpl struct { + repo repository +} + +func NewService(pool *pgxpool.Pool) Service { + return &serviceImpl{repo: newRepository(pool)} +} + +func (s *serviceImpl) Create(ctx context.Context, name, adminEmail string) (*Network, error) { + name = strings.TrimSpace(name) + if name == "" { + return nil, ErrInvalidName + } + + adminEmail, err := utils.NormalizeEmail(adminEmail) + if err != nil { + return nil, err + } + + network, err := s.repo.create(ctx, name, adminEmail) + if err != nil { + return nil, err + } + + err = s.AddMembers(ctx, network.ID, []string{adminEmail}) + if err != nil { + return nil, err + } + + return network, nil +} + +func (s *serviceImpl) GetByID(ctx context.Context, id string) (*Network, error) { + n, err := s.repo.getByID(ctx, id) + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return n, err +} + +func (s *serviceImpl) SetName(ctx context.Context, id, name string) error { + name = strings.TrimSpace(name) + if name == "" { + return ErrInvalidName + } + + err := s.repo.updateName(ctx, id, name) + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err +} + +func (s *serviceImpl) AddMembers(ctx context.Context, networkID string, emails []string) error { + for _, email := range emails { + normalized, err := utils.NormalizeEmail(email) + if err != nil { + return fmt.Errorf("invalid email: %w", err) + } + if err := s.repo.addMember(ctx, networkID, normalized); err != nil { + return err + } + } + return nil +} + +func (s *serviceImpl) RemoveMember(ctx context.Context, networkID, email string) error { + email, err := utils.NormalizeEmail(email) + if err != nil { + return fmt.Errorf("invalid email: %w", err) + } + return s.repo.removeMember(ctx, networkID, email) +} + +func (s *serviceImpl) ListForEmail(ctx context.Context, email string) ([]*Network, error) { + email, err := utils.NormalizeEmail(email) + if err != nil { + return nil, fmt.Errorf("invalid email: %w", err) + } + return s.repo.getNetworksForEmail(ctx, email) +} + +func (s *serviceImpl) IsMember(ctx context.Context, networkID, email string) (bool, error) { + email, err := utils.NormalizeEmail(email) + if err != nil { + return false, err + } + return s.repo.isMember(ctx, networkID, email) +} + +func (s *serviceImpl) SetOpenStreamCapacity(ctx context.Context, networkID string, capacity int) error { + if capacity < 0 { + capacity = 0 + } + err := s.repo.setOpenStreamCapacity(ctx, networkID, capacity) + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err +} + +func (s *serviceImpl) IncrementOpenStreamCount(ctx context.Context, networkID string) error { + err := s.repo.incrementOpenStreamCount(ctx, networkID) + if errors.Is(err, errNotFound) { + return ErrNotFound + } + if errors.Is(err, errCapacityExceeded) { + return ErrCapacityExceeded + } + return err +} + +func (s *serviceImpl) DecrementOpenStreamCount(ctx context.Context, networkID string) error { + err := s.repo.decrementOpenStreamCount(ctx, networkID) + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err +} diff --git a/go/internal/network/service_test.go b/go/internal/network/service_test.go new file mode 100644 index 0000000..04dd539 --- /dev/null +++ b/go/internal/network/service_test.go @@ -0,0 +1,109 @@ +package network_test + +import ( + "context" + "os" + "testing" + + "github.com/flowy-live/llink/internal/network" + "github.com/flowy-live/llink/internal/testhelper" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/stretchr/testify/assert" +) + +var dbPool *pgxpool.Pool + +func TestMain(m *testing.M) { + dbPool = testhelper.SetupTestDB() + defer testhelper.TeardownTestDB() + + ret := m.Run() + os.Exit(ret) +} + +func TestNetworkService(t *testing.T) { + ctx := context.Background() + svc := network.NewService(dbPool) + + // Test Create + createdNetwork, err := svc.Create(ctx, "Test Network", "admin@example.com") + assert.NoError(t, err) + assert.NotEmpty(t, createdNetwork.ID) + assert.Equal(t, "Test Network", createdNetwork.Name) + assert.Equal(t, "admin@example.com", createdNetwork.AdminEmail) + assert.NotZero(t, createdNetwork.CreatedAt) + + // Test GetByID + foundNetwork, err := svc.GetByID(ctx, createdNetwork.ID) + assert.NoError(t, err) + assert.Equal(t, createdNetwork.ID, foundNetwork.ID) + assert.Equal(t, createdNetwork.Name, foundNetwork.Name) + assert.Equal(t, createdNetwork.AdminEmail, foundNetwork.AdminEmail) + + // Test GetByID with non-existent id + _, err = svc.GetByID(ctx, "network_nonexistent") + assert.Error(t, err) + assert.ErrorIs(t, err, network.ErrNotFound) + + // Test SetName + err = svc.SetName(ctx, createdNetwork.ID, "Updated Network Name") + assert.NoError(t, err) + + // Verify name was updated + updatedNetwork, err := svc.GetByID(ctx, createdNetwork.ID) + assert.NoError(t, err) + assert.Equal(t, "Updated Network Name", updatedNetwork.Name) + + // Test SetName with non-existent id + err = svc.SetName(ctx, "network_nonexistent", "New Name") + assert.Error(t, err) + assert.ErrorIs(t, err, network.ErrNotFound) + + // Test AddMembers + err = svc.AddMembers(ctx, createdNetwork.ID, []string{"member1@example.com", "member2@example.com"}) + assert.NoError(t, err) + + // Test ListForEmail - should find network for admin + networks, err := svc.ListForEmail(ctx, "admin@example.com") + assert.NoError(t, err) + assert.Len(t, networks, 1) + assert.Equal(t, createdNetwork.ID, networks[0].ID) + + // Test ListForEmail - should find network for member + networks, err = svc.ListForEmail(ctx, "member1@example.com") + assert.NoError(t, err) + assert.Len(t, networks, 1) + assert.Equal(t, createdNetwork.ID, networks[0].ID) + + // Test ListForEmail - should return empty for non-member + networks, err = svc.ListForEmail(ctx, "stranger@example.com") + assert.NoError(t, err) + assert.Len(t, networks, 0) + + // Test RemoveMember + err = svc.RemoveMember(ctx, createdNetwork.ID, "member1@example.com") + assert.NoError(t, err) + + // Verify member was removed + networks, err = svc.ListForEmail(ctx, "member1@example.com") + assert.NoError(t, err) + assert.Len(t, networks, 0) + + // member2 should still have access + networks, err = svc.ListForEmail(ctx, "member2@example.com") + assert.NoError(t, err) + assert.Len(t, networks, 1) + + // Create another network and verify ListForEmail returns multiple + network2, err := svc.Create(ctx, "Second Network", "member2@example.com") + assert.NoError(t, err) + + networks, err = svc.ListForEmail(ctx, "member2@example.com") + assert.NoError(t, err) + assert.Len(t, networks, 2) + + // Verify both networks are returned + networkIDs := []string{networks[0].ID, networks[1].ID} + assert.Contains(t, networkIDs, createdNetwork.ID) + assert.Contains(t, networkIDs, network2.ID) +} diff --git a/go/internal/particle/errors.go b/go/internal/particle/errors.go new file mode 100644 index 0000000..dafef01 --- /dev/null +++ b/go/internal/particle/errors.go @@ -0,0 +1,19 @@ +package particle + +import "errors" + +var ( + ErrNotFound = errors.New("particle not found") + ErrAccessDenied = errors.New("access denied") + ErrCapacityExceeded = errors.New("open stream capacity exceeded") + ErrInvalidParent = errors.New("invalid parent particle") + ErrInvalidType = errors.New("invalid particle type") + ErrInvalidData = errors.New("invalid particle data") + ErrNotAStream = errors.New("particle is not a stream") + ErrStreamAlreadyOpen = errors.New("stream is already open") + ErrStreamAlreadyClosed = errors.New("stream is already closed") + ErrAccessExpansion = errors.New("cannot expand access beyond parent") + ErrMembersRequired = errors.New("custom visibility requires at least one member") + ErrInheritedAtRoot = errors.New("root particles cannot use inherited visibility") + ErrNotAContainer = errors.New("only streams can have members") +) diff --git a/go/internal/particle/models.go b/go/internal/particle/models.go new file mode 100644 index 0000000..4c1427e --- /dev/null +++ b/go/internal/particle/models.go @@ -0,0 +1,174 @@ +package particle + +import ( + "encoding/json" + "errors" + "time" +) + +// ParticleType represents the type of particle +type ParticleType string + +const ( + TypeStream ParticleType = "stream" + TypeFolder ParticleType = "folder" + TypeMedia ParticleType = "media" + TypeFile ParticleType = "file" + TypeText ParticleType = "text" + TypeQuest ParticleType = "quest" + TypePaper ParticleType = "paper" + // TypeThink ParticleType = "think" +) + +// VisibilityMode represents how access to a particle is determined +type VisibilityMode string + +const ( + VisibilityNetworkAll VisibilityMode = "network_all" + VisibilityCustom VisibilityMode = "custom" + VisibilityInherited VisibilityMode = "inherited" +) + +var ErrInvalidParticleType = errors.New("invalid particle type") +var ErrInvalidVisibilityMode = errors.New("invalid visibility mode") + +// ParseParticleType parses a string into a ParticleType +func ParseParticleType(s string) (ParticleType, error) { + switch s { + case string(TypeStream): + return TypeStream, nil + case string(TypeFolder): + return TypeFolder, nil + case string(TypeMedia): + return TypeMedia, nil + case string(TypeFile): + return TypeFile, nil + case string(TypeText): + return TypeText, nil + case string(TypeQuest): + return TypeQuest, nil + case string(TypePaper): + return TypePaper, nil + default: + return "", ErrInvalidParticleType + } +} + +// ParseVisibilityMode parses a string into a VisibilityMode +func ParseVisibilityMode(s string) (VisibilityMode, error) { + switch s { + case "", string(VisibilityNetworkAll): + return VisibilityNetworkAll, nil + case string(VisibilityCustom): + return VisibilityCustom, nil + case string(VisibilityInherited): + return VisibilityInherited, nil + default: + return "", ErrInvalidVisibilityMode + } +} + +// Stream status values +type StreamStatus string + +const ( + StreamStatusOpen StreamStatus = "open" + StreamStatusClosed StreamStatus = "closed" +) + +// Particle represents a content particle in the system +type Particle struct { + ID string + Type ParticleType + NetworkID string + ParentID *string + CreatedByEmail string + Visibility VisibilityMode + Data json.RawMessage + UpdatedAt time.Time + CreatedAt time.Time +} + +// CreateInput represents the input for creating a new particle +type CreateInput struct { + Type ParticleType + NetworkID string + ParentID *string + Data json.RawMessage + Members []string // Only used when visibility is custom + Visibility VisibilityMode +} + +// ListFilter represents filtering options for listing particles +type ListFilter struct { + Types []ParticleType +} + +// Cursor represents a pagination cursor for bidirectional pagination +type Cursor struct { + Position string // particle ID or timestamp + Direction string // "before" or "after" +} + +// ParticleList represents a paginated list of particles +type ParticleList struct { + Particles []*Particle + HasMore bool + NextCursor *Cursor + PrevCursor *Cursor +} + +// StreamData represents the data stored for stream particles +type StreamData struct { + Name string `json:"name"` + Status string `json:"status"` // "open" or "closed" + Description *string `json:"description"` +} + +// FolderData represents the data stored for folder particles +type FolderData struct { + Name string `json:"name"` + Color *string `json:"color"` +} + +// MediaData represents the data stored for media particles +type MediaData struct { + ObjectID string `json:"object_id"` // reference to storage object + MimeType string `json:"mime_type"` + DurationMs int `json:"duration_ms"` + // Caption *string `json:"caption"` +} + +// FileData represents the data stored for file particles +type FileData struct { + ObjectID string `json:"object_id"` // reference to storage object + Filename string `json:"filename"` + MimeType string `json:"mime_type"` + Size int64 `json:"size"` // in bytes +} + +// TextData represents the data stored for text particles +type TextData struct { + Content string `json:"content"` +} + +// QuestData represents the data stored for quest particles +type QuestData struct { + Title string `json:"title"` + Description string `json:"description"` + Status *string `json:"status"` + AssignedTo *string `json:"assigned_to,omitempty"` // email + DueDate *string `json:"due_date,omitempty"` // ISO date string +} + +// PaperData represents the data stored for paper particles +type PaperData struct { + Title string `json:"title"` + Content string `json:"content"` // markdown +} + +// AckInfo represents an acknowledgment record +type AckInfo struct { + Email string + AckedAt time.Time +} diff --git a/go/internal/particle/repository.go b/go/internal/particle/repository.go new file mode 100644 index 0000000..7b8089f --- /dev/null +++ b/go/internal/particle/repository.go @@ -0,0 +1,413 @@ +package particle + +import ( + "context" + "encoding/json" + "errors" + "time" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + "go.jetify.com/typeid" +) + +var errNotFound = errors.New("not found") +var errAccessDenied = errors.New("access denied") + +type particleIDPrefix struct{} + +func (particleIDPrefix) Prefix() string { return "particle" } + +type particleID struct { + typeid.TypeID[particleIDPrefix] +} + +func newParticleID() (particleID, error) { + return typeid.New[particleID]() +} + +type repository interface { + create(ctx context.Context, p *Particle) (*Particle, error) + getByID(ctx context.Context, id string) (*Particle, error) + update(ctx context.Context, id string, data json.RawMessage, updatedAt time.Time) error + delete(ctx context.Context, id string) error + + list(ctx context.Context, networkID string, parentID *string, requesterEmail string, filter ListFilter, limit int, cursor *Cursor) ([]*Particle, error) + + setVisibility(ctx context.Context, id string, mode VisibilityMode) error + addMembers(ctx context.Context, particleID string, emails []string) error + removeMembers(ctx context.Context, particleID string, emails []string) error + getMembers(ctx context.Context, particleID string) ([]string, error) + getMembersMap(ctx context.Context, particleIDs []string) (map[string][]string, error) + + // getAncestorChain returns the particle and all its ancestors (for access checks) + getAncestorChain(ctx context.Context, particleID string) ([]*Particle, error) + isMemberOf(ctx context.Context, particleID, email string) (bool, error) + + // Seen tracking + markSeen(ctx context.Context, particleID, email string) error + getSeenMap(ctx context.Context, particleIDs []string, email string) (map[string]bool, error) + getUnseenCounts(ctx context.Context, streamIDs []string, email string) (map[string]int, error) + + // Ack tracking + ack(ctx context.Context, particleID, email string) error + getAcksMap(ctx context.Context, particleIDs []string) (map[string][]AckInfo, error) +} + +type repositoryImpl struct { + pool *pgxpool.Pool +} + +func newRepository(pool *pgxpool.Pool) repository { + return &repositoryImpl{pool: pool} +} + +func (r *repositoryImpl) create(ctx context.Context, p *Particle) (*Particle, error) { + id, err := newParticleID() + if err != nil { + return nil, err + } + + var result Particle + err = r.pool.QueryRow(ctx, + `INSERT INTO particles (id, type, network_id, parent_id, created_by_email, visibility, data) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id, type, network_id, parent_id, created_by_email, visibility, data, updated_at, created_at`, + id.String(), p.Type, p.NetworkID, p.ParentID, p.CreatedByEmail, p.Visibility, p.Data, + ).Scan(&result.ID, &result.Type, &result.NetworkID, &result.ParentID, &result.CreatedByEmail, + &result.Visibility, &result.Data, &result.UpdatedAt, &result.CreatedAt) + if err != nil { + return nil, err + } + + return &result, nil +} + +func (r *repositoryImpl) getByID(ctx context.Context, id string) (*Particle, error) { + var p Particle + err := r.pool.QueryRow(ctx, + `SELECT id, type, network_id, parent_id, created_by_email, visibility, data, updated_at, created_at + FROM particles WHERE id = $1`, + id, + ).Scan(&p.ID, &p.Type, &p.NetworkID, &p.ParentID, &p.CreatedByEmail, + &p.Visibility, &p.Data, &p.UpdatedAt, &p.CreatedAt) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, errNotFound + } + return nil, err + } + return &p, nil +} + +func (r *repositoryImpl) update(ctx context.Context, id string, data json.RawMessage, updatedAt time.Time) error { + result, err := r.pool.Exec(ctx, + `UPDATE particles SET data = $1, updated_at = $2 WHERE id = $3`, + data, updatedAt, id, + ) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) delete(ctx context.Context, id string) error { + result, err := r.pool.Exec(ctx, `DELETE FROM particles WHERE id = $1`, id) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) list(ctx context.Context, networkID string, parentID *string, requesterEmail string, filter ListFilter, limit int, cursor *Cursor) ([]*Particle, error) { + query := `SELECT id, type, network_id, parent_id, created_by_email, visibility, data, updated_at, created_at + FROM particles p WHERE p.network_id = $1` + + args := []any{networkID} + argIdx := 2 + + if parentID != nil { + query += ` AND p.parent_id = $` + string(rune('0'+argIdx)) + args = append(args, *parentID) + argIdx++ + } else { + query += ` AND p.parent_id IS NULL` + } + + // Filter by visibility: include if network_all, inherited, OR user is a member + query += ` AND (p.visibility = 'network_all' OR p.visibility = 'inherited' OR EXISTS (SELECT 1 FROM particle_members pm WHERE pm.particle_id = p.id AND pm.email = $` + string(rune('0'+argIdx)) + `))` + args = append(args, requesterEmail) + argIdx++ + + if len(filter.Types) > 0 { + query += ` AND p.type = ANY($` + string(rune('0'+argIdx)) + `)` + typeStrings := make([]string, len(filter.Types)) + for i, t := range filter.Types { + typeStrings[i] = string(t) + } + args = append(args, typeStrings) + argIdx++ + } + + if cursor != nil { + if cursor.Direction == "before" { + query += ` AND p.updated_at > $` + string(rune('0'+argIdx)) + } else { + query += ` AND p.updated_at < $` + string(rune('0'+argIdx)) + } + args = append(args, cursor.Position) + argIdx++ + } + + query += ` ORDER BY p.updated_at DESC LIMIT $` + string(rune('0'+argIdx)) + args = append(args, limit) + + rows, err := r.pool.Query(ctx, query, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + return scanParticles(rows) +} + +func scanParticles(rows pgx.Rows) ([]*Particle, error) { + var particles []*Particle + for rows.Next() { + var p Particle + if err := rows.Scan(&p.ID, &p.Type, &p.NetworkID, &p.ParentID, &p.CreatedByEmail, + &p.Visibility, &p.Data, &p.UpdatedAt, &p.CreatedAt); err != nil { + return nil, err + } + particles = append(particles, &p) + } + return particles, rows.Err() +} + +func (r *repositoryImpl) setVisibility(ctx context.Context, id string, mode VisibilityMode) error { + result, err := r.pool.Exec(ctx, + `UPDATE particles SET visibility = $1, updated_at = NOW() WHERE id = $2`, + mode, id, + ) + if err != nil { + return err + } + if result.RowsAffected() == 0 { + return errNotFound + } + return nil +} + +func (r *repositoryImpl) addMembers(ctx context.Context, particleID string, emails []string) error { + for _, email := range emails { + _, err := r.pool.Exec(ctx, + `INSERT INTO particle_members (particle_id, email) VALUES ($1, $2) + ON CONFLICT (particle_id, email) DO NOTHING`, + particleID, email, + ) + if err != nil { + return err + } + } + return nil +} + +func (r *repositoryImpl) removeMembers(ctx context.Context, particleID string, emails []string) error { + for _, email := range emails { + _, err := r.pool.Exec(ctx, + `DELETE FROM particle_members WHERE particle_id = $1 AND email = $2`, + particleID, email, + ) + if err != nil { + return err + } + } + return nil +} + +func (r *repositoryImpl) getMembers(ctx context.Context, particleID string) ([]string, error) { + rows, err := r.pool.Query(ctx, + `SELECT email FROM particle_members WHERE particle_id = $1`, + particleID, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + var emails []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + emails = append(emails, email) + } + return emails, rows.Err() +} + +func (r *repositoryImpl) getMembersMap(ctx context.Context, particleIDs []string) (map[string][]string, error) { + if len(particleIDs) == 0 { + return map[string][]string{}, nil + } + + rows, err := r.pool.Query(ctx, + `SELECT particle_id, email FROM particle_members WHERE particle_id = ANY($1)`, + particleIDs, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + result := make(map[string][]string) + for rows.Next() { + var particleID, email string + if err := rows.Scan(&particleID, &email); err != nil { + return nil, err + } + result[particleID] = append(result[particleID], email) + } + return result, rows.Err() +} + +func (r *repositoryImpl) getAncestorChain(ctx context.Context, particleID string) ([]*Particle, error) { + rows, err := r.pool.Query(ctx, ` + WITH RECURSIVE ancestors AS ( + SELECT id, type, network_id, parent_id, created_by_email, visibility, data, updated_at, created_at + FROM particles WHERE id = $1 + UNION ALL + SELECT p.id, p.type, p.network_id, p.parent_id, p.created_by_email, p.visibility, p.data, p.updated_at, p.created_at + FROM particles p JOIN ancestors a ON p.id = a.parent_id + ) + SELECT id, type, network_id, parent_id, created_by_email, visibility, data, updated_at, created_at + FROM ancestors; + `, particleID) + if err != nil { + return nil, err + } + defer rows.Close() + + particles, err := scanParticles(rows) + if err != nil { + return nil, err + } + if len(particles) == 0 { + return nil, errNotFound + } + return particles, nil +} + +func (r *repositoryImpl) isMemberOf(ctx context.Context, particleID, email string) (bool, error) { + var isMember bool + err := r.pool.QueryRow(ctx, ` + SELECT EXISTS(SELECT 1 FROM particle_members WHERE particle_id = $1 AND email = $2) + `, particleID, email).Scan(&isMember) + return isMember, err +} + +func (r *repositoryImpl) markSeen(ctx context.Context, particleID, email string) error { + _, err := r.pool.Exec(ctx, + `INSERT INTO particle_seen (particle_id, email) VALUES ($1, $2) + ON CONFLICT (particle_id, email) DO NOTHING`, + particleID, email, + ) + return err +} + +func (r *repositoryImpl) getSeenMap(ctx context.Context, particleIDs []string, email string) (map[string]bool, error) { + if len(particleIDs) == 0 { + return map[string]bool{}, nil + } + + rows, err := r.pool.Query(ctx, + `SELECT particle_id FROM particle_seen WHERE particle_id = ANY($1) AND email = $2`, + particleIDs, email, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + result := make(map[string]bool) + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + return nil, err + } + result[id] = true + } + return result, rows.Err() +} + +func (r *repositoryImpl) getUnseenCounts(ctx context.Context, streamIDs []string, email string) (map[string]int, error) { + if len(streamIDs) == 0 { + return map[string]int{}, nil + } + + rows, err := r.pool.Query(ctx, ` + SELECT p.parent_id, COUNT(*) + FROM particles p + WHERE p.parent_id = ANY($1) + AND NOT EXISTS (SELECT 1 FROM particle_seen ps WHERE ps.particle_id = p.id AND ps.email = $2) + AND (p.visibility = 'network_all' OR p.visibility = 'inherited' + OR EXISTS (SELECT 1 FROM particle_members pm WHERE pm.particle_id = p.id AND pm.email = $2)) + GROUP BY p.parent_id + `, streamIDs, email) + if err != nil { + return nil, err + } + defer rows.Close() + + result := make(map[string]int) + for rows.Next() { + var parentID string + var count int + if err := rows.Scan(&parentID, &count); err != nil { + return nil, err + } + result[parentID] = count + } + return result, rows.Err() +} + +func (r *repositoryImpl) ack(ctx context.Context, particleID, email string) error { + _, err := r.pool.Exec(ctx, + `INSERT INTO particle_acks (particle_id, email) VALUES ($1, $2) + ON CONFLICT (particle_id, email) DO NOTHING`, + particleID, email, + ) + return err +} + +func (r *repositoryImpl) getAcksMap(ctx context.Context, particleIDs []string) (map[string][]AckInfo, error) { + if len(particleIDs) == 0 { + return map[string][]AckInfo{}, nil + } + + rows, err := r.pool.Query(ctx, + `SELECT particle_id, email, acked_at FROM particle_acks WHERE particle_id = ANY($1) ORDER BY acked_at`, + particleIDs, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + result := make(map[string][]AckInfo) + for rows.Next() { + var particleID string + var info AckInfo + if err := rows.Scan(&particleID, &info.Email, &info.AckedAt); err != nil { + return nil, err + } + result[particleID] = append(result[particleID], info) + } + return result, rows.Err() +} diff --git a/go/internal/particle/service.go b/go/internal/particle/service.go new file mode 100644 index 0000000..684ce32 --- /dev/null +++ b/go/internal/particle/service.go @@ -0,0 +1,954 @@ +package particle + +import ( + "context" + "encoding/json" + "errors" + "log/slog" + "time" + + "github.com/flowy-live/llink/internal/network" + "github.com/flowy-live/llink/internal/utils" + "github.com/jackc/pgx/v5/pgxpool" +) + +const defaultPageSize = 50 + +type Service interface { + // Create creates a new particle. Caller must be a network member (verified by handler). + // Returns ErrInvalidType, ErrInvalidData, ErrMembersRequired, ErrInvalidParent, ErrAccessDenied, or ErrCapacityExceeded. + Create(ctx context.Context, input CreateInput, requesterEmail string) (*Particle, error) + // GetByID returns ErrNotFound or ErrAccessDenied. + GetByID(ctx context.Context, id, requesterEmail string) (*Particle, error) + // Update updates the particle's data. Returns ErrNotFound, ErrAccessDenied, or ErrInvalidData. + Update(ctx context.Context, id string, data json.RawMessage, requesterEmail string) (*Particle, error) + // Delete returns ErrNotFound or ErrAccessDenied. + Delete(ctx context.Context, id, requesterEmail string) error + + // List returns particles in a network. Use parentID=nil for root particles. + // Returns ErrNotFound or ErrAccessDenied if parentID is specified and inaccessible. + List(ctx context.Context, networkID string, parentID *string, requesterEmail string, filter ListFilter, cursor *Cursor, limit int) (*ParticleList, error) + + // OpenStream opens a closed stream. Returns ErrNotFound, ErrAccessDenied, ErrNotAStream, ErrStreamAlreadyOpen, or ErrCapacityExceeded. + OpenStream(ctx context.Context, id, requesterEmail string) error + // CloseStream closes an open stream. Returns ErrNotFound, ErrAccessDenied, ErrNotAStream, or ErrStreamAlreadyClosed. + CloseStream(ctx context.Context, id, requesterEmail string) error + + // SetVisibility changes the particle's visibility mode. Returns ErrNotFound, ErrAccessDenied, or ErrAccessExpansion. + SetVisibility(ctx context.Context, id string, mode VisibilityMode, requesterEmail string) error + // AddMembers adds members to a custom visibility particle. Returns ErrNotFound or ErrAccessDenied. + AddMembers(ctx context.Context, id string, emails []string, requesterEmail string) error + // RemoveMembers removes members from a custom visibility particle. Returns ErrNotFound or ErrAccessDenied. + RemoveMembers(ctx context.Context, id string, emails []string, requesterEmail string) error + + // Seen tracking (private) + MarkSeen(ctx context.Context, id, requesterEmail string) error + MarkSeenBatch(ctx context.Context, ids []string, requesterEmail string) error + + // Ack tracking (public, permanent) + Ack(ctx context.Context, id, requesterEmail string) error + + // Unseen counts for stream list view + GetUnseenCounts(ctx context.Context, networkID string, streamIDs []string, requesterEmail string) (map[string]int, error) + + // Bulk lookups for handler enrichment + GetSeenMap(ctx context.Context, particleIDs []string, requesterEmail string) (map[string]bool, error) + GetAcksMap(ctx context.Context, particleIDs []string) (map[string][]AckInfo, error) + GetMembersMap(ctx context.Context, particleIDs []string) (map[string][]string, error) +} + +type serviceImpl struct { + repo repository + networkSvc network.Service +} + +func NewService(pool *pgxpool.Pool, networkSvc network.Service) Service { + return &serviceImpl{ + repo: newRepository(pool), + networkSvc: networkSvc, + } +} + +// checkAccess verifies that the email has access to the particle based on visibility. +// Assumes the caller is already verified as a network member (handler responsibility). +// Walks up the ancestor chain only when visibility is inherited, stopping at the first +// network_all or custom node. +func (s *serviceImpl) checkAccess(ctx context.Context, particleID, email string) (bool, error) { + ancestors, err := s.repo.getAncestorChain(ctx, particleID) + if err != nil { + return false, err + } + + if len(ancestors) == 0 { + return false, errNotFound + } + + // Build lookup map by ID + byID := make(map[string]*Particle, len(ancestors)) + for _, p := range ancestors { + byID[p.ID] = p + } + + // Start from the target particle (first in chain) and walk up on inherited + current := ancestors[0] + for { + switch current.Visibility { + case VisibilityNetworkAll: + return true, nil + case VisibilityCustom: + return s.repo.isMemberOf(ctx, current.ID, email) + case VisibilityInherited: + if current.ParentID == nil { + // inherited at root is invalid state, deny access + return false, nil + } + parent, ok := byID[*current.ParentID] + if !ok { + return false, nil + } + current = parent + default: + return false, nil + } + } +} + +func (s *serviceImpl) Create(ctx context.Context, input CreateInput, requesterEmail string) (*Particle, error) { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return nil, err + } + + // Validate particle type + if !isValidParticleType(input.Type) { + return nil, ErrInvalidType + } + + // Validate data matches type requirements + if err := validateParticleData(input.Type, input.Data); err != nil { + return nil, err + } + + // MVP visibility rules: + // - Child particles (have parent) → always inherited + // - Root particles (no parent) → cannot be inherited, default network_all + if input.ParentID != nil { + // Children always inherit from parent + input.Visibility = VisibilityInherited + input.Members = nil // no members on inherited particles + + // Reject streams and folders as children (MVP: streams are root-level only) + if input.Type == TypeStream || input.Type == TypeFolder { + return nil, ErrInvalidParent + } + } else { + // Root particles cannot be inherited + if input.Visibility == VisibilityInherited { + return nil, ErrInheritedAtRoot + } + if input.Visibility == "" { + input.Visibility = VisibilityNetworkAll + } + } + + // Custom visibility requires at least one member and must be a stream + if input.Visibility == VisibilityCustom { + if input.Type != TypeStream { + return nil, ErrNotAContainer + } + if len(input.Members) == 0 { + return nil, ErrMembersRequired + } + } + + // Network membership is verified by handler - we only check particle visibility + // If parent specified, check parent access (visibility-based) + if input.ParentID != nil { + hasAccess, err := s.checkAccess(ctx, *input.ParentID, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrInvalidParent + } + return nil, err + } + if !hasAccess { + return nil, ErrAccessDenied + } + } + + // Build the particle + p := &Particle{ + Type: input.Type, + NetworkID: input.NetworkID, + ParentID: input.ParentID, + CreatedByEmail: requesterEmail, + Visibility: input.Visibility, + Data: input.Data, + } + + if p.Data == nil { + p.Data = json.RawMessage("{}") + } + + // For streams, set initial status to open and check capacity + if input.Type == TypeStream { + // Set status to open in the data JSON + data, err := setStreamStatus(p.Data, string(StreamStatusOpen)) + if err != nil { + return nil, err + } + p.Data = data + + // Check and increment capacity + err = s.networkSvc.IncrementOpenStreamCount(ctx, input.NetworkID) + if err != nil { + if errors.Is(err, network.ErrCapacityExceeded) { + return nil, ErrCapacityExceeded + } + return nil, err + } + } + + // Create the particle + created, err := s.repo.create(ctx, p) + if err != nil { + // If we incremented the stream count but creation failed, decrement it + if input.Type == TypeStream { + if decErr := s.networkSvc.DecrementOpenStreamCount(ctx, input.NetworkID); decErr != nil { + slog.Warn("failed to rollback stream count after particle creation failure", "error", decErr, "network_id", input.NetworkID) + } + } + return nil, err + } + + // Add members if custom visibility (only streams for MVP) + if input.Visibility == VisibilityCustom && len(input.Members) > 0 { + normalizedEmails := make([]string, 0, len(input.Members)+1) + // Always include the creator + normalizedEmails = append(normalizedEmails, requesterEmail) + for _, email := range input.Members { + normalized, err := utils.NormalizeEmail(email) + if err != nil { + continue // Skip invalid emails + } + if normalized == requesterEmail { + continue // Already added + } + normalizedEmails = append(normalizedEmails, normalized) + } + if err := s.repo.addMembers(ctx, created.ID, normalizedEmails); err != nil { + return nil, err + } + } + + return created, nil +} + +func (s *serviceImpl) GetByID(ctx context.Context, id, requesterEmail string) (*Particle, error) { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return nil, err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + if !hasAccess { + return nil, ErrAccessDenied + } + + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + return p, nil +} + +func (s *serviceImpl) Update(ctx context.Context, id string, data json.RawMessage, requesterEmail string) (*Particle, error) { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return nil, err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + if !hasAccess { + return nil, ErrAccessDenied + } + + // Get the particle to validate data against its type + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + + // Validate data matches type requirements + if err := validateParticleData(p.Type, data); err != nil { + return nil, err + } + + err = s.repo.update(ctx, id, data, time.Now()) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + + return s.repo.getByID(ctx, id) +} + +func (s *serviceImpl) Delete(ctx context.Context, id, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + // Get the particle to check if it's an open stream + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + // If it's an open stream, decrement the count + if p.Type == TypeStream && getStreamStatus(p.Data) == string(StreamStatusOpen) { + if err := s.networkSvc.DecrementOpenStreamCount(ctx, p.NetworkID); err != nil { + return err + } + } + + err = s.repo.delete(ctx, id) + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err +} + +func (s *serviceImpl) List(ctx context.Context, networkID string, parentID *string, requesterEmail string, filter ListFilter, cursor *Cursor, limit int) (*ParticleList, error) { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return nil, err + } + + // Network membership is verified by handler - we only check particle visibility + // If parentID specified, check access to parent (visibility-based) + if parentID != nil { + hasAccess, err := s.checkAccess(ctx, *parentID, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, ErrNotFound + } + return nil, err + } + if !hasAccess { + return nil, ErrAccessDenied + } + } + + // Fetch one extra to determine if there are more + // Access filtering is done in the query itself (network_all OR user is member) + if limit == 0 { + limit = defaultPageSize + } + extraLimit := limit + 1 + particles, err := s.repo.list(ctx, networkID, parentID, requesterEmail, filter, extraLimit, cursor) + if err != nil { + return nil, err + } + + hasMore := len(particles) > limit + result := &ParticleList{ + HasMore: hasMore, + } + + if hasMore { + particles = particles[:limit] + } + result.Particles = particles + + // Bidirectional cursors + if len(particles) > 0 { + firstParticle := particles[0] + lastParticle := particles[len(particles)-1] + + result.PrevCursor = &Cursor{ + Position: firstParticle.UpdatedAt.Format(time.RFC3339Nano), + Direction: "before", + } + + if result.HasMore { + result.NextCursor = &Cursor{ + Position: lastParticle.UpdatedAt.Format(time.RFC3339Nano), + Direction: "after", + } + } + } + + return result, nil +} + +func (s *serviceImpl) OpenStream(ctx context.Context, id, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + // Get the particle + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + if p.Type != TypeStream { + return ErrNotAStream + } + + if getStreamStatus(p.Data) == string(StreamStatusOpen) { + return ErrStreamAlreadyOpen + } + + // Check and increment capacity + err = s.networkSvc.IncrementOpenStreamCount(ctx, p.NetworkID) + if err != nil { + if errors.Is(err, network.ErrCapacityExceeded) { + return ErrCapacityExceeded + } + return err + } + + // Update stream status in data + newData, err := setStreamStatus(p.Data, string(StreamStatusOpen)) + if err != nil { + if decErr := s.networkSvc.DecrementOpenStreamCount(ctx, p.NetworkID); decErr != nil { + slog.Warn("failed to rollback stream count after status update failure", "error", decErr, "network_id", p.NetworkID, "particle_id", id) + } + return err + } + + err = s.repo.update(ctx, id, newData, time.Now()) + if err != nil { + // Rollback the capacity increment + if decErr := s.networkSvc.DecrementOpenStreamCount(ctx, p.NetworkID); decErr != nil { + slog.Warn("failed to rollback stream count after particle update failure", "error", decErr, "network_id", p.NetworkID, "particle_id", id) + } + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + return nil +} + +func (s *serviceImpl) CloseStream(ctx context.Context, id, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + // Get the particle + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + if p.Type != TypeStream { + return ErrNotAStream + } + + if getStreamStatus(p.Data) == string(StreamStatusClosed) { + return ErrStreamAlreadyClosed + } + + // Update stream status in data + newData, err := setStreamStatus(p.Data, string(StreamStatusClosed)) + if err != nil { + return err + } + + err = s.repo.update(ctx, id, newData, time.Now()) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + // Decrement capacity + return s.networkSvc.DecrementOpenStreamCount(ctx, p.NetworkID) +} + +func (s *serviceImpl) SetVisibility(ctx context.Context, id string, mode VisibilityMode, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + // Get the particle to check constraints + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + // Root particles cannot be inherited + if mode == VisibilityInherited && p.ParentID == nil { + return ErrInheritedAtRoot + } + + // If expanding to network_all, check that parent's effective visibility allows it + if mode == VisibilityNetworkAll && p.ParentID != nil { + parentVis, err := s.getEffectiveVisibility(ctx, *p.ParentID) + if err != nil { + return err + } + if parentVis == VisibilityCustom { + return ErrAccessExpansion + } + } + + err = s.repo.setVisibility(ctx, id, mode) + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err +} + +// getEffectiveVisibility walks up the inherited chain to find the concrete visibility mode. +func (s *serviceImpl) getEffectiveVisibility(ctx context.Context, particleID string) (VisibilityMode, error) { + ancestors, err := s.repo.getAncestorChain(ctx, particleID) + if err != nil { + return "", err + } + if len(ancestors) == 0 { + return "", errNotFound + } + + byID := make(map[string]*Particle, len(ancestors)) + for _, p := range ancestors { + byID[p.ID] = p + } + + current := ancestors[0] + for { + if current.Visibility != VisibilityInherited { + return current.Visibility, nil + } + if current.ParentID == nil { + return VisibilityNetworkAll, nil + } + parent, ok := byID[*current.ParentID] + if !ok { + return VisibilityNetworkAll, nil + } + current = parent + } +} + +func (s *serviceImpl) AddMembers(ctx context.Context, id string, emails []string, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + // Get the particle to check type and parent access + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + // Only streams can have members + if p.Type != TypeStream { + return ErrNotAContainer + } + + // Validate and normalize emails, check network membership + normalizedEmails := make([]string, 0, len(emails)) + for _, email := range emails { + normalized, err := utils.NormalizeEmail(email) + if err != nil { + continue + } + + // Root stream - check network membership + isMember, err := s.networkSvc.IsMember(ctx, p.NetworkID, normalized) + if err != nil || !isMember { + continue + } + + normalizedEmails = append(normalizedEmails, normalized) + } + + if len(normalizedEmails) == 0 { + return nil + } + + return s.repo.addMembers(ctx, id, normalizedEmails) +} + +func (s *serviceImpl) RemoveMembers(ctx context.Context, id string, emails []string, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + // Get the particle to check type + p, err := s.repo.getByID(ctx, id) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + + // Only streams can have members + if p.Type != TypeStream { + return ErrNotAContainer + } + + normalizedEmails := make([]string, 0, len(emails)) + for _, email := range emails { + normalized, err := utils.NormalizeEmail(email) + if err != nil { + continue + } + normalizedEmails = append(normalizedEmails, normalized) + } + + if len(normalizedEmails) == 0 { + return nil + } + + return s.repo.removeMembers(ctx, id, normalizedEmails) +} + +func (s *serviceImpl) MarkSeen(ctx context.Context, id, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + return s.repo.markSeen(ctx, id, requesterEmail) +} + +func (s *serviceImpl) MarkSeenBatch(ctx context.Context, ids []string, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access for each particle and mark seen + for _, id := range ids { + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + continue // Skip non-existent particles + } + return err + } + if !hasAccess { + continue // Skip inaccessible particles + } + + if err := s.repo.markSeen(ctx, id, requesterEmail); err != nil { + return err + } + } + + return nil +} + +func (s *serviceImpl) Ack(ctx context.Context, id, requesterEmail string) error { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return err + } + + // Check access + hasAccess, err := s.checkAccess(ctx, id, requesterEmail) + if err != nil { + if errors.Is(err, errNotFound) { + return ErrNotFound + } + return err + } + if !hasAccess { + return ErrAccessDenied + } + + // Ack also marks as seen + if err := s.repo.markSeen(ctx, id, requesterEmail); err != nil { + return err + } + + return s.repo.ack(ctx, id, requesterEmail) +} + +func (s *serviceImpl) GetUnseenCounts(ctx context.Context, networkID string, streamIDs []string, requesterEmail string) (map[string]int, error) { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return nil, err + } + + return s.repo.getUnseenCounts(ctx, streamIDs, requesterEmail) +} + +func (s *serviceImpl) GetSeenMap(ctx context.Context, particleIDs []string, requesterEmail string) (map[string]bool, error) { + requesterEmail, err := utils.NormalizeEmail(requesterEmail) + if err != nil { + return nil, err + } + + return s.repo.getSeenMap(ctx, particleIDs, requesterEmail) +} + +func (s *serviceImpl) GetAcksMap(ctx context.Context, particleIDs []string) (map[string][]AckInfo, error) { + return s.repo.getAcksMap(ctx, particleIDs) +} + +func (s *serviceImpl) GetMembersMap(ctx context.Context, particleIDs []string) (map[string][]string, error) { + return s.repo.getMembersMap(ctx, particleIDs) +} + +func isValidParticleType(t ParticleType) bool { + switch t { + case TypeStream, TypeFolder, TypeMedia, TypeFile, TypeText, TypeQuest, TypePaper: + return true + default: + return false + } +} + +// getStreamStatus extracts the status from a stream particle's data +func getStreamStatus(data json.RawMessage) string { + var d StreamData + if err := json.Unmarshal(data, &d); err != nil { + return "" + } + return d.Status +} + +// setStreamStatus updates the status in a stream particle's data +func setStreamStatus(data json.RawMessage, status string) (json.RawMessage, error) { + var d StreamData + if err := json.Unmarshal(data, &d); err != nil { + d = StreamData{} + } + d.Status = status + return json.Marshal(d) +} + +// validateParticleData validates that the data field contains valid JSON +// and has required fields for the given particle type. +func validateParticleData(pType ParticleType, data json.RawMessage) error { + // Empty or null data is allowed - will default to {} + if len(data) == 0 || string(data) == "null" || string(data) == "{}" { + return nil + } + + switch pType { + case TypeStream: + var d StreamData + if err := json.Unmarshal(data, &d); err != nil { + return errors.Join(ErrInvalidData, err) + } + if d.Name == "" { + return errors.Join(ErrInvalidData, errors.New("stream requires name")) + } + if d.Status != string(StreamStatusOpen) && d.Status != string(StreamStatusClosed) { + return errors.Join(ErrInvalidData, errors.New("stream requires valid status")) + } + + case TypeFolder: + var d FolderData + if err := json.Unmarshal(data, &d); err != nil { + return errors.Join(ErrInvalidData, err) + } + if d.Name == "" { + return errors.Join(ErrInvalidData, errors.New("folder requires name")) + } + + case TypeMedia: + var d MediaData + if err := json.Unmarshal(data, &d); err != nil { + return errors.Join(ErrInvalidData, err) + } + if d.ObjectID == "" { + return errors.Join(ErrInvalidData, errors.New("media requires object_id")) + } + if d.MimeType == "" { + return errors.Join(ErrInvalidData, errors.New("media requires mime_type")) + } + if d.DurationMs <= 0 { + return errors.Join(ErrInvalidData, errors.New("media requires positive duration_ms")) + } + + case TypeFile: + var d FileData + if err := json.Unmarshal(data, &d); err != nil { + return errors.Join(ErrInvalidData, err) + } + if d.ObjectID == "" { + return errors.Join(ErrInvalidData, errors.New("file requires object_id")) + } + if d.Filename == "" { + return errors.Join(ErrInvalidData, errors.New("file requires filename")) + } + if d.MimeType == "" { + return errors.Join(ErrInvalidData, errors.New("file requires mime_type")) + } + if d.Size <= 0 { + return errors.Join(ErrInvalidData, errors.New("file requires non-negative size")) + } + + case TypeText: + var d TextData + if err := json.Unmarshal(data, &d); err != nil { + return errors.Join(ErrInvalidData, err) + } + if d.Content == "" { + return errors.Join(ErrInvalidData, errors.New("text requires content")) + } + + case TypeQuest: + var d QuestData + if err := json.Unmarshal(data, &d); err != nil { + return errors.Join(ErrInvalidData, err) + } + if d.Title == "" { + return errors.Join(ErrInvalidData, errors.New("quest requires title")) + } + if d.Description == "" { + return errors.Join(ErrInvalidData, errors.New("quest requires description")) + } + + case TypePaper: + var d PaperData + if err := json.Unmarshal(data, &d); err != nil { + return errors.Join(ErrInvalidData, err) + } + if d.Title == "" { + return errors.Join(ErrInvalidData, errors.New("paper requires title")) + } + if d.Content == "" { + return errors.Join(ErrInvalidData, errors.New("paper requires content")) + } + } + + return nil +} diff --git a/go/internal/particle/service_test.go b/go/internal/particle/service_test.go new file mode 100644 index 0000000..7832a92 --- /dev/null +++ b/go/internal/particle/service_test.go @@ -0,0 +1,399 @@ +package particle_test + +import ( + "context" + "encoding/json" + "os" + "testing" + + "github.com/flowy-live/llink/internal/network" + "github.com/flowy-live/llink/internal/particle" + "github.com/flowy-live/llink/internal/testhelper" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/stretchr/testify/assert" +) + +var dbPool *pgxpool.Pool + +func TestMain(m *testing.M) { + dbPool = testhelper.SetupTestDB() + defer testhelper.TeardownTestDB() + + ret := m.Run() + os.Exit(ret) +} + +func getStreamStatus(data json.RawMessage) string { + var d struct { + Status string `json:"status"` + } + json.Unmarshal(data, &d) + return d.Status +} + +func TestParticleService_CreateAndGet(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network first + net, err := networkSvc.Create(ctx, "Test Network", "admin@example.com") + assert.NoError(t, err) + + // Test Create stream particle + data := json.RawMessage(`{"name":"My Stream","status":"open","description":"A test stream"}`) + input := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: net.ID, + Data: data, + } + created, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + assert.NotEmpty(t, created.ID) + assert.Equal(t, particle.TypeStream, created.Type) + assert.Equal(t, net.ID, created.NetworkID) + assert.Nil(t, created.ParentID) + assert.Equal(t, particle.VisibilityNetworkAll, created.Visibility) + assert.Equal(t, string(particle.StreamStatusOpen), getStreamStatus(created.Data)) + + // Test GetByID + found, err := svc.GetByID(ctx, created.ID, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, created.ID, found.ID) + + // Test GetByID with non-existent id + _, err = svc.GetByID(ctx, "particle_nonexistent", "admin@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrNotFound) + + // Note: Network membership check is handler's responsibility + // Service assumes caller is already verified as network member +} + +func TestParticleService_StreamCapacity(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network with capacity 2 + net, err := networkSvc.Create(ctx, "Capacity Test Network", "admin@example.com") + assert.NoError(t, err) + + err = networkSvc.SetOpenStreamCapacity(ctx, net.ID, 2) + assert.NoError(t, err) + + // Create first stream - should succeed + input := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: net.ID, + Data: json.RawMessage(`{"name":"Stream 1","status":"open"}`), + } + stream1, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + + // Create second stream - should succeed + input.Data = json.RawMessage(`{"name":"Stream 2","status":"open"}`) + stream2, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + + // Create third stream - should fail with capacity exceeded + input.Data = json.RawMessage(`{"name":"Stream 3","status":"open"}`) + _, err = svc.Create(ctx, input, "admin@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrCapacityExceeded) + + // Close a stream + err = svc.CloseStream(ctx, stream1.ID, "admin@example.com") + assert.NoError(t, err) + + // Now we can create another stream + stream3, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + assert.NotEmpty(t, stream3.ID) + + // Verify stream2 is still open + found, err := svc.GetByID(ctx, stream2.ID, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, string(particle.StreamStatusOpen), getStreamStatus(found.Data)) + + // Verify stream1 is closed + found, err = svc.GetByID(ctx, stream1.ID, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, string(particle.StreamStatusClosed), getStreamStatus(found.Data)) +} + +func TestParticleService_NestedParticles(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network + net, err := networkSvc.Create(ctx, "Nested Test Network", "admin@example.com") + assert.NoError(t, err) + + // Create a parent stream + streamInput := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: net.ID, + Data: json.RawMessage(`{"name":"Parent Stream","status":"open"}`), + } + stream, err := svc.Create(ctx, streamInput, "admin@example.com") + assert.NoError(t, err) + + // Create a text particle as child + textInput := particle.CreateInput{ + Type: particle.TypeText, + NetworkID: net.ID, + ParentID: &stream.ID, + Data: json.RawMessage(`{"content":"Hello world"}`), + } + text, err := svc.Create(ctx, textInput, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, stream.ID, *text.ParentID) + + // Create a file as child of stream + fileInput := particle.CreateInput{ + Type: particle.TypeFile, + NetworkID: net.ID, + ParentID: &stream.ID, + Data: json.RawMessage(`{"object_id":"obj_abc123","filename":"test.pdf","mime_type":"application/pdf","size":1024}`), + } + file, err := svc.Create(ctx, fileInput, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, stream.ID, *file.ParentID) + + // List children of stream + children, err := svc.List(ctx, net.ID, &stream.ID, "admin@example.com", particle.ListFilter{}, nil, 50) + assert.NoError(t, err) + assert.Len(t, children.Particles, 2) +} + +func TestParticleService_CustomVisibility(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network with a member + net, err := networkSvc.Create(ctx, "Visibility Test Network", "admin@example.com") + assert.NoError(t, err) + + err = networkSvc.AddMembers(ctx, net.ID, []string{"member@example.com", "other@example.com"}) + assert.NoError(t, err) + + // Create a stream with custom visibility including only admin and member + streamInput := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: net.ID, + Visibility: particle.VisibilityCustom, + Members: []string{"admin@example.com", "member@example.com"}, + Data: json.RawMessage(`{"name":"Private Stream","status":"open"}`), + } + stream, err := svc.Create(ctx, streamInput, "admin@example.com") + assert.NoError(t, err) + + // Admin can access + _, err = svc.GetByID(ctx, stream.ID, "admin@example.com") + assert.NoError(t, err) + + // Member can access + _, err = svc.GetByID(ctx, stream.ID, "member@example.com") + assert.NoError(t, err) + + // Other network member cannot access + _, err = svc.GetByID(ctx, stream.ID, "other@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrAccessDenied) + + // Non-network member cannot access + _, err = svc.GetByID(ctx, stream.ID, "stranger@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrAccessDenied) +} + +func TestParticleService_UpdateAndDelete(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network + net, err := networkSvc.Create(ctx, "Update Test Network", "admin@example.com") + assert.NoError(t, err) + + // Create a text particle + input := particle.CreateInput{ + Type: particle.TypeText, + NetworkID: net.ID, + Data: json.RawMessage(`{"content":"Original content"}`), + } + created, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + + // Update the particle + newData := json.RawMessage(`{"content":"Updated content"}`) + updated, err := svc.Update(ctx, created.ID, newData, "admin@example.com") + assert.NoError(t, err) + // PostgreSQL normalizes JSON, so compare unmarshaled values + var expected, actual map[string]interface{} + json.Unmarshal(newData, &expected) + json.Unmarshal(updated.Data, &actual) + assert.Equal(t, expected, actual) + + // Delete the particle + err = svc.Delete(ctx, created.ID, "admin@example.com") + assert.NoError(t, err) + + // Verify it's gone + _, err = svc.GetByID(ctx, created.ID, "admin@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrNotFound) +} + +func TestParticleService_ListRootParticles(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network + net, err := networkSvc.Create(ctx, "List Test Network", "admin@example.com") + assert.NoError(t, err) + + // Create multiple root particles + for i := 0; i < 3; i++ { + input := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: net.ID, + Data: json.RawMessage(`{"name":"Stream","status":"open"}`), + } + _, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + } + + // List root particles (parentID = nil) + list, err := svc.List(ctx, net.ID, nil, "admin@example.com", particle.ListFilter{}, nil, 50) + assert.NoError(t, err) + assert.GreaterOrEqual(t, len(list.Particles), 3) +} + +func TestParticleService_OpenCloseStream(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network + net, err := networkSvc.Create(ctx, "Open Close Test Network", "admin@example.com") + assert.NoError(t, err) + + // Create a stream + input := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: net.ID, + Data: json.RawMessage(`{"name":"Test Stream","status":"open"}`), + } + stream, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, string(particle.StreamStatusOpen), getStreamStatus(stream.Data)) + + // Close the stream + err = svc.CloseStream(ctx, stream.ID, "admin@example.com") + assert.NoError(t, err) + + // Verify it's closed + found, err := svc.GetByID(ctx, stream.ID, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, string(particle.StreamStatusClosed), getStreamStatus(found.Data)) + + // Try to close again - should error + err = svc.CloseStream(ctx, stream.ID, "admin@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrStreamAlreadyClosed) + + // Reopen the stream + err = svc.OpenStream(ctx, stream.ID, "admin@example.com") + assert.NoError(t, err) + + // Verify it's open + found, err = svc.GetByID(ctx, stream.ID, "admin@example.com") + assert.NoError(t, err) + assert.Equal(t, string(particle.StreamStatusOpen), getStreamStatus(found.Data)) + + // Try to open again - should error + err = svc.OpenStream(ctx, stream.ID, "admin@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrStreamAlreadyOpen) +} + +func TestParticleService_NotAStream(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network + net, err := networkSvc.Create(ctx, "Not Stream Test Network", "admin@example.com") + assert.NoError(t, err) + + // Create a text particle + input := particle.CreateInput{ + Type: particle.TypeText, + NetworkID: net.ID, + Data: json.RawMessage(`{"content":"Hello"}`), + } + text, err := svc.Create(ctx, input, "admin@example.com") + assert.NoError(t, err) + + // Try to open it as a stream + err = svc.OpenStream(ctx, text.ID, "admin@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrNotAStream) + + // Try to close it as a stream + err = svc.CloseStream(ctx, text.ID, "admin@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrNotAStream) +} + +func TestParticleService_AccessInheritance(t *testing.T) { + ctx := context.Background() + networkSvc := network.NewService(dbPool) + svc := particle.NewService(dbPool, networkSvc) + + // Create a network with members + net, err := networkSvc.Create(ctx, "Access Inheritance Test Network", "admin@example.com") + assert.NoError(t, err) + + err = networkSvc.AddMembers(ctx, net.ID, []string{"member@example.com", "other@example.com"}) + assert.NoError(t, err) + + // Create a stream with custom visibility (admin and member only) + streamInput := particle.CreateInput{ + Type: particle.TypeStream, + NetworkID: net.ID, + Visibility: particle.VisibilityCustom, + Members: []string{"admin@example.com", "member@example.com"}, + Data: json.RawMessage(`{"name":"Private Stream","status":"open"}`), + } + stream, err := svc.Create(ctx, streamInput, "admin@example.com") + assert.NoError(t, err) + + // Create a child text (network_all visibility) + textInput := particle.CreateInput{ + Type: particle.TypeText, + NetworkID: net.ID, + ParentID: &stream.ID, + Data: json.RawMessage(`{"content":"Child text"}`), + } + text, err := svc.Create(ctx, textInput, "admin@example.com") + assert.NoError(t, err) + + // Admin can access child + _, err = svc.GetByID(ctx, text.ID, "admin@example.com") + assert.NoError(t, err) + + // Member can access child + _, err = svc.GetByID(ctx, text.ID, "member@example.com") + assert.NoError(t, err) + + // Other cannot access child (even though child is network_all, parent restricts) + _, err = svc.GetByID(ctx, text.ID, "other@example.com") + assert.Error(t, err) + assert.ErrorIs(t, err, particle.ErrAccessDenied) +} diff --git a/go/internal/redis.go b/go/internal/redis.go new file mode 100644 index 0000000..473f389 --- /dev/null +++ b/go/internal/redis.go @@ -0,0 +1,46 @@ +package internal + +import ( + "context" + "fmt" + "log/slog" + "os" + + "github.com/flowy-live/llink/internal/utils" + "github.com/redis/go-redis/v9" +) + +func ConnectAndTestRedis(db int) *redis.Client { + redisHost := utils.MustGetEnv("REDIS_HOST") + if redisHost == "" { + slog.Error("must provide REDIS_HOST") + os.Exit(1) + } + redisAddr := fmt.Sprintf("%s:%s", redisHost, "6379") + rdb := redis.NewClient(&redis.Options{ + Addr: redisAddr, + Password: "", // no password set + DB: db, + }) + + err := rdb.Set(context.Background(), "key", "value", 0).Err() + if err != nil { + panic(err) + } + + val, err := rdb.Get(context.Background(), "key").Result() + if err != nil { + panic(err) + } + slog.Debug("redis test", "key", val) + if val != "value" { + panic("unexpected value") + } + + err = rdb.Del(context.Background(), "key").Err() + if err != nil { + panic(err) + } + + return rdb +} diff --git a/go/internal/testhelper/postgres.go b/go/internal/testhelper/postgres.go new file mode 100644 index 0000000..b9c8df3 --- /dev/null +++ b/go/internal/testhelper/postgres.go @@ -0,0 +1,95 @@ +package testhelper + +import ( + "context" + "fmt" + "log/slog" + "os" + "time" + + "github.com/golang-migrate/migrate/v4" + _ "github.com/golang-migrate/migrate/v4/database/postgres" + _ "github.com/golang-migrate/migrate/v4/source/file" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/modules/postgres" + "github.com/testcontainers/testcontainers-go/wait" +) + +var ( + container *postgres.PostgresContainer + dbPool *pgxpool.Pool + ctx = context.Background() +) + +// SetupTestDB starts a PostgreSQL container and returns a connection pool +func SetupTestDB() *pgxpool.Pool { + var err error + + // Start PostgreSQL container + container, err = postgres.Run(ctx, + "postgres:16-alpine", + postgres.WithDatabase("testdb"), + postgres.WithUsername("postgres"), + postgres.WithPassword("testpassword"), + testcontainers.WithWaitStrategy( + wait.ForLog("database system is ready to accept connections"). + WithOccurrence(2). + WithStartupTimeout(60*time.Second), + ), + ) + if err != nil { + slog.Error("failed to start postgres container", "error", err) + os.Exit(1) + } + + // Get connection URL + host, err := container.Host(ctx) + if err != nil { + slog.Error("failed to get container host", "error", err) + os.Exit(1) + } + + port, err := container.MappedPort(ctx, "5432") + if err != nil { + slog.Error("failed to get container port", "error", err) + os.Exit(1) + } + + connectionURL := fmt.Sprintf("postgres://postgres:testpassword@%s:%s/testdb?sslmode=disable", + host, port.Port()) + + // Run migrations + m, err := migrate.New("file://../../migrations", connectionURL) + if err != nil { + slog.Error("failed to create migrate instance", "error", err) + os.Exit(1) + } + defer m.Close() + + if err := m.Up(); err != nil && err != migrate.ErrNoChange { + slog.Error("failed to run migrations", "error", err) + os.Exit(1) + } + + // Create connection pool + dbPool, err = pgxpool.New(ctx, connectionURL) + if err != nil { + slog.Error("failed to create connection pool", "error", err) + os.Exit(1) + } + + return dbPool +} + +// TeardownTestDB cleans up the test database +func TeardownTestDB() { + if dbPool != nil { + dbPool.Close() + } + if container != nil { + if err := container.Terminate(ctx); err != nil { + slog.Error("failed to terminate container", "error", err) + } + } +} diff --git a/go/internal/utils/emails.go b/go/internal/utils/emails.go new file mode 100644 index 0000000..5635f13 --- /dev/null +++ b/go/internal/utils/emails.go @@ -0,0 +1,28 @@ +package utils + +import ( + "errors" + "net/mail" + "strings" +) + +func NormalizeEmail(email string) (string, error) { + if email == "" { + return "", errors.New("email empty") + } + + lower := strings.ToLower(email) + lower = strings.TrimSpace(lower) + + parsed, err := mail.ParseAddress(lower) + if err != nil { + return "", err + } + + return parsed.Address, nil +} + +func IsValidEmail(email string) bool { + _, err := mail.ParseAddress(email) + return err == nil +} diff --git a/go/internal/utils/env.go b/go/internal/utils/env.go new file mode 100644 index 0000000..64dafb7 --- /dev/null +++ b/go/internal/utils/env.go @@ -0,0 +1,35 @@ +package utils + +import ( + "os" + + "github.com/sirupsen/logrus" +) + +// enum of environment variables +type EnvVar string + +const () + +// MustGetEnv returns the value of the environment variable with the given key. +// panics if the variable is not set. +func MustGetEnv[T string | EnvVar](key T) string { + keyString := string(key) + value := os.Getenv(keyString) + if value == "" { + logrus.Errorf("Missing required environment variable %s", key) + panic("Missing required environment variable") + } + + return value +} + +// GetEnv returns the value of the environment variable with the given key. +// returns an empty string if the variable is not set. +func GetEnv(key string) string { + value := os.Getenv(key) + if value == "" { + logrus.Warnf("Missing optional environment variable %s", key) + } + return value +} diff --git a/go/internal/utils/optionals.go b/go/internal/utils/optionals.go new file mode 100644 index 0000000..84b58e8 --- /dev/null +++ b/go/internal/utils/optionals.go @@ -0,0 +1,116 @@ +package utils + +import ( + "errors" + "strconv" +) + +func OptionalBool(input *bool) bool { + if input == nil { + return false + } + + return *input +} + +func CreateOptionalBool(input bool) *bool { + if input == false { + return nil + } + + return &input +} + +// OptionalString converts a non-nil *string to the respective string or returns "". +func OptionalString(input *string) string { + if input == nil { + return "" + } + + return *input +} + +// OptionalInt converts a non-nil *int to the respective int, otherwise returns 0. +func OptionalInt(input *int) int { + if input == nil { + return 0 + } + + return *input +} + +// CreateOptionalInt when given a zero value int (0), it returns a nil *int. +// Otherwise, it gives a proper *int with valid value. +func CreateOptionalInt(input int) *int { + if input == 0 { + return nil + } + + return &input +} + +// CreateOptionalString when given an empty string, it returns a nil *string. +// Otherwise, it gives a proper *string with valid value. +func CreateOptionalString(input string) *string { + if input == "" { + return nil + } + + return &input +} + +// GetNumberFromString converts a string to a number. +// Returns error if the query is not a number. +func GetNumberFromString(input string) (int, error) { + for _, c := range input { + if c < '0' || c > '9' { + return 0, errors.New("invalid input") + } + } + + idAsInt, err := strconv.Atoi(input) + if err != nil || idAsInt <= 0 { + return 0, errors.New("invalid input") + } + + return idAsInt, nil +} + +type Number interface { + int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64 +} + +// OptionalNumber converts a non-nil *NUMBER to the respective number value or returns 0. +func OptionalNumber[T Number](input *T) T { + if input == nil { + return 0 + } + + return *input +} + +// CreateOptionalNumber when given an zero value NUMBER (0), it returns a nil *NUMBER, otherwise, it gives a proper *NUMBER with valid value. +func CreateOptionalNumber[T Number](input T) *T { + if input == 0 { + return nil + } + + return &input +} + +func IntToInt64Pointer(input *int) *int64 { + if input == nil { + return nil + } + val := int64(*input) + return &val +} + +func NumberToNumberPointer[T Number, Y Number](input *T) *Y { + if input == nil { + return nil + } + + val := Y(*input) + return &val +} diff --git a/go/internal/utils/random_generator.go b/go/internal/utils/random_generator.go new file mode 100644 index 0000000..022f091 --- /dev/null +++ b/go/internal/utils/random_generator.go @@ -0,0 +1,32 @@ +package utils + +import ( + "math/rand" + "strings" +) + +const ( + charset = "abcdefghijklmnopqrstuvwxyz0123456789" + charsetNumbers = "0123456789" +) + +// RandomString generates a random string of length n based on self defined charset +func RandomString(length int) string { + sb := strings.Builder{} + sb.Grow(length) + for i := 0; i < length; i++ { + sb.WriteByte(charset[rand.Intn(len(charset))]) + } + return sb.String() +} + +// RandomStringNumbers +func RandomStringNumbers(length int) string { + sb := strings.Builder{} + sb.Grow(length) + for range length { + sb.WriteByte(charsetNumbers[rand.Intn(len(charsetNumbers))]) + } + + return sb.String() +} diff --git a/go/internal/utils/slices.go b/go/internal/utils/slices.go new file mode 100644 index 0000000..f35a78d --- /dev/null +++ b/go/internal/utils/slices.go @@ -0,0 +1,15 @@ +package utils + +func Unique(slice []string) []string { + keys := make(map[string]bool) + list := []string{} + + for _, entry := range slice { + if _, value := keys[entry]; !value { + keys[entry] = true + list = append(list, entry) + } + } + + return list +} diff --git a/go/internal/utils/time.go b/go/internal/utils/time.go new file mode 100644 index 0000000..bdedffb --- /dev/null +++ b/go/internal/utils/time.go @@ -0,0 +1,5 @@ +package utils + +func HoursToMicroseconds[K uint32 | uint64](hours K) int64 { + return int64(hours) * 60 * 60 * 1000000 +} diff --git a/go/internal/utils/urls.go b/go/internal/utils/urls.go new file mode 100644 index 0000000..7d9503d --- /dev/null +++ b/go/internal/utils/urls.go @@ -0,0 +1,15 @@ +package utils + +import "net/url" + +func IsValidURL(urlString string) bool { + _, err := url.ParseRequestURI(urlString) + if err != nil { + return false + } + u, err := url.Parse(urlString) + if err != nil || u.Scheme == "" || u.Host == "" { + return false + } + return true +} diff --git a/go/internal/utils/utils_test.go b/go/internal/utils/utils_test.go new file mode 100644 index 0000000..6152736 --- /dev/null +++ b/go/internal/utils/utils_test.go @@ -0,0 +1,29 @@ +package utils + +import "testing" + +func TestNormalizeEmail(t *testing.T) { + email := "arjun@flowy.live" + normalizedEmail, err := NormalizeEmail(email) + if err != nil { + t.Error("invalid email parse", err) + } + + email = " arjun@flowy.live" + normalizedEmail, err = NormalizeEmail(email) + if err != nil { + t.Error("invalid email parse", err) + } + if normalizedEmail != "arjun@flowy.live" { + t.Errorf("invalid email parse: %s", normalizedEmail) + } + + email = "Arjun@flowy.live" + normalizedEmail, err = NormalizeEmail(email) + if err != nil { + t.Error("invalid email parse", err) + } + if normalizedEmail != "arjun@flowy.live" { + t.Errorf("invalid email parse: %s", normalizedEmail) + } +} diff --git a/go/k8s/dev/orion.yaml b/go/k8s/dev/orion.yaml new file mode 100644 index 0000000..b1bcabf --- /dev/null +++ b/go/k8s/dev/orion.yaml @@ -0,0 +1,111 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: orion +spec: + selector: + matchLabels: + app: orion + replicas: 1 + template: + metadata: + labels: + app: orion + spec: + serviceAccountName: default-service-account + nodeSelector: + cloud.google.com/gke-spot: "true" + terminationGracePeriodSeconds: 15 + containers: + - name: orion + image: "orion" + ports: + - containerPort: 8080 + resources: + requests: + memory: "52Mi" + cpu: 50m + limits: + memory: "52Mi" + cpu: 50m + env: + - name: "PORT" + value: "8080" + - name: "AERO_ADDR" + value: "aero:50051" + - name: "IAM_FOR_GKE_SERVICE_ACCOUNT" + value: "iam-for-gke-sa@flowy-dev-440017.iam.gserviceaccount.com" + - name: "GCS_BUCKET" + value: "flowy-llink-bucket" + - name: "LLINK_POSTGRES_CONNECTION_URL" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LLINK_POSTGRES_CONNECTION_URL + - name: "DEEPGRAM_SECRET" + valueFrom: + secretKeyRef: + name: shared-secrets + key: DEEPGRAM_SECRET + - name: "GCP_PROJECT" + value: "flowy-dev-440017" + - name: "GOOGLE_SERVICE_ACCOUNT_EMAIL" + value: "iam-for-gke-sa@flowy-dev-440017.iam.gserviceaccount.com" + - name: "REDIS_HOST" + value: "10.138.57.187" + +--- + +apiVersion: v1 +kind: Service +metadata: + name: orion +spec: + selector: + app: orion + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + +--- + +kind: HTTPRoute +apiVersion: gateway.networking.k8s.io/v1beta1 +metadata: + name: orion +spec: + parentRefs: + - kind: Gateway + name: external-gateway + hostnames: + - orion.dev.flowy.live + rules: + - backendRefs: + - name: orion + port: 8080 + +--- + +apiVersion: networking.gke.io/v1 +kind: HealthCheckPolicy +metadata: + name: orion-service-health-check +spec: + default: + checkIntervalSec: 15 + timeoutSec: 15 + healthyThreshold: 1 + unhealthyThreshold: 2 + logConfig: + enabled: true + config: + type: HTTP + httpHealthCheck: + portSpecification: USE_FIXED_PORT + port: 8080 + requestPath: /health + targetRef: + group: "" + kind: Service + name: orion diff --git a/go/k8s/migrations.yaml b/go/k8s/migrations.yaml new file mode 100644 index 0000000..0a67a4b --- /dev/null +++ b/go/k8s/migrations.yaml @@ -0,0 +1,20 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: migrations +spec: + template: + spec: + containers: + - name: migrations + image: migrations + command: ["migrate"] + args: ["-path", "/migrations", "-database", "$(LLINK_POSTGRES_CONNECTION_URL)", "up"] + env: + - name: "LLINK_POSTGRES_CONNECTION_URL" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LLINK_POSTGRES_CONNECTION_URL + restartPolicy: Never + backoffLimit: 0 diff --git a/go/migrate_dev.sh b/go/migrate_dev.sh new file mode 100755 index 0000000..f21c7e3 --- /dev/null +++ b/go/migrate_dev.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +echo "# NOTE: if you run into issues with 'dirty' migrations: https://github.com/golang-migrate/migrate/issues/282#issuecomment-530743258" + +export KUBE_CONTEXT=dev +export SKAFFOLD_DEFAULT_REPO=us-west2-docker.pkg.dev/flowy-dev-440017/deployments +kubectl delete job migrations --ignore-not-found --context=$KUBE_CONTEXT +skaffold run -p migrations --kube-context dev + diff --git a/go/migrations/000001_humans.down.sql b/go/migrations/000001_humans.down.sql new file mode 100644 index 0000000..585c50c --- /dev/null +++ b/go/migrations/000001_humans.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS humans; diff --git a/go/migrations/000001_humans.up.sql b/go/migrations/000001_humans.up.sql new file mode 100644 index 0000000..a939f78 --- /dev/null +++ b/go/migrations/000001_humans.up.sql @@ -0,0 +1,5 @@ +CREATE TABLE humans ( + id TEXT PRIMARY KEY, + email VARCHAR(255) NOT NULL UNIQUE, + created_at TIMESTAMPTZ DEFAULT NOW() +); diff --git a/go/migrations/000002_networks.down.sql b/go/migrations/000002_networks.down.sql new file mode 100644 index 0000000..e414a12 --- /dev/null +++ b/go/migrations/000002_networks.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS network_members; +DROP TABLE IF EXISTS networks; diff --git a/go/migrations/000002_networks.up.sql b/go/migrations/000002_networks.up.sql new file mode 100644 index 0000000..e481a3f --- /dev/null +++ b/go/migrations/000002_networks.up.sql @@ -0,0 +1,13 @@ +CREATE TABLE networks ( + id TEXT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + admin_email VARCHAR(255) NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE network_members ( + network_id TEXT NOT NULL REFERENCES networks(id) ON DELETE CASCADE, + email VARCHAR(255) NOT NULL, + joined_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (network_id, email) +); diff --git a/go/migrations/000003_network_capacity.down.sql b/go/migrations/000003_network_capacity.down.sql new file mode 100644 index 0000000..87e9857 --- /dev/null +++ b/go/migrations/000003_network_capacity.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE networks + DROP COLUMN IF EXISTS open_stream_capacity, + DROP COLUMN IF EXISTS open_stream_count; diff --git a/go/migrations/000003_network_capacity.up.sql b/go/migrations/000003_network_capacity.up.sql new file mode 100644 index 0000000..60f848b --- /dev/null +++ b/go/migrations/000003_network_capacity.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE networks + ADD COLUMN open_stream_capacity INTEGER NOT NULL DEFAULT 5, + ADD COLUMN open_stream_count INTEGER NOT NULL DEFAULT 0; diff --git a/go/migrations/000004_particles.down.sql b/go/migrations/000004_particles.down.sql new file mode 100644 index 0000000..d048a08 --- /dev/null +++ b/go/migrations/000004_particles.down.sql @@ -0,0 +1,4 @@ +DROP TABLE IF EXISTS particle_members; +DROP TABLE IF EXISTS particles; +DROP TYPE IF EXISTS visibility_mode; +DROP TYPE IF EXISTS particle_type; diff --git a/go/migrations/000004_particles.up.sql b/go/migrations/000004_particles.up.sql new file mode 100644 index 0000000..6e38c15 --- /dev/null +++ b/go/migrations/000004_particles.up.sql @@ -0,0 +1,30 @@ +CREATE TYPE particle_type AS ENUM ( + 'stream', 'folder', 'media', 'file', 'text', 'quest', 'paper', 'think' +); + +CREATE TYPE visibility_mode AS ENUM ('network_all', 'custom'); + +CREATE TABLE particles ( + id TEXT PRIMARY KEY, + type particle_type NOT NULL, + network_id TEXT NOT NULL REFERENCES networks(id) ON DELETE CASCADE, + parent_id TEXT REFERENCES particles(id) ON DELETE CASCADE, + created_by_email VARCHAR(255) NOT NULL, + visibility visibility_mode NOT NULL DEFAULT 'network_all', + data JSONB NOT NULL DEFAULT '{}', + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE particle_members ( + particle_id TEXT NOT NULL REFERENCES particles(id) ON DELETE CASCADE, + email VARCHAR(255) NOT NULL, + added_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (particle_id, email) +); + +-- Indexes +CREATE INDEX idx_particles_parent_updated ON particles(parent_id, updated_at DESC); +CREATE INDEX idx_particles_network_root ON particles(network_id, updated_at DESC) WHERE parent_id IS NULL; +CREATE INDEX idx_particles_open_streams ON particles(network_id) WHERE type = 'stream' AND data->>'status' = 'open'; +CREATE INDEX idx_particle_members_email ON particle_members(email, particle_id); diff --git a/go/migrations/000005_depot.down.sql b/go/migrations/000005_depot.down.sql new file mode 100644 index 0000000..12081ca --- /dev/null +++ b/go/migrations/000005_depot.down.sql @@ -0,0 +1,2 @@ +DROP INDEX IF EXISTS idx_depot_objects_orphaned; +DROP TABLE IF EXISTS depot_objects; diff --git a/go/migrations/000005_depot.up.sql b/go/migrations/000005_depot.up.sql new file mode 100644 index 0000000..7b4a73f --- /dev/null +++ b/go/migrations/000005_depot.up.sql @@ -0,0 +1,13 @@ +CREATE TABLE depot_objects ( + id TEXT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + content_type VARCHAR(255) NOT NULL, + content_length BIGINT NOT NULL, + bucket_name VARCHAR(255) NOT NULL, + object_key TEXT NOT NULL, + contains_content BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE INDEX idx_depot_objects_orphaned +ON depot_objects(created_at) WHERE contains_content = FALSE; diff --git a/go/migrations/000006_particle_tracking.down.sql b/go/migrations/000006_particle_tracking.down.sql new file mode 100644 index 0000000..a346b3f --- /dev/null +++ b/go/migrations/000006_particle_tracking.down.sql @@ -0,0 +1,4 @@ +DROP INDEX IF EXISTS idx_particle_acks_particle; +DROP INDEX IF EXISTS idx_particle_seen_email; +DROP TABLE IF EXISTS particle_acks; +DROP TABLE IF EXISTS particle_seen; diff --git a/go/migrations/000006_particle_tracking.up.sql b/go/migrations/000006_particle_tracking.up.sql new file mode 100644 index 0000000..18167b5 --- /dev/null +++ b/go/migrations/000006_particle_tracking.up.sql @@ -0,0 +1,21 @@ +-- Seen tracking: private per-user state +CREATE TABLE particle_seen ( + particle_id TEXT NOT NULL REFERENCES particles(id) ON DELETE CASCADE, + email VARCHAR(255) NOT NULL, + seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + PRIMARY KEY (particle_id, email) +); + +-- Ack tracking: public, visible to others +CREATE TABLE particle_acks ( + particle_id TEXT NOT NULL REFERENCES particles(id) ON DELETE CASCADE, + email VARCHAR(255) NOT NULL, + acked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + PRIMARY KEY (particle_id, email) +); + +-- Index for bulk "which particles has this user seen?" +CREATE INDEX idx_particle_seen_email ON particle_seen(email, particle_id); + +-- Index for "who acked this particle?" +CREATE INDEX idx_particle_acks_particle ON particle_acks(particle_id); diff --git a/go/migrations/000007_visibility_inherited.down.sql b/go/migrations/000007_visibility_inherited.down.sql new file mode 100644 index 0000000..6d0440d --- /dev/null +++ b/go/migrations/000007_visibility_inherited.down.sql @@ -0,0 +1,2 @@ +-- PostgreSQL does not support removing enum values. +-- To reverse: UPDATE particles SET visibility = 'network_all' WHERE visibility = 'inherited'; diff --git a/go/migrations/000007_visibility_inherited.up.sql b/go/migrations/000007_visibility_inherited.up.sql new file mode 100644 index 0000000..438c197 --- /dev/null +++ b/go/migrations/000007_visibility_inherited.up.sql @@ -0,0 +1 @@ +ALTER TYPE visibility_mode ADD VALUE 'inherited'; diff --git a/go/protocol b/go/protocol new file mode 160000 index 0000000..d323ba3 --- /dev/null +++ b/go/protocol @@ -0,0 +1 @@ +Subproject commit d323ba3d2b80577048bdfa06a247f12b6b3848c2 diff --git a/go/skaffold.yaml b/go/skaffold.yaml new file mode 100644 index 0000000..11e5f20 --- /dev/null +++ b/go/skaffold.yaml @@ -0,0 +1,58 @@ +apiVersion: skaffold/v4beta11 +kind: Config +metadata: + name: llink-services +build: + local: {} + tagPolicy: + gitCommit: + variant: AbbrevCommitSha + +# NOTE: we use different profiles for a simpler mental model +profiles: + - name: migrations + build: + artifacts: + - image: migrations + context: . + docker: + dockerfile: Dockerfile.migrations + manifests: + rawYaml: + - k8s/migrations.yaml + deploy: + kubectl: {} + + - name: dev + build: + hooks: + before: + # already run in make test + # - command: ["go", "test", "./..."] + artifacts: + - image: orion + context: . + docker: + dockerfile: Dockerfile + manifests: + rawYaml: + - k8s/dev/* + deploy: + kubectl: {} + + - name: prod + build: + hooks: + before: + # already run in make test + # - command: ["go", "test", "./..."] + artifacts: + - image: orion + context: . + docker: + dockerfile: Dockerfile + manifests: + rawYaml: + - k8s/prod/* + deploy: + kubectl: {}