diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..9056b9b --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,80 @@ +name: Deploy to Oracle Cloud VM + +on: + push: + branches: + - dev_oracle + +jobs: + deploy: + runs-on: ubuntu-latest + + env: + OCI_HOST: ${{ secrets.OCI_HOST }} + OCI_USERNAME: ${{ secrets.OCI_USERNAME }} + REPO_NAME: ${{ github.repository }} + API_ENV_CONTENT: ${{ secrets.API_ENV_CONTENT }} + SOCIAL_ENV_CONTENT: ${{ secrets.SOCIAL_ENV_CONTENT }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Configure SSH + run: | + mkdir -p ~/.ssh + echo "${{ secrets.OCI_SSH_KEY }}" | tr -d '\r' > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + echo "Host *" > ~/.ssh/config + echo " StrictHostKeyChecking no" >> ~/.ssh/config + echo " UserKnownHostsFile /dev/null" >> ~/.ssh/config + + - name: Create temp .env files + run: | + echo "$API_ENV_CONTENT" > api.env + echo "$SOCIAL_ENV_CONTENT" > social.env + + - name: Upload .env files to Oracle VM + run: | + scp -i ~/.ssh/id_rsa api.env $OCI_USERNAME@$OCI_HOST:/home/$OCI_USERNAME/app/api-service/.env + scp -i ~/.ssh/id_rsa social.env $OCI_USERNAME@$OCI_HOST:/home/$OCI_USERNAME/app/social-media-service/.env + + - name: Deploy to Oracle Cloud Instance + run: | + ssh -i ~/.ssh/id_rsa $OCI_USERNAME@$OCI_HOST < sudo docker network create --subnet=172.1.1.0/24 kong-net \ No newline at end of file diff --git a/api-gateway/config/kong.conf b/api-gateway/config/kong.conf new file mode 100644 index 0000000..075ab19 --- /dev/null +++ b/api-gateway/config/kong.conf @@ -0,0 +1,18 @@ +# config/kong.conf +database = postgres +pg_host = kong-database +pg_user = kong +pg_password = mykongpassword +pg_database = kong + +plugins = bundled,keycloak-introspection + +admin_listen = 0.0.0.0:8001 +proxy_listen = 0.0.0.0:8000, 0.0.0.0:8443 ssl + +client_id = kong-oidc +client_secret = xxxxxxxx +realm = kong +discovery = http://keycloak:8080/realms/kong/.well-known/openid-configuration +scope = openid +redirect_after_logout_uri = https://localhost/auth/realms/kong/protocol/openid-connect/logout?redirect_uri=https://localhost \ No newline at end of file diff --git a/api-gateway/docker-compose.yml b/api-gateway/docker-compose.yml new file mode 100644 index 0000000..9af5dd5 --- /dev/null +++ b/api-gateway/docker-compose.yml @@ -0,0 +1,89 @@ +version: "3" + +x-kong-env: &kong-env + KONG_DATABASE: postgres + KONG_PG_DATABASE: kong + KONG_PG_HOST: kong-database + KONG_PG_USER: kong + KONG_PG_PASSWORD: kong + +volumes: + kong_data: {} + kong_prefix_vol: + driver_opts: + type: tmpfs + device: tmpfs + kong_tmp_vol: + driver_opts: + type: tmpfs + device: tmpfs + +networks: + kong-net: + ipam: + config: + - subnet: 172.1.1.0/24 + +services: + kong-database: + image: postgres:16-alpine + environment: + POSTGRES_DB: kong + POSTGRES_USER: kong + POSTGRES_PASSWORD: kong + volumes: + - kong_data:/var/lib/postgresql/data + networks: + - kong-net + healthcheck: + test: ["CMD", "pg_isready", "-d", "kong", "-U", "kong"] + interval: 30s + timeout: 10s + retries: 3 + restart: unless-stopped + + kong-migrations: + image: kong:3.5 + command: kong migrations bootstrap + environment: + <<: *kong-env + networks: + - kong-net + depends_on: + - kong-database + restart: on-failure + + kong: + image: kong:3.5 + user: kong + environment: + <<: *kong-env + KONG_ADMIN_ACCESS_LOG: /dev/stdout + KONG_ADMIN_ERROR_LOG: /dev/stderr + KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl + KONG_ADMIN_LISTEN: 0.0.0.0:8001 + KONG_ADMIN_GUI_LISTEN: 0.0.0.0:8002 + KONG_PROXY_ACCESS_LOG: /dev/stdout + KONG_PROXY_ERROR_LOG: /dev/stderr + KONG_PREFIX: /var/run/kong + KONG_TRACING_INSTRUMENTATIONS: request + ports: + - "8000:8000" + - "8443:8443" + - "8001:8001" + - "8444:8444" + - "8002:8002" + networks: + - kong-net + healthcheck: + test: ["CMD", "kong", "health"] + interval: 10s + timeout: 10s + retries: 10 + restart: on-failure + read_only: true + volumes: + - kong_prefix_vol:/var/run/kong + - kong_tmp_vol:/tmp + security_opt: + - no-new-privileges diff --git a/api-gateway/keycloak-introspection/handler.lua b/api-gateway/keycloak-introspection/handler.lua new file mode 100644 index 0000000..b48820c --- /dev/null +++ b/api-gateway/keycloak-introspection/handler.lua @@ -0,0 +1,80 @@ +-- keycloak-introspection/handler.lua + +local http = require("resty.http") +local cjson = require("cjson") + +local KeycloakIntrospectionHandler = { + VERSION = "1.0.0", + PRIORITY = 10, +} + +function KeycloakIntrospectionHandler:access(config) + + -- Get the access token from the request headers + --local access_token = ngx.req.get_headers()["Authorization"] + local access_token= ngx.var.http_authorization + + if not access_token then + ngx.log(ngx.ERR, "Access token not found in request headers") + return ngx.exit(ngx.HTTP_UNAUTHORIZED) + end + -- Introspect the access token with Keycloak + + local introspection_url = config.keycloak_introspection_url + --local access_token = ngx.var.http_authorization + local httpc = http.new() + + + local headers = { + ["Content-Type"] = "application/x-www-form-urlencoded", + ["Authorization"] = "Basic " .. ngx.encode_base64(config.client_id .. ":" .. config.client_secret), + } + + local body = "token=" .. access_token + + local request_options = { + method = "POST", + body = body, + headers = headers, + } + + local res, err = httpc:request_uri(introspection_url, request_options) + + ngx.log(ngx.NOTICE, "Entering access function") + ngx.log(ngx.NOTICE, "body ", cjson.encode(request_options)) + ngx.log(ngx.NOTICE, "Plugin Configuration :", cjson.encode(config)) + + + + + if not res then + ngx.log(ngx.ERR, "Failed to introspect token: ", err) + return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + end + + if res.status ~= 200 then + ngx.log(ngx.ERR, "Token introspection failed with status: ", res.status) + return ngx.exit(ngx.HTTP_UNAUTHORIZED) + end + + -- Parse the introspection response + local introspection_result = cjson.decode(res.body) + ngx.log(ngx.NOTICE, "Introspection result: ", res.body) + + -- Check if the token is active + if not introspection_result.active then + ngx.log(ngx.ERR, "Access token is not active") + return ngx.exit(ngx.HTTP_UNAUTHORIZED) + end + + -- Add introspection result to request headers + ngx.req.set_header("X-User-Id", introspection_result.sub) + ngx.req.set_header("X-Username", introspection_result.username) + + ngx.log(ngx.INFO, "Token introspection successful") + + -- Close the HTTP connection + httpc:close() +end + +return KeycloakIntrospectionHandler \ No newline at end of file diff --git a/api-gateway/keycloak-introspection/schema.lua b/api-gateway/keycloak-introspection/schema.lua new file mode 100644 index 0000000..76f6ad6 --- /dev/null +++ b/api-gateway/keycloak-introspection/schema.lua @@ -0,0 +1,19 @@ +local typedefs = require "kong.db.schema.typedefs" + +return { + name = "keycloak-introspection", + fields = { + { consumer = typedefs.no_consumer }, + { protocols = typedefs.protocols_http }, + { + config = { + type = "record", + fields = { + { keycloak_introspection_url = { type = "string", required = true, match = "https?://.+" } }, + { client_id = { type = "string", required = true, default = "check" } }, + { client_secret = { type = "string", required = true } }, + }, + }, + }, + }, +} \ No newline at end of file diff --git a/api-service/.env b/api-service/.env new file mode 100644 index 0000000..9f2e4be --- /dev/null +++ b/api-service/.env @@ -0,0 +1,3 @@ +GOOGLE_MAPS_API_KEY=AIzaSyBqQhDKu98x-nZO85f-JVoUGgNUw2W_SWE +GOOGLE_GEMINI_API_KEY=AIzaSyAb08virZswAtMDNWXGGfBxM8ECwmFQS1w +PORT=8000 \ No newline at end of file diff --git a/api-service/Dockerfile b/api-service/Dockerfile new file mode 100644 index 0000000..9d4802e --- /dev/null +++ b/api-service/Dockerfile @@ -0,0 +1,27 @@ +# Builder stage +FROM golang:1.24.3-alpine AS builder + +WORKDIR /app + +# Copy go.mod and go.sum and download dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Copy the rest of the source code +COPY . . + +# Build the application +RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-w -s" -o /api-service . + +# Final stage +FROM alpine:latest + +# Copy the built binary from the builder stage +COPY --from=builder /api-service /api-service + +# Expose ports +EXPOSE 8000 +EXPOSE 50051 + +# Set the entrypoint +ENTRYPOINT ["/api-service"] diff --git a/api-service/README.md b/api-service/README.md new file mode 100644 index 0000000..d5914f4 --- /dev/null +++ b/api-service/README.md @@ -0,0 +1,18 @@ + +## Running the Project + + > **Prerequisite:** Install [Go](https://go.dev/doc/install) (version 1.18 or higher). Follow the official installation guide for your operating system before proceeding. + +1. Clone the repository: + ```bash + cd GoTogether-backend/api-service + ``` + +2. Install dependencies and run the service: + ```bash + go mod tidy + go run main.go + +3. The API service will start on the configured port. Check the terminal output for details. + +4. To stop the service, press `Ctrl+C` in the terminal. diff --git a/api-service/api-grpc.md b/api-service/api-grpc.md new file mode 100644 index 0000000..71ad395 --- /dev/null +++ b/api-service/api-grpc.md @@ -0,0 +1,109 @@ +# gRPC API Documentation + +This document outlines the gRPC services provided. + +## Protobuf Definitions + +The gRPC service and message definitions are organized by domain into the following files within the `proto/` directory: + +- `common.proto`: Defines common or example services (like `ExampleGreeter`). +- `maps.proto`: Defines services and messages related to mapping functionalities (Geocoding, Places, Directions, Distance Matrix). +- `gemini.proto`: Defines services and messages for interacting with the Gemini AI model. + +Clients should use these definitions to generate stubs for communication. Each `.proto` file specifies its Go package path (e.g., `api-service/grpc/pb/maps` for `maps.proto`) which will be relevant for Go clients. + +## Services + +This section details the gRPC services provided by the API. + +### Common Services (`common.proto`) + +#### `ExampleGreeter` Service + +This is a simple service for demonstration purposes. + +**Service Name:** `common_proto.ExampleGreeter` + +#### Methods + +##### SayHello + +Sends a greeting. + +* **Request:** `common_proto.HelloRequest` + ```protobuf + message HelloRequest { + string name = 1; + } + ``` +* **Response:** `common_proto.HelloReply` + ```protobuf + message HelloReply { + string message = 1; + } + ``` + +* **Description:** + Takes a `HelloRequest` with a `name` field and returns a `HelloReply` with a `message` field containing a greeting. + +### Maps Services (`maps.proto`) + +#### `Maps` Service +**Service Name:** `maps_proto.Maps` + +Provides access to various Google Maps functionalities. Refer to `proto/maps.proto` for detailed message definitions. + +##### Methods + +###### `Geocode` +Converts a human-readable address into geographic coordinates. +* **Request:** `maps_proto.GeocodeRequest` (contains `address`) +* **Response:** `maps_proto.GeocodeResponse` (contains `results` with `formatted_address`, `location`, and `status`) + +###### `SearchPlaces` +Searches for places based on a query string or location. +* **Request:** `maps_proto.SearchPlacesRequest` (contains `query`, `location`) +* **Response:** `maps_proto.SearchPlacesResponse` (contains `results` of type `maps_proto.Place` and `status`) + +###### `GetPlaceDetails` +Retrieves detailed information about a specific place using its Place ID. +* **Request:** `maps_proto.PlaceDetailsRequest` (contains `place_id`) +* **Response:** `maps_proto.PlaceDetailsResponse` (contains `result` of type `maps_proto.Place` and `status`) + +###### `GetDirections` +Provides directions between an origin and a destination. +* **Request:** `maps_proto.DirectionsRequest` (contains `origin`, `destination`) +* **Response:** `maps_proto.DirectionsResponse` (contains `routes`, `geocoded_waypoints`, and `status`) + +###### `GetDistanceMatrix` +Calculates travel time and distance between one or more origins and destinations. +* **Request:** `maps_proto.DistanceMatrixRequest` (contains `origins`, `destinations`) +* **Response:** `maps_proto.DistanceMatrixResponse` (contains `origin_addresses`, `destination_addresses`, `rows` with element details, and `status`) + +### AI Services (`gemini.proto`) + +#### `Gemini` Service +**Service Name:** `gemini_proto.Gemini` + +Provides access to Google's Gemini AI model for content generation. Refer to `proto/gemini.proto` for detailed message definitions. + +##### Methods + +###### `GenerateContent` +Sends a textual prompt to the Gemini model and receives generated content. +* **Request:** `gemini_proto.GeminiRequest` (contains `prompt`) +* **Response:** `gemini_proto.GeminiResponse` (contains `candidates` with generated `content`, `safety_ratings`, etc.) + +## Connecting to the Server + +The gRPC server in `api-service` runs on port `50051` by default (non-TLS). + +Clients need to generate stubs from the relevant `.proto` files located in the `proto/` directory: +- `common.proto` (for `ExampleGreeter` service) +- `maps.proto` (for `Maps` service) +- `gemini.proto` (for `Gemini` service) + +For Go clients, the generated packages will correspond to the `go_package` options specified in these files: +- `api-service/grpc/pb/common` +- `api-service/grpc/pb/maps` +- `api-service/grpc/pb/gemini` diff --git a/api-service/api.md b/api-service/api.md new file mode 100644 index 0000000..dcaa61e --- /dev/null +++ b/api-service/api.md @@ -0,0 +1,598 @@ +# API Service Endpoints Documentation + +## 1. Geocode Address + +Converts a human-readable address into geographic coordinates (latitude and longitude). + +- **Path:** `/maps/geocode` +- **Method:** `GET` +- **Controller:** `controllers.GeocodeController` +- **Service:** `services.maps.GeocodeService.Geocode()` + +### Request + +#### Query Parameters: + +- `address` (string, required): The street address that you want to geocode. + - Example: `1600 Amphitheatre Parkway, Mountain View, CA` + +#### Example `curl` Request: + +```bash +curl "http://:/maps/geocode?address=1600%20Amphitheatre%20Parkway,%20Mountain%20View,%20CA" +``` + +### Response + +The response is a JSON object mirroring the Google Maps Geocoding API response. + +#### Success (200 OK) + +- **Content-Type:** `application/json` + +##### Body Structure: + +```json +{ + "results": [ + { + "formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", + "geometry": { + "location": { + "lat": 37.4224764, + "lng": -122.0842499 + } + // ... other geometry details from Google API might be present + } + // ... other address components and details from Google API might be present + } + // ... potentially more results if the address is ambiguous + ], + "status": "OK" // Or other Google API statuses like "ZERO_RESULTS" +} +``` + +#### Error Responses: + +- **500 Internal Server Error:** If the backend service fails to connect to the Google API or encounters other issues. + ```json + { + "error": "failed to get geocode: " + } + ``` +- Other error statuses from Google Geocoding API (e.g., `REQUEST_DENIED`, `INVALID_REQUEST`) will be reflected in the `status` field of a 200 OK response from our service, but the body will contain Google's error message. The service's `Geocode` function returns an error if `resp.StatusCode != http.StatusOK`, which the controller then turns into a 500. + +--- +## 2. Search Places + +Searches for places using either a text query or geographic coordinates (for nearby searches). This endpoint now includes fully constructed photo URLs in the response. + +- **Path:** `/maps/places` +- **Method:** `GET` +- **Controller:** `controllers.LocationDataController` +- **Service:** `services.maps.PlacesService.SearchPlaces()` + +### Request + +#### Query Parameters: + +- `query` (string, optional): The text string to search for (e.g., "restaurants in Sydney", "Eiffel Tower"). If provided, a text search is performed. +- `location` (string, optional): Latitude and longitude coordinates (e.g., "37.4224764,-122.0842499"). If `query` is not provided or is empty, and `location` is provided, a nearby search is performed. + - *Note:* The service's `SearchPlaces` function prioritizes `query` over `location` if both are provided. + +#### Example `curl` Requests: + +1. **Text Search:** + ```bash + curl "http://:/maps/places?query=restaurants%20in%20Sydney" + ``` + +2. **Nearby Search (when `query` is omitted):** + ```bash + curl "http://:/maps/places?location=37.4224764,-122.0842499" + ``` + +### Response + +The response is a JSON object based on the Google Maps Places API response, with the addition of the `photo_urls` field. + +#### Success (200 OK) + +- **Content-Type:** `application/json` + +##### Body Structure (`models.PlacesResponse`): + +```json +{ + "results": [ + { + "name": "Example Restaurant", + "vicinity": "123 Main St, Anytown", // Or "address" depending on Google's field name, mapped from "vicinity" + "rating": 4.5, + "user_ratings_total": 100, + "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4", + "types": ["restaurant", "food", "point_of_interest"], + "geometry": { + "location": { + "lat": -33.8670522, + "lng": 151.1957362 + } + }, + "opening_hours": { // Present if available from Google + "open_now": true + }, + "photos": [ // Original 'photos' array from Google API, may contain photo_reference + { + "photo_reference": "CmRaAAAA...", + "height": 800, + "width": 1200 + // ... other HTML attributions if present + } + ], + "photo_urls": [ // <<< NEW FIELD >>> Array of fully constructed photo URLs + "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CmRaAAAA...&key=YOUR_GOOGLE_MAPS_API_KEY" + // ... more URLs if multiple photos exist + ] + } + // ... other results + ], + "status": "OK" // Or other Google API statuses like "ZERO_RESULTS" +} +``` + +#### Error Responses: + +- **500 Internal Server Error:** If the backend service fails to connect to the Google API, encounters issues during processing, or if neither `query` nor `location` is provided. + ```json + { + "error": "failed to search places: " + // or "either query or location must be provided" + } + ``` +- Google API errors (e.g., `REQUEST_DENIED`, `INVALID_REQUEST`) will be reflected in the `status` field of a 200 OK response (if the error occurs at Google's end but after a successful HTTP call), or could lead to a 500 error if our service treats it as a failed fetch. + +--- +## 3. Get Directions + +Provides directions between two locations (origin and destination). + +- **Path:** `/maps/directions` +- **Method:** `GET` +- **Controller:** `controllers.DirectionsController` +- **Service:** `services.maps.DirectionsService.GetDirections()` + +### Request + +#### Query Parameters: + +- `origin` (string, required): The starting point for the directions. + - Example: `Toronto` or `43.6532,-79.3832` +- `destination` (string, required): The ending point for the directions. + - Example: `Montreal` or `45.5017,-73.5673` + +#### Example `curl` Request: + +```bash +curl "http://:/maps/directions?origin=Toronto&destination=Montreal" +``` + +### Response + +The response is a JSON object mirroring the Google Maps Directions API response. The structure can be complex, providing routes, legs, steps, and polylines. + +#### Success (200 OK) + +- **Content-Type:** `application/json` + +##### Body Structure (Simplified Example): + +```json +{ + "routes": [ + { + "summary": "ON-401 E", + "legs": [ + { + "distance": { + "text": "542 km", + "value": 542200 // meters + }, + "duration": { + "text": "5 hours 30 mins", + "value": 19800 // seconds + }, + "start_address": "Toronto, ON, Canada", + "end_address": "Montreal, QC, Canada", + "steps": [ // Array of step-by-step instructions + { + "html_instructions": "Head east on Queen St W toward Bay St", + "distance": {"text": "0.6 km", "value": 600}, + "duration": {"text": "1 min", "value": 60}, + "polyline": { + "points": "encoded_polyline_string" + } + // ... more step details + } + // ... more steps + ] + } + // ... more legs if waypoints were involved (not supported by this simple endpoint) + ], + "overview_polyline": { + "points": "encoded_overview_polyline_string" + }, + "warnings": [], + "bounds": { // Northeast and southwest coordinates of the bounding box for the route + "northeast": {"lat": 45.5017, "lng": -73.5673}, + "southwest": {"lat": 43.6532, "lng": -79.3832} + } + // ... other route details + } + // ... potentially more routes + ], + "geocoded_waypoints": [ // Status for origin and destination geocoding + {"geocoder_status": "OK", "place_id": "ChIJpTvG15DL1IkRd8S0Kl9NkvU", "types": ["locality", "political"]}, + {"geocoder_status": "OK", "place_id": "ChIJDbdkHFQayUwR7-8fMbi8JUA", "types": ["locality", "political"]} + ], + "status": "OK" // Or other Google API statuses like "ZERO_RESULTS", "NOT_FOUND" +} +``` + +#### Error Responses: + +- **500 Internal Server Error:** If the backend service fails to connect to the Google API or encounters other issues. + ```json + { + "error": "failed to get directions: " + } + ``` +- Google API errors (e.g., `NOT_FOUND`, `ZERO_RESULTS`, `REQUEST_DENIED`) will be reflected in the `status` field of the main JSON response (if the HTTP call itself was okay). + +--- +## 4. Get Distance Matrix + +Calculates travel time and distance between one or more origins and destinations. + +- **Path:** `/maps/distance-matrix` +- **Method:** `GET` +- **Controller:** `controllers.DistanceMatrixController` +- **Service:** `services.maps.DistanceMatrixService.GetDistanceMatrix()` + +### Request + +#### Query Parameters: + +- `origins` (string, required): One or more addresses, place IDs, or latitude/longitude coordinates from which to calculate distance and time. If you pass multiple locations, separate them with the pipe character (`|`). + - Example: `Vancouver BC|Seattle` or `49.2827,-123.1207|47.6062,-122.3321` +- `destinations` (string, required): One or more addresses, place IDs, or latitude/longitude coordinates to which to calculate distance and time. If you pass multiple locations, separate them with the pipe character (`|`). + - Example: `San Francisco|Victoria BC` or `37.7749,-122.4194|48.4284,-123.3656` + +#### Example `curl` Request: + +```bash +curl "http://:/maps/distance-matrix?origins=Vancouver%20BC|Seattle&destinations=San%20Francisco|Victoria%20BC" +``` + +### Response + +The response is a JSON object containing origin and destination addresses as returned by Google, and rows corresponding to each origin, each containing elements corresponding to each destination. + +#### Success (200 OK) + +- **Content-Type:** `application/json` + +##### Body Structure (`maps.DistanceMatrixResponse`): + +```json +{ + // Note: The actual Google API response includes "origin_addresses" and "destination_addresses" arrays here. + // The current Go service model DistanceMatrixResponse does not explicitly map these, + // but they would be part of the raw response from Google if you inspected it before decoding. + // The Go model focuses on the "rows" part. + "rows": [ + { // Corresponds to the first origin + "elements": [ + { // Corresponds to the first origin vs first destination + "status": "OK", // e.g., "OK", "NOT_FOUND", "ZERO_RESULTS" + "duration": { + "text": "14 hours 4 mins", // Human-readable duration + "value": 50640 // Duration in seconds + }, + "distance": { + "text": "1,540 km", // Human-readable distance + "value": 1540123 // Distance in meters + } + }, + { // Corresponds to the first origin vs second destination + "status": "OK", + "duration": { + "text": "3 hours 0 mins", + "value": 10800 + }, + "distance": { + "text": "110 km", + "value": 109987 + } + } + // ... more elements if more destinations + ] + }, + { // Corresponds to the second origin + "elements": [ + { // Corresponds to the second origin vs first destination + "status": "OK", + "duration": { + "text": "12 hours 30 mins", + "value": 45000 + }, + "distance": { + "text": "1,350 km", + "value": 1350000 + } + }, + { // Corresponds to the second origin vs second destination + "status": "OK", + "duration": { + "text": "1 hour 30 mins", + "value": 5400 + }, + "distance": { + "text": "70 km", + "value": 70000 + } + } + // ... more elements + ] + } + // ... more rows if more origins + ] + // The Google API also includes a general "status" field for the overall request here. + // Example: "status": "OK" + // This is not explicitly in the current Go service model DistanceMatrixResponse. +} +``` +*Note: The Go model `DistanceMatrixResponse` primarily focuses on the `rows`. The full Google API response also includes `origin_addresses`, `destination_addresses`, and an overall `status` field for the request, which are not explicitly defined in the current Go model but are part of the raw JSON from Google.* + +#### Error Responses: + +- **500 Internal Server Error:** If the backend service fails to connect to the Google API or encounters other issues (e.g., JSON decoding failure). + ```json + { + "error": "failed to get distance matrix: " + } + ``` +- Element-level errors (e.g., a specific origin/destination pair not found) are indicated by the `status` field within each element (e.g., `"NOT_FOUND"`, `"ZERO_RESULTS"`). The overall HTTP status will still be 200 OK if the API call itself succeeded. + +--- +## 5. Get AI Response (Gemini) + +Sends a prompt to a Google Gemini model ("gemini-2.0-flash") and returns its response. + +- **Path:** `/gemini/` +- **Method:** `GET` +- **Controller:** `controllers.GeminiController` +- **Service:** `services.gemini.AIService.GetAIResponse()` +- **Authentication:** Requires `GOOGLE_GEMINI_API_KEY` to be set in the service's environment. + +### Request + +#### Query Parameters: + +- `prompt` (string, required): The prompt or question to send to the AI model. + - Example: `Explain quantum computing in simple terms.` + +#### Example `curl` Request: + +```bash +curl "http://:/gemini/?prompt=Explain%20quantum%20computing%20in%20simple%20terms." +``` + +### Response + +The response is a JSON object based on the Google Gemini API's `GenerateContentResponse`. The exact structure can vary based on the model and request options. + +#### Success (200 OK) + +- **Content-Type:** `application/json` + +##### Body Structure (Simplified Example of `genai.GenerateContentResponse`): + +```json +{ + "candidates": [ + { + "content": { + "parts": [ + { + "text": "Imagine a regular computer uses bits, which are like light switches that are either ON or OFF (0 or 1). Quantum computers use 'qubits'. A qubit is like a dimmer switch that can be ON, OFF, or somewhere in between. It can even be both ON and OFF at the same time (superposition)! This allows quantum computers to explore many possibilities at once, making them super fast for certain complex problems that regular computers would take billions of years to solve, like discovering new medicines or materials." + } + ], + "role": "model" + }, + "finish_reason": "STOP", // e.g., STOP, MAX_TOKENS, SAFETY, RECITATION, OTHER + "index": 0, + "safety_ratings": [ // Array of safety ratings for different categories + {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "probability": "NEGLIGIBLE"}, + {"category": "HARM_CATEGORY_HATE_SPEECH", "probability": "NEGLIGIBLE"}, + {"category": "HARM_CATEGORY_HARASSMENT", "probability": "NEGLIGIBLE"}, + {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "probability": "NEGLIGIBLE"} + ] + // "citation_metadata" might be present if content is sourced + } + ], + "prompt_feedback": { // Feedback on the prompt itself, if applicable + "safety_ratings": [ + {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "probability": "NEGLIGIBLE"}, + {"category": "HARM_CATEGORY_HATE_SPEECH", "probability": "NEGLIGIBLE"}, + {"category": "HARM_CATEGORY_HARASSMENT", "probability": "NEGLIGIBLE"}, + {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "probability": "NEGLIGIBLE"} + ] + // "block_reason" might be present if prompt was blocked + } +} +``` +*Note: The main generated text is typically found within `candidates[0].content.parts[0].text`.* + +#### Error Responses: + +- **500 Internal Server Error:** If the backend service fails to initialize the AI client, connect to the Gemini API, or encounters other issues. + ```json + { + "error": "" + } + ``` +- Errors from the Gemini API itself (e.g., authentication issues if API key is wrong, rate limits) would also typically result in a 500 error from this endpoint with a message from the underlying client library. + +--- +## 6. Get Place Details by ID + +Retrieves detailed information for a specific place given its Google Place ID. This includes name, address, coordinates, photos (with fully constructed URLs), reviews, opening hours, and more. + +- **Path:** `/maps/place/:place_id` +- **Method:** `GET` +- **Controller:** `controllers.PlaceDetailsController` +- **Service:** `services.maps.PlacesService.FindPlaceByID()` + +### Request + +#### Path Parameters: + +- `place_id` (string, required): The Google Place ID for the location you want details for. + - Example: `ChIJN1t_tDeuEmsRUsoyG83frY4` (This is an example ID for Google Sydney) + +#### Example `curl` Request: + +```bash +curl "http://:/maps/place/ChIJN1t_tDeuEmsRUsoyG83frY4" +``` + +### Response + +The response is a JSON object containing the detailed place information. + +#### Success (200 OK) + +- **Content-Type:** `application/json` + +##### Body Structure (`models.PlaceDetailResponse`): + +```json +{ + "result": { + "name": "Google Building 43", + "formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", + "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4", // Example, will match requested ID + "types": ["establishment", "point_of_interest"], + "geometry": { + "location": { + "lat": 37.4224764, + "lng": -122.0842499 + } + }, + "rating": 4.5, + "user_ratings_total": 150, + "photos": [ // Original photo references from Google + { + "photo_reference": "CmRaAAAA...", + "height": 1024, + "width": 768, + "html_attributions": ["<a href=\"https://maps.google.com/maps/contrib/1000...\">A User</a>"] + } + ], + "photo_urls": [ // <<< Fully constructed photo URLs >>> + "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CmRaAAAA...&key=YOUR_GOOGLE_MAPS_API_KEY" + ], + "reviews": [ + { + "author_name": "Jane Doe", + "rating": 5, + "relative_time_description": "a month ago", + "text": "Great place!", + "time": 1609459200 + // other review fields like author_url, profile_photo_url + } + ], + "website": "https://www.google.com/", + "international_phone_number": "+1 650-253-0000", + "formatted_phone_number": "(650) 253-0000", + "opening_hours": { + "open_now": true, + "periods": [ + {"open": {"day": 1, "time": "0800"}, "close": {"day": 1, "time": "1800"}} + // ... other periods + ], + "weekday_text": [ + "Monday: 8:00 AM โ€“ 6:00 PM", + // ... other days + ], + "permanently_closed": false + }, + "vicinity": "1600 Amphitheatre Parkway, Mountain View", + "utc_offset_minutes": -420, + "address_components": [ + // ... array of address components + ] + // ... other fields like utc_offset_minutes, address_components as defined in model + }, + "status": "OK", + "html_attributions": [], + "error_message": null // or empty string +} +``` + +#### Error Responses: + +- **400 Bad Request:** If `place_id` is missing or malformed (based on Google's validation). + - Response body example (if `placeDetails.Status == "INVALID_REQUEST"`): + ```json + { + "result": {}, // Or minimal result structure + "status": "INVALID_REQUEST", + "error_message": "The place ID '...' is not valid." // Example message from Google + } + ``` +- **403 Forbidden:** If the API key is invalid or lacks permissions for Places Details. + - Response body example (if `placeDetails.Status == "REQUEST_DENIED"`): + ```json + { + "result": {}, + "status": "REQUEST_DENIED", + "error_message": "Your request was denied." // Example message from Google + } + ``` +- **404 Not Found:** If the `place_id` does not correspond to a known place. + - Response body example (if `placeDetails.Status == "NOT_FOUND"`): + ```json + { + "result": {}, // Or minimal result structure + "status": "NOT_FOUND", + "error_message": null // Error message might be null if status is NOT_FOUND + } + ``` +- **429 Too Many Requests:** If the API key has exceeded its query limit. + - Response body example (if `placeDetails.Status == "OVER_QUERY_LIMIT"`): + ```json + { + "result": {}, + "status": "OVER_QUERY_LIMIT", + "error_message": "You have exceeded your daily request quota for this API." // Example + } + ``` +- **500 Internal Server Error:** For other backend issues or unexpected errors from Google (e.g., `UNKNOWN_ERROR`). + - Response body example: + ```json + { + "error": "Failed to retrieve place details", + "details": "" + } + ``` + Or, if Google returns an `UNKNOWN_ERROR` status within the response object: + ```json + { + "result": {}, + "status": "UNKNOWN_ERROR", + "error_message": "An unexpected error occurred." // Example + } + ``` + +--- diff --git a/api-service/config/config.go b/api-service/config/config.go new file mode 100644 index 0000000..5251f55 --- /dev/null +++ b/api-service/config/config.go @@ -0,0 +1,21 @@ +package config + +import ( + "log" + "os" + + "github.com/joho/godotenv" +) + +func LoadEnv() { + if err := godotenv.Load(); err != nil { + log.Println("No .env file found") + } +} + +func GetEnv(key, fallback string) string { + if value := os.Getenv(key); value != "" { + return value + } + return fallback +} diff --git a/api-service/controllers/gemini_controller.go b/api-service/controllers/gemini_controller.go new file mode 100644 index 0000000..4ef130d --- /dev/null +++ b/api-service/controllers/gemini_controller.go @@ -0,0 +1,22 @@ +package controllers + +import ( + "api-service/services/gemini" + "net/http" + "os" + + "github.com/gin-gonic/gin" +) + +var AIService = gemini.NewAIService(os.Getenv("GOOGLE_GEMINI_API_KEY")) + +func GeminiController(c *gin.Context) { + prompt := c.Query("prompt") + + directions, err := AIService.GetAIResponse(prompt) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, directions) +} diff --git a/api-service/controllers/maps_controller.go b/api-service/controllers/maps_controller.go new file mode 100644 index 0000000..3e5c861 --- /dev/null +++ b/api-service/controllers/maps_controller.go @@ -0,0 +1,102 @@ +package controllers + +import ( + "api-service/services/maps" + "net/http" + "strings" // Added strings import + + "github.com/gin-gonic/gin" +) + +var directionsService = maps.NewDirectionsService() +var distanceMatrixService = maps.NewDistanceMatrixService() +var geocodeService = maps.NewGeocodeService() +var placesService = maps.NewPlacesService() + +func DirectionsController(c *gin.Context) { + // Logic to handle directions request + origin := c.Query("origin") + destination := c.Query("destination") + + directions, err := directionsService.GetDirections(origin, destination) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, directions) +} + +func DistanceMatrixController(c *gin.Context) { + // Logic to handle distance matrix request + origins := c.Query("origins") + destinations := c.Query("destinations") + + distanceMatrix, err := distanceMatrixService.GetDistanceMatrix(origins, destinations) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, distanceMatrix) +} + +func GeocodeController(c *gin.Context) { + address := c.Query("address") + geocode, err := geocodeService.Geocode(address) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, geocode) +} + +func LocationDataController(c *gin.Context) { + query := c.Query("query") + location := c.Query("location") + places, err := placesService.SearchPlaces(query, location) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, places) +} + +func PlaceDetailsController(c *gin.Context) { + placeID := c.Param("place_id") + if placeID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "place_id parameter is required"}) + return + } + + response, err := placesService.FindPlaceByID(placeID) // placesService is already initialized globally + + if err != nil { + // Default to 500 + statusCode := http.StatusInternalServerError + // Try to refine based on response content if available + if response != nil { + switch response.Status { + case "NOT_FOUND": + statusCode = http.StatusNotFound + case "INVALID_REQUEST": + statusCode = http.StatusBadRequest + case "REQUEST_DENIED": + statusCode = http.StatusForbidden // Or StatusBadRequest + case "OVER_QUERY_LIMIT": + statusCode = http.StatusTooManyRequests + // No default case needed here, statusCode is already 500 + } + c.JSON(statusCode, response) // Send the whole response from Google which includes error details + } else { + // If response is nil, just send the error message + // Attempt to infer from error string for NOT_FOUND as a common case + if strings.Contains(strings.ToUpper(err.Error()), "NOT_FOUND") { + statusCode = http.StatusNotFound + } + c.JSON(statusCode, gin.H{"error": err.Error()}) + } + return + } + + // If err is nil, response must be non-nil and response.Status should be "OK" + c.JSON(http.StatusOK, response) +} diff --git a/api-service/go.mod b/api-service/go.mod new file mode 100644 index 0000000..b459d04 --- /dev/null +++ b/api-service/go.mod @@ -0,0 +1,68 @@ +module api-service + +go 1.24.2 + +require ( + github.com/gin-gonic/gin v1.10.0 + github.com/google/generative-ai-go v0.20.1 + github.com/joho/godotenv v1.5.1 + google.golang.org/genai v1.4.0 + google.golang.org/grpc v1.72.2 + google.golang.org/protobuf v1.36.6 +) + +require ( + cloud.google.com/go v0.116.0 // indirect + cloud.google.com/go/ai v0.8.0 // indirect + cloud.google.com/go/auth v0.9.3 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/longrunning v0.5.7 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/s2a-go v0.1.8 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect + golang.org/x/arch v0.16.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/oauth2 v0.26.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect + golang.org/x/time v0.6.0 // indirect + google.golang.org/api v0.197.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/api-service/go.sum b/api-service/go.sum new file mode 100644 index 0000000..e64d93b --- /dev/null +++ b/api-service/go.sum @@ -0,0 +1,238 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/ai v0.8.0 h1:rXUEz8Wp2OlrM8r1bfmpF2+VKqc1VJpafE3HgzRnD/w= +cloud.google.com/go/ai v0.8.0/go.mod h1:t3Dfk4cM61sytiggo2UyGsDVW3RF1qGZaUKDrZFyqkE= +cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= +cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= +cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/generative-ai-go v0.20.1 h1:6dEIujpgN2V0PgLhr6c/M1ynRdc7ARtiIDPFzj45uNQ= +github.com/google/generative-ai-go v0.20.1/go.mod h1:TjOnZJmZKzarWbjUJgy+r3Ee7HGBRVLhOIgupnwR4Bg= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +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/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U= +golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= +golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.197.0 h1:x6CwqQLsFiA5JKAiGyGBjc2bNtHtLddhJCE2IKuhhcQ= +google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genai v1.4.0 h1:i3D6q5UTLoAHuXOaDtJnA4Lcz6v+aBP3phGBYOgzEm4= +google.golang.org/genai v1.4.0/go.mod h1:TyfOKRz/QyCaj6f/ZDt505x+YreXnY40l2I6k8TvgqY= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= +google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/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.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= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/api-service/grpc/common_server.go b/api-service/grpc/common_server.go new file mode 100644 index 0000000..577663b --- /dev/null +++ b/api-service/grpc/common_server.go @@ -0,0 +1,25 @@ +package grpc + +import ( + "context" + "log" + + pb_common "api-service/grpc/pb/common" // Alias for the new common protobuf package + // No more maps or gemini specific imports here +) + +// ExampleGreeterServerImpl is used to implement pb_common.ExampleGreeterServer. +type ExampleGreeterServerImpl struct { + pb_common.UnimplementedExampleGreeterServer +} + +// SayHello implements pb_common.ExampleGreeterServer +func (s *ExampleGreeterServerImpl) SayHello(ctx context.Context, in *pb_common.HelloRequest) (*pb_common.HelloReply, error) { + log.Printf("Received gRPC SayHello request: %v", in.GetName()) + return &pb_common.HelloReply{Message: "Hello " + in.GetName()}, nil +} + +// Note: All MapsServerImpl, GeminiServerImpl, their specific service interfaces (IPlacesService, IAIService, etc.), +// and their patchable constructor functions (newPlacesServiceFunc, newAIServiceFunc, etc.) +// have been moved to maps_server.go and gemini_server.go respectively. +// This file now only contains common/example server implementations. diff --git a/api-service/grpc/common_server_test.go b/api-service/grpc/common_server_test.go new file mode 100644 index 0000000..7cbef91 --- /dev/null +++ b/api-service/grpc/common_server_test.go @@ -0,0 +1,47 @@ +package grpc + +import ( + "context" + "testing" + + pb_common "api-service/grpc/pb/common" // Updated import +) + +func TestSayHello(t *testing.T) { + s := ExampleGreeterServerImpl{} // Use specific server implementation + + tests := []struct { + name string + reqName string + wantMsg string + }{ + { + name: "StandardGreeting", + reqName: "Jules", + wantMsg: "Hello Jules", + }, + { + name: "EmptyName", + reqName: "", + wantMsg: "Hello ", + }, + { + name: "DifferentName", + reqName: "Tester", + wantMsg: "Hello Tester", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := &pb_common.HelloRequest{Name: tt.reqName} // Updated type + resp, err := s.SayHello(context.Background(), req) + if err != nil { + t.Fatalf("SayHello(%v) got unexpected error: %v", req, err) + } + if resp.Message != tt.wantMsg { + t.Errorf("SayHello(%v) = %q, want %q", req, resp.Message, tt.wantMsg) + } + }) + } +} diff --git a/api-service/grpc/gemini_server.go b/api-service/grpc/gemini_server.go new file mode 100644 index 0000000..32a9b63 --- /dev/null +++ b/api-service/grpc/gemini_server.go @@ -0,0 +1,104 @@ +package grpc + +import ( + "context" + "log" + + "api-service/config" + "api-service/services/gemini" + pb_gemini "api-service/grpc/pb/gemini" // Alias for the new gemini protobuf package + + "github.com/google/generative-ai-go/genai" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// --- Service Interface for Gemini --- +type IAIService interface { + GetAIResponse(prompt string) (interface{}, error) +} + +// --- Patchable Service Constructor for Gemini --- +var ( + newAIServiceFunc func(apiKey string) IAIService = func(apiKey string) IAIService { return gemini.NewAIService(apiKey) } +) + +// GeminiServerImpl implements pb_gemini.GeminiServer +type GeminiServerImpl struct { + pb_gemini.UnimplementedGeminiServer +} + +// --- GeminiService Implementation --- +func (s *GeminiServerImpl) GenerateContent(ctx context.Context, req *pb_gemini.GeminiRequest) (*pb_gemini.GeminiResponse, error) { + log.Printf("Received gRPC GenerateContent request for prompt (first 100 chars): %.100s", req.GetPrompt()) + + apiKey := config.GetEnv("GOOGLE_GEMINI_API_KEY", "") + if apiKey == "" { + log.Printf("GOOGLE_GEMINI_API_KEY not set in environment") + return nil, status.Errorf(codes.FailedPrecondition, "GOOGLE_GEMINI_API_KEY not configured") + } + + aiService := newAIServiceFunc(apiKey) + serviceResponseInterface, err := aiService.GetAIResponse(req.GetPrompt()) + + if err != nil { + log.Printf("Gemini AIService error: %v", err) + return nil, status.Errorf(codes.Internal, "Gemini AIService failed: %v", err) + } + if serviceResponseInterface == nil { + log.Printf("Gemini AIService returned nil interface") + return nil, status.Errorf(codes.Internal, "Gemini AIService returned nil interface") + } + + genaiResponse, ok := serviceResponseInterface.(*genai.GenerateContentResponse) + if !ok { + log.Printf("Gemini AIService response is not *genai.GenerateContentResponse: %T", serviceResponseInterface) + return nil, status.Errorf(codes.Internal, "Gemini AIService response format error") + } + + pbResp := &pb_gemini.GeminiResponse{} + + for _, candidate := range genaiResponse.Candidates { + pbCandidate := &pb_gemini.GeminiResponse_Candidate{ + Index: int32(candidate.Index), + } + if candidate.FinishReason > 0 { + pbCandidate.FinishReason = candidate.FinishReason.String() + } + + if candidate.Content != nil { + pbContent := &pb_gemini.GeminiResponse_Content{Role: candidate.Content.Role} + for _, part := range candidate.Content.Parts { + if textPart, ok := part.(genai.Text); ok { + pbContent.Parts = append(pbContent.Parts, &pb_gemini.GeminiResponse_ContentPart{Text: string(textPart)}) + } else { + log.Printf("Unhandled part type in candidate content: %T", part) + } + } + pbCandidate.Content = pbContent + } + + for _, safetyRating := range candidate.SafetyRatings { + pbSafetyRating := &pb_gemini.GeminiResponse_SafetyRating{ + Category: safetyRating.Category.String(), + Probability: safetyRating.Probability.String(), + } + pbCandidate.SafetyRatings = append(pbCandidate.SafetyRatings, pbSafetyRating) + } + pbResp.Candidates = append(pbResp.Candidates, pbCandidate) + } + + if genaiResponse.PromptFeedback != nil { + pbPromptFeedback := &pb_gemini.GeminiResponse_PromptFeedback{} + for _, safetyRating := range genaiResponse.PromptFeedback.SafetyRatings { + pbSafetyRating := &pb_gemini.GeminiResponse_SafetyRating{ + Category: safetyRating.Category.String(), + Probability: safetyRating.Probability.String(), + } + pbPromptFeedback.SafetyRatings = append(pbPromptFeedback.SafetyRatings, pbSafetyRating) + } + pbResp.PromptFeedback = pbPromptFeedback + } + + return pbResp, nil +} diff --git a/api-service/grpc/gemini_server_test.go b/api-service/grpc/gemini_server_test.go new file mode 100644 index 0000000..624db9b --- /dev/null +++ b/api-service/grpc/gemini_server_test.go @@ -0,0 +1,165 @@ +package grpc + +import ( + "context" + "errors" + "os" + "reflect" + "testing" + + "api-service/config" // Required for GetEnv, though direct use is in server code + "api-service/services/gemini" // For actual service, used by patchable func + pb_gemini "api-service/grpc/pb/gemini" + + "github.com/google/generative-ai-go/genai" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// --- Mock Definition for Gemini --- +type MockAIService struct { + GetAIResponseFunc func(prompt string) (interface{}, error) +} + +func (m *MockAIService) GetAIResponse(prompt string) (interface{}, error) { + if m.GetAIResponseFunc != nil { + return m.GetAIResponseFunc(prompt) + } + return nil, errors.New("GetAIResponseFunc not implemented in mock") +} + + +// --- Test GenerateContent --- +func TestGeminiServerImpl_GenerateContent(t *testing.T) { + server := &GeminiServerImpl{} // Uses the Impl from gemini_server.go + ctx := context.Background() + + // Original newAIServiceFunc from gemini_server.go + originalFunc := newAIServiceFunc + defer func() { newAIServiceFunc = originalFunc }() + + mockService := &MockAIService{} + // Patch the constructor function in gemini_server.go + // The apiKey passed to the func will be from config.GetEnv in the actual server code + newAIServiceFunc = func(apiKey string) IAIService { return mockService } + + // Store original API key and defer restoration + originalAPIKey := os.Getenv("GOOGLE_GEMINI_API_KEY") + defer func() { + if err := os.Setenv("GOOGLE_GEMINI_API_KEY", originalAPIKey); err != nil { + t.Logf("Warning: could not restore GOOGLE_GEMINI_API_KEY: %v", err) + } + }() + + + tests := []struct { + name string + req *pb_gemini.GeminiRequest + apiKeyEnv string // Value to set for GOOGLE_GEMINI_API_KEY for this test + mockSetup func() + expectedResp *pb_gemini.GeminiResponse + expectedCode codes.Code + }{ + { + name: "Success", + req: &pb_gemini.GeminiRequest{Prompt: "Hello Gemini"}, + apiKeyEnv: "test_api_key", + mockSetup: func() { + mockService.GetAIResponseFunc = func(prompt string) (interface{}, error) { + return &genai.GenerateContentResponse{ + Candidates: []*genai.Candidate{ + { + Index: 0, + FinishReason: genai.FinishReasonStop, + Content: &genai.Content{Role: "model", Parts: []genai.Part{genai.Text("Hello there!")}}, + SafetyRatings: []*genai.SafetyRating{{Category: genai.HarmCategoryHarassment, Probability: genai.HarmProbabilityNegligible}}, + }, + }, + PromptFeedback: &genai.PromptFeedback{ + SafetyRatings: []*genai.SafetyRating{{Category: genai.HarmCategorySexuallyExplicit, Probability: genai.HarmProbabilityLow}}, + }, + }, nil + } + }, + expectedResp: &pb_gemini.GeminiResponse{ + Candidates: []*pb_gemini.GeminiResponse_Candidate{ + { + Index: 0, + FinishReason: genai.FinishReasonStop.String(), + Content: &pb_gemini.GeminiResponse_Content{Role: "model", Parts: []*pb_gemini.GeminiResponse_ContentPart{{Text: "Hello there!"}}}, + SafetyRatings: []*pb_gemini.GeminiResponse_SafetyRating{{Category: genai.HarmCategoryHarassment.String(), Probability: genai.HarmProbabilityNegligible.String()}}, + }, + }, + PromptFeedback: &pb_gemini.GeminiResponse_PromptFeedback{ + SafetyRatings: []*pb_gemini.GeminiResponse_SafetyRating{{Category: genai.HarmCategorySexuallyExplicit.String(), Probability: genai.HarmProbabilityLow.String()}}, + }, + }, + expectedCode: codes.OK, + }, + { + name: "Service Error", + req: &pb_gemini.GeminiRequest{Prompt: "prompt_error"}, + apiKeyEnv: "test_api_key", + mockSetup: func() { + mockService.GetAIResponseFunc = func(prompt string) (interface{}, error) { + return nil, errors.New("gemini service internal error") + } + }, + expectedResp: nil, + expectedCode: codes.Internal, + }, + { + name: "API Key Missing", + req: &pb_gemini.GeminiRequest{Prompt: "prompt_no_key"}, + apiKeyEnv: "", // API key is empty for this test + mockSetup: func() { + // No mock setup needed as it should fail before calling the service due to empty API key + }, + expectedResp: nil, + expectedCode: codes.FailedPrecondition, + }, + { + name: "Invalid Response Type from Service", + req: &pb_gemini.GeminiRequest{Prompt: "prompt_bad_type"}, + apiKeyEnv: "test_api_key", + mockSetup: func() { + mockService.GetAIResponseFunc = func(prompt string) (interface{}, error) { + return "not a *genai.GenerateContentResponse", nil // Return incorrect type + } + }, + expectedResp: nil, + expectedCode: codes.Internal, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := os.Setenv("GOOGLE_GEMINI_API_KEY", tt.apiKeyEnv); err != nil { + t.Fatalf("Failed to set GOOGLE_GEMINI_API_KEY for test: %v", err) + } + // Ensure config re-reads env var if it caches (not an issue with current config.GetEnv) + // config.LoadEnv() // If config had a Load function that caches. + + tt.mockSetup() // Setup the mock function for this specific test case + + resp, err := server.GenerateContent(ctx, tt.req) + + if tt.expectedCode != codes.OK { + if err == nil { + t.Fatalf("Expected error code %v, got nil", tt.expectedCode) + } + st, ok := status.FromError(err) + if !ok || st.Code() != tt.expectedCode { + t.Fatalf("Expected gRPC status code %v, got %v (err: %v)", tt.expectedCode, st.Code(), err) + } + } else { + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if !reflect.DeepEqual(resp, tt.expectedResp) { + t.Errorf("Response mismatch:\nGot: %+v\nWant:%+v", resp, tt.expectedResp) + } + } + }) + } +} diff --git a/api-service/grpc/maps_server.go b/api-service/grpc/maps_server.go new file mode 100644 index 0000000..eb3ae26 --- /dev/null +++ b/api-service/grpc/maps_server.go @@ -0,0 +1,401 @@ +package grpc + +import ( + "context" + "log" + + "api-service/models" + "api-service/services/maps" + pb_maps "api-service/grpc/pb/maps" // Alias for the new maps protobuf package + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// --- Service Interfaces for Maps --- +type IGeocodeService interface { + Geocode(address string) (map[string]interface{}, error) +} + +type IPlacesService interface { + FindPlaceByID(placeID string) (*models.PlaceDetailResponse, error) + SearchPlaces(query, location string) (*models.PlacesResponse, error) +} + +type IDirectionsService interface { + GetDirections(origin, destination string) (interface{}, error) +} + +type IDistanceMatrixService interface { + GetDistanceMatrix(origins, destinations string) (*maps.DistanceMatrixResponse, error) +} + +// --- Patchable Service Constructors for Maps --- +var ( + newGeocodeServiceFunc func() IGeocodeService = func() IGeocodeService { return maps.NewGeocodeService() } + newPlacesServiceFunc func() IPlacesService = func() IPlacesService { return maps.NewPlacesService() } + newDirectionsServiceFunc func() IDirectionsService = func() IDirectionsService { return maps.NewDirectionsService() } + newDistanceMatrixServiceFunc func() IDistanceMatrixService = func() IDistanceMatrixService { return maps.NewDistanceMatrixService() } +) + +// MapsServerImpl implements pb_maps.MapsServer +type MapsServerImpl struct { + pb_maps.UnimplementedMapsServer +} + +// --- MapsService Implementation --- + +func (s *MapsServerImpl) Geocode(ctx context.Context, req *pb_maps.GeocodeRequest) (*pb_maps.GeocodeResponse, error) { + log.Printf("Received gRPC Geocode request for address: %s", req.GetAddress()) + + geoService := newGeocodeServiceFunc() // Use patchable constructor + serviceResponse, err := geoService.Geocode(req.GetAddress()) + + if err != nil { + log.Printf("Geocode service error: %v", err) + return nil, status.Errorf(codes.Internal, "Geocoding failed: %v", err) + } + + var pbResults []*pb_maps.GeocodeResponse_Result + var responseStatus string + if val, ok := serviceResponse["status"].(string); ok { + responseStatus = val + } else { + log.Printf("Geocode service response missing or invalid 'status' field: %v", serviceResponse) + return nil, status.Errorf(codes.Internal, "Geocoding response format error: missing status") + } + + if responseStatus != "OK" && responseStatus != "ZERO_RESULTS" { + log.Printf("Geocode service returned non-OK status: %s", responseStatus) + } + + if resultsData, ok := serviceResponse["results"].([]interface{}); ok { + for _, item := range resultsData { + if resultMap, ok := item.(map[string]interface{}); ok { + pbRes := &pb_maps.GeocodeResponse_Result{} + if formattedAddr, ok := resultMap["formatted_address"].(string); ok { + pbRes.FormattedAddress = formattedAddr + } + if geometry, ok := resultMap["geometry"].(map[string]interface{}); ok { + if location, ok := geometry["location"].(map[string]interface{}); ok { + lat, latOk := location["lat"].(float64) + lng, lngOk := location["lng"].(float64) + if latOk && lngOk { + pbRes.Location = &pb_maps.GeocodeResponse_Location{Lat: lat, Lng: lng} + } + } + } + pbResults = append(pbResults, pbRes) + } + } + } else if responseStatus == "OK" { + log.Printf("Geocode service response 'OK' but 'results' field is missing or invalid: %v", serviceResponse) + return nil, status.Errorf(codes.Internal, "Geocoding response format error: results field issue") + } + + return &pb_maps.GeocodeResponse{ + Results: pbResults, + Status: responseStatus, + }, nil +} + +func (s *MapsServerImpl) SearchPlaces(ctx context.Context, req *pb_maps.SearchPlacesRequest) (*pb_maps.SearchPlacesResponse, error) { + log.Printf("Received gRPC SearchPlaces request: query='%s', location='%s'", req.GetQuery(), req.GetLocation()) + + placesService := newPlacesServiceFunc() + serviceResponse, err := placesService.SearchPlaces(req.GetQuery(), req.GetLocation()) + + if err != nil { + log.Printf("SearchPlaces service error: %v", err) + return nil, status.Errorf(codes.Internal, "SearchPlaces failed: %v", err) + } + if serviceResponse == nil { + log.Printf("SearchPlaces service returned nil response") + return nil, status.Errorf(codes.Internal, "SearchPlaces service returned nil response") + } + + var pbPlaces []*pb_maps.Place + for _, placeResultItem := range serviceResponse.Results { + pbPlace := &pb_maps.Place{ + PlaceId: placeResultItem.PlaceID, + Name: placeResultItem.Name, + Vicinity: placeResultItem.Address, + Rating: placeResultItem.Rating, + UserRatingsTotal: int32(placeResultItem.UserRatingsTotal), + Types: placeResultItem.Types, + PhotoUrls: placeResultItem.PhotoURLs, + } + // placeResultItem.Geometry.Location is a struct as per places_model.go for PlacesResponse.Results[].Geometry.Location + if placeResultItem.Geometry.Location.Lat != 0 || placeResultItem.Geometry.Location.Lng != 0 { + pbPlace.GeometryLocation = &pb_maps.Place_Location{ + Lat: placeResultItem.Geometry.Location.Lat, + Lng: placeResultItem.Geometry.Location.Lng, + } + } + // placeResultItem.OpeningHours is a struct. Direct assignment for OpenNow is fine. + // If placeResultItem.OpeningHours is a zero struct, OpenNow will be its default (false). + pbPlace.OpeningHours = &pb_maps.Place_OpeningHours{ + OpenNow: placeResultItem.OpeningHours.OpenNow, + } + var pbPhotos []*pb_maps.Place_Photo + for _, photo := range placeResultItem.Photos { + pbPhotos = append(pbPhotos, &pb_maps.Place_Photo{ + PhotoReference: photo.PhotoReference, + Height: int32(photo.Height), + Width: int32(photo.Width), + }) + } + pbPlace.Photos = pbPhotos + pbPlaces = append(pbPlaces, pbPlace) + } + + return &pb_maps.SearchPlacesResponse{ + Results: pbPlaces, + Status: serviceResponse.Status, + }, nil +} + +func (s *MapsServerImpl) GetPlaceDetails(ctx context.Context, req *pb_maps.PlaceDetailsRequest) (*pb_maps.PlaceDetailsResponse, error) { + log.Printf("Received gRPC GetPlaceDetails request for place_id: %s", req.GetPlaceId()) + + placesService := newPlacesServiceFunc() + serviceResponse, err := placesService.FindPlaceByID(req.GetPlaceId()) + + if err != nil { + log.Printf("FindPlaceByID service error: %v", err) + return nil, status.Errorf(codes.Internal, "FindPlaceByID failed: %v", err) + } + if serviceResponse == nil { + log.Printf("FindPlaceByID service returned nil response") + return nil, status.Errorf(codes.Internal, "FindPlaceByID service returned nil response") + } + + // serviceResponse.Result is a struct (PlaceDetailResult). + // Check PlaceID for emptiness if status is OK. + if serviceResponse.Status != "OK" || (serviceResponse.Status == "OK" && serviceResponse.Result.PlaceID == "") { + log.Printf("FindPlaceByID service returned status: %s or (Status=OK and PlaceID is empty)", serviceResponse.Status) + return &pb_maps.PlaceDetailsResponse{ + Status: serviceResponse.Status, + Result: nil, // Treat as no result if PlaceID is empty or status not OK + }, nil + } + + result := serviceResponse.Result // result is of type models.PlaceDetailResult (a struct) + pbPlace := &pb_maps.Place{ + PlaceId: result.PlaceID, + Name: result.Name, + Rating: result.Rating, + UserRatingsTotal: int32(result.UserRatingsTotal), + Types: result.Types, + PhotoUrls: result.PhotoURLs, + } + if result.Vicinity != "" { + pbPlace.Vicinity = result.Vicinity + } else { + pbPlace.Vicinity = result.FormattedAddress + } + // result.Geometry.Location is a struct as per places_model.go for PlaceDetailResult.Geometry.Location + if result.Geometry.Location.Lat != 0 || result.Geometry.Location.Lng != 0 { + pbPlace.GeometryLocation = &pb_maps.Place_Location{ + Lat: result.Geometry.Location.Lat, + Lng: result.Geometry.Location.Lng, + } + } + // result.OpeningHours is a pointer (*models.PlaceOpeningHours), so nil check is correct. + if result.OpeningHours != nil { + pbPlace.OpeningHours = &pb_maps.Place_OpeningHours{ + OpenNow: result.OpeningHours.OpenNow, + } + } + var pbPhotos []*pb_maps.Place_Photo + for _, photo := range result.Photos { + pbPhotos = append(pbPhotos, &pb_maps.Place_Photo{ + PhotoReference: photo.PhotoReference, + Height: int32(photo.Height), + Width: int32(photo.Width), + }) + } + pbPlace.Photos = pbPhotos + + return &pb_maps.PlaceDetailsResponse{ + Result: pbPlace, + Status: serviceResponse.Status, + }, nil +} + +func (s *MapsServerImpl) GetDirections(ctx context.Context, req *pb_maps.DirectionsRequest) (*pb_maps.DirectionsResponse, error) { + log.Printf("Received gRPC GetDirections request: origin='%s', destination='%s'", req.GetOrigin(), req.GetDestination()) + + dirService := newDirectionsServiceFunc() + serviceResponseInterface, err := dirService.GetDirections(req.GetOrigin(), req.GetDestination()) + + if err != nil { + log.Printf("DirectionsService error: %v", err) + return nil, status.Errorf(codes.Internal, "DirectionsService failed: %v", err) + } + if serviceResponseInterface == nil { + log.Printf("DirectionsService returned nil interface") + return nil, status.Errorf(codes.Internal, "DirectionsService returned nil interface") + } + + serviceResponse, ok := serviceResponseInterface.(map[string]interface{}) + if !ok { + log.Printf("DirectionsService response is not map[string]interface{}: %T", serviceResponseInterface) + return nil, status.Errorf(codes.Internal, "DirectionsService response format error") + } + + var responseStatus string + if val, ok := serviceResponse["status"].(string); ok { + responseStatus = val + } else { + log.Printf("DirectionsService response missing or invalid 'status' field: %v", serviceResponse) + return nil, status.Errorf(codes.Internal, "DirectionsService response format error: missing status") + } + + if responseStatus != "OK" { + log.Printf("DirectionsService returned non-OK status: %s", responseStatus) + return &pb_maps.DirectionsResponse{Status: responseStatus}, nil + } + + var pbRoutes []*pb_maps.DirectionsResponse_Route + if routesData, ok := serviceResponse["routes"].([]interface{}); ok { + for _, routeItem := range routesData { + routeMap, rok := routeItem.(map[string]interface{}) + if !rok { continue } + pbRoute := &pb_maps.DirectionsResponse_Route{} + if summary, ok := routeMap["summary"].(string); ok { pbRoute.Summary = summary } + if opm, ok := routeMap["overview_polyline"].(map[string]interface{}); ok { + if pts, ok := opm["points"].(string); ok { pbRoute.OverviewPolyline = &pb_maps.DirectionsResponse_Polyline{Points: pts} } + } + + var pbLegs []*pb_maps.DirectionsResponse_Leg + if legsData, ok := routeMap["legs"].([]interface{}); ok { + for _, legItem := range legsData { + legMap, lok := legItem.(map[string]interface{}) + if !lok { continue } + pbLeg := &pb_maps.DirectionsResponse_Leg{} + if sa, ok := legMap["start_address"].(string); ok { pbLeg.StartAddress = sa } + if ea, ok := legMap["end_address"].(string); ok { pbLeg.EndAddress = ea } + if distMap, ok := legMap["distance"].(map[string]interface{}); ok { + pbDist := &pb_maps.DirectionsResponse_Distance{} + if txt, ok := distMap["text"].(string); ok { pbDist.Text = txt } + if val, ok := distMap["value"].(float64); ok { pbDist.Value = int32(val) } + pbLeg.Distance = pbDist + } + if durMap, ok := legMap["duration"].(map[string]interface{}); ok { + pbDur := &pb_maps.DirectionsResponse_Duration{} + if txt, ok := durMap["text"].(string); ok { pbDur.Text = txt } + if val, ok := durMap["value"].(float64); ok { pbDur.Value = int32(val) } + pbLeg.Duration = pbDur + } + + var pbSteps []*pb_maps.DirectionsResponse_Step + if stepsData, ok := legMap["steps"].([]interface{}); ok { + for _, stepItem := range stepsData { + stepMap, sok := stepItem.(map[string]interface{}) + if !sok { continue } + pbStep := &pb_maps.DirectionsResponse_Step{} + if hi, ok := stepMap["html_instructions"].(string); ok { pbStep.HtmlInstructions = hi } + if stepDistMap, ok := stepMap["distance"].(map[string]interface{}); ok { + pbStepDist := &pb_maps.DirectionsResponse_Distance{} + if txt, ok := stepDistMap["text"].(string); ok { pbStepDist.Text = txt } + if val, ok := stepDistMap["value"].(float64); ok { pbStepDist.Value = int32(val) } + pbStep.Distance = pbStepDist + } + if stepDurMap, ok := stepMap["duration"].(map[string]interface{}); ok { + pbStepDur := &pb_maps.DirectionsResponse_Duration{} + if txt, ok := stepDurMap["text"].(string); ok { pbStepDur.Text = txt } + if val, ok := stepDurMap["value"].(float64); ok { pbStepDur.Value = int32(val) } + pbStep.Duration = pbStepDur + } + if polyMap, ok := stepMap["polyline"].(map[string]interface{}); ok { + if pts, ok := polyMap["points"].(string); ok { pbStep.Polyline = &pb_maps.DirectionsResponse_Polyline{Points: pts} } + } + pbSteps = append(pbSteps, pbStep) + } + } + pbLeg.Steps = pbSteps + pbLegs = append(pbLegs, pbLeg) + } + } + pbRoute.Legs = pbLegs + pbRoutes = append(pbRoutes, pbRoute) + } + } + + var pbWaypoints []*pb_maps.DirectionsResponse_GeocodedWaypoint + if waypointData, ok := serviceResponse["geocoded_waypoints"].([]interface{}); ok { + for _, waypointItem := range waypointData { + waypointMap, wok := waypointItem.(map[string]interface{}) + if !wok { continue } + pbWaypoint := &pb_maps.DirectionsResponse_GeocodedWaypoint{} + if gs, ok := waypointMap["geocoder_status"].(string); ok { pbWaypoint.GeocoderStatus = gs } + if pid, ok := waypointMap["place_id"].(string); ok { pbWaypoint.PlaceId = pid } + if typesInterface, ok := waypointMap["types"].([]interface{}); ok { + var typesStr []string + for _, typeItem := range typesInterface { + if typeStr, ok := typeItem.(string); ok { typesStr = append(typesStr, typeStr) } + } + pbWaypoint.Types = typesStr + } + pbWaypoints = append(pbWaypoints, pbWaypoint) + } + } + + return &pb_maps.DirectionsResponse{ + Status: responseStatus, + Routes: pbRoutes, + GeocodedWaypoints: pbWaypoints, + }, nil +} + +func (s *MapsServerImpl) GetDistanceMatrix(ctx context.Context, req *pb_maps.DistanceMatrixRequest) (*pb_maps.DistanceMatrixResponse, error) { + log.Printf("Received gRPC GetDistanceMatrix request: origins='%s', destinations='%s'", req.GetOrigins(), req.GetDestinations()) + + distMatrixService := newDistanceMatrixServiceFunc() + serviceResponse, err := distMatrixService.GetDistanceMatrix(req.GetOrigins(), req.GetDestinations()) + + if err != nil { + log.Printf("DistanceMatrixService error: %v", err) + return nil, status.Errorf(codes.Internal, "DistanceMatrixService failed: %v", err) + } + if serviceResponse == nil { + log.Printf("DistanceMatrixService returned nil response") + return nil, status.Errorf(codes.Internal, "DistanceMatrixService returned nil response") + } + + // serviceResponse from maps.DistanceMatrixService only contains Rows. + // OriginAddresses, DestinationAddresses, and overall Status are part of the proto but not this service model. + pbResp := &pb_maps.DistanceMatrixResponse{} + + var pbRows []*pb_maps.DistanceMatrixResponse_Row + for _, serviceRow := range serviceResponse.Rows { + pbRow := &pb_maps.DistanceMatrixResponse_Row{} + var pbElements []*pb_maps.DistanceMatrixResponse_Element + for _, serviceElement := range serviceRow.Elements { + pbElement := &pb_maps.DistanceMatrixResponse_Element{Status: serviceElement.Status} + // serviceElement.Duration is a struct, check its fields for meaningful data + if serviceElement.Duration.Text != "" || serviceElement.Duration.Value != 0 { + pbElement.Duration = &pb_maps.DistanceMatrixResponse_Element_Duration{ + Text: serviceElement.Duration.Text, + Value: int32(serviceElement.Duration.Value), + } + } + // serviceElement.Distance is a struct, check its fields for meaningful data + if serviceElement.Distance.Text != "" || serviceElement.Distance.Value != 0 { + pbElement.Distance = &pb_maps.DistanceMatrixResponse_Element_Distance{ + Text: serviceElement.Distance.Text, + Value: int32(serviceElement.Distance.Value), + } + } + pbElements = append(pbElements, pbElement) + } + pbRow.Elements = pbElements + pbRows = append(pbRows, pbRow) + } + pbResp.Rows = pbRows + + // serviceResponse.Status does not exist on maps.DistanceMatrixResponse from the service. + // The status for each element is handled within the element itself. + return pbResp, nil +} diff --git a/api-service/grpc/maps_server_test.go b/api-service/grpc/maps_server_test.go new file mode 100644 index 0000000..c5a7b1b --- /dev/null +++ b/api-service/grpc/maps_server_test.go @@ -0,0 +1,194 @@ +package grpc + +import ( + "context" + "errors" + "reflect" + "testing" + + "api-service/models" + "api-service/services/maps" // For maps.DistanceMatrixResponse etc. + pb_maps "api-service/grpc/pb/maps" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// --- Mock Definitions for Maps --- + +// MockGeocodeService for IGeocodeService +type MockGeocodeService struct { + GeocodeFunc func(address string) (map[string]interface{}, error) +} + +func (m *MockGeocodeService) Geocode(address string) (map[string]interface{}, error) { + if m.GeocodeFunc != nil { + return m.GeocodeFunc(address) + } + return nil, errors.New("GeocodeFunc not implemented in mock") +} + +// MockPlacesService for IPlacesService +type MockPlacesService struct { + FindPlaceByIDFunc func(placeID string) (*models.PlaceDetailResponse, error) + SearchPlacesFunc func(query, location string) (*models.PlacesResponse, error) +} + +func (m *MockPlacesService) FindPlaceByID(placeID string) (*models.PlaceDetailResponse, error) { + if m.FindPlaceByIDFunc != nil { + return m.FindPlaceByIDFunc(placeID) + } + return nil, errors.New("FindPlaceByIDFunc not implemented in mock") +} + +func (m *MockPlacesService) SearchPlaces(query, location string) (*models.PlacesResponse, error) { + if m.SearchPlacesFunc != nil { + return m.SearchPlacesFunc(query, location) + } + return nil, errors.New("SearchPlacesFunc not implemented in mock") +} + +// MockDirectionsService for IDirectionsService +type MockDirectionsService struct { + GetDirectionsFunc func(origin, destination string) (interface{}, error) +} + +func (m *MockDirectionsService) GetDirections(origin, destination string) (interface{}, error) { + if m.GetDirectionsFunc != nil { + return m.GetDirectionsFunc(origin, destination) + } + return nil, errors.New("GetDirectionsFunc not implemented in mock") +} + +// MockDistanceMatrixService for IDistanceMatrixService +type MockDistanceMatrixService struct { + GetDistanceMatrixFunc func(origins, destinations string) (*maps.DistanceMatrixResponse, error) +} + +func (m *MockDistanceMatrixService) GetDistanceMatrix(origins, destinations string) (*maps.DistanceMatrixResponse, error) { + if m.GetDistanceMatrixFunc != nil { + return m.GetDistanceMatrixFunc(origins, destinations) + } + return nil, errors.New("GetDistanceMatrixFunc not implemented in mock") +} + + +// --- Test GetPlaceDetails --- +func TestMapsServerImpl_GetPlaceDetails(t *testing.T) { + server := &MapsServerImpl{} // Uses the Impl from maps_server.go + ctx := context.Background() + + // Original newPlacesServiceFunc from maps_server.go + originalFunc := newPlacesServiceFunc + defer func() { newPlacesServiceFunc = originalFunc }() + + mockService := &MockPlacesService{} + // Patch the constructor function in maps_server.go + newPlacesServiceFunc = func() IPlacesService { return mockService } + + tests := []struct { + name string + req *pb_maps.PlaceDetailsRequest + mockSetup func() + expectedResp *pb_maps.PlaceDetailsResponse + expectedCode codes.Code + }{ + { + name: "Success", + req: &pb_maps.PlaceDetailsRequest{PlaceId: "test_place_id"}, + mockSetup: func() { + mockService.FindPlaceByIDFunc = func(placeID string) (*models.PlaceDetailResponse, error) { + return &models.PlaceDetailResponse{ + Status: "OK", + Result: &models.PlaceResult{ + PlaceID: "test_place_id", + Name: "Test Place", + Vicinity: "Test Vicinity", + Rating: 4.5, + UserRatingsTotal: 100, + Types: []string{"cafe", "bakery"}, + Geometry: &models.Geometry{Location: &models.Location{Lat: 10.0, Lng: 20.0}}, + OpeningHours: &models.OpeningHours{OpenNow: true}, + Photos: []models.Photo{{PhotoReference: "ref1", Height: 100, Width: 200}}, + PhotoURLs: []string{"http://example.com/photo1.jpg"}, + }, + }, nil + } + }, + expectedResp: &pb_maps.PlaceDetailsResponse{ + Status: "OK", + Result: &pb_maps.Place{ + PlaceId: "test_place_id", + Name: "Test Place", + Vicinity: "Test Vicinity", + Rating: 4.5, + UserRatingsTotal: 100, + Types: []string{"cafe", "bakery"}, + GeometryLocation: &pb_maps.Place_Location{Lat: 10.0, Lng: 20.0}, + OpeningHours: &pb_maps.Place_OpeningHours{OpenNow: true}, + Photos: []*pb_maps.Place_Photo{{PhotoReference: "ref1", Height: 100, Width: 200}}, + PhotoUrls: []string{"http://example.com/photo1.jpg"}, + }, + }, + expectedCode: codes.OK, + }, + { + name: "Service Error", + req: &pb_maps.PlaceDetailsRequest{PlaceId: "error_id"}, + mockSetup: func() { + mockService.FindPlaceByIDFunc = func(placeID string) (*models.PlaceDetailResponse, error) { + return nil, errors.New("internal service error") + } + }, + expectedResp: nil, + expectedCode: codes.Internal, + }, + { + name: "Place Not Found (NOT_FOUND status)", + req: &pb_maps.PlaceDetailsRequest{PlaceId: "not_found_id"}, + mockSetup: func() { + mockService.FindPlaceByIDFunc = func(placeID string) (*models.PlaceDetailResponse, error) { + return &models.PlaceDetailResponse{Status: "NOT_FOUND", Result: nil}, nil + } + }, + expectedResp: &pb_maps.PlaceDetailsResponse{Status: "NOT_FOUND", Result: nil}, + expectedCode: codes.OK, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.mockSetup() + resp, err := server.GetPlaceDetails(ctx, tt.req) + + if tt.expectedCode != codes.OK { + if err == nil { + t.Fatalf("Expected error code %v, got nil", tt.expectedCode) + } + st, ok := status.FromError(err) + if !ok || st.Code() != tt.expectedCode { + t.Fatalf("Expected gRPC status code %v, got %v (err: %v)", tt.expectedCode, st.Code(), err) + } + } else { + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if !reflect.DeepEqual(resp, tt.expectedResp) { + t.Errorf("Response mismatch:\nGot: %+v\nWant:%+v", resp, tt.expectedResp) + } + } + }) + } +} + +// TODO: Add tests for Geocode, SearchPlaces, GetDirections, GetDistanceMatrix +// using a similar pattern of mocking their respective newXServiceFunc variables +// and testing success/error cases. +// For example, for Geocode: +// originalGeocodeFunc := newGeocodeServiceFunc +// defer func() { newGeocodeServiceFunc = originalGeocodeFunc }() +// mockGeoSvc := &MockGeocodeService{} +// newGeocodeServiceFunc = func() IGeocodeService { return mockGeoSvc } +// ... then setup mockGeoSvc.GeocodeFunc ... +// server.Geocode(...) +// ... assertions ... diff --git a/api-service/grpc/pb/common/common.pb.go b/api-service/grpc/pb/common/common.pb.go new file mode 100644 index 0000000..33dfa27 --- /dev/null +++ b/api-service/grpc/pb/common/common.pb.go @@ -0,0 +1,175 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.21.12 +// source: common.proto + +package common + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type HelloRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HelloRequest) Reset() { + *x = HelloRequest{} + mi := &file_common_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloRequest) ProtoMessage() {} + +func (x *HelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_common_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 HelloRequest.ProtoReflect.Descriptor instead. +func (*HelloRequest) Descriptor() ([]byte, []int) { + return file_common_proto_rawDescGZIP(), []int{0} +} + +func (x *HelloRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type HelloReply struct { + state protoimpl.MessageState `protogen:"open.v1"` + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HelloReply) Reset() { + *x = HelloReply{} + mi := &file_common_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HelloReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloReply) ProtoMessage() {} + +func (x *HelloReply) ProtoReflect() protoreflect.Message { + mi := &file_common_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 HelloReply.ProtoReflect.Descriptor instead. +func (*HelloReply) Descriptor() ([]byte, []int) { + return file_common_proto_rawDescGZIP(), []int{1} +} + +func (x *HelloReply) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_common_proto protoreflect.FileDescriptor + +const file_common_proto_rawDesc = "" + + "\n" + + "\fcommon.proto\x12\fcommon_proto\"\"\n" + + "\fHelloRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"&\n" + + "\n" + + "HelloReply\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage2T\n" + + "\x0eExampleGreeter\x12B\n" + + "\bSayHello\x12\x1a.common_proto.HelloRequest\x1a\x18.common_proto.HelloReply\"\x00BK\n" + + "+com.example.planning.grpc.apiservice.commonP\x01Z\x1aapi-service/grpc/pb/commonb\x06proto3" + +var ( + file_common_proto_rawDescOnce sync.Once + file_common_proto_rawDescData []byte +) + +func file_common_proto_rawDescGZIP() []byte { + file_common_proto_rawDescOnce.Do(func() { + file_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_common_proto_rawDesc), len(file_common_proto_rawDesc))) + }) + return file_common_proto_rawDescData +} + +var file_common_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_common_proto_goTypes = []any{ + (*HelloRequest)(nil), // 0: common_proto.HelloRequest + (*HelloReply)(nil), // 1: common_proto.HelloReply +} +var file_common_proto_depIdxs = []int32{ + 0, // 0: common_proto.ExampleGreeter.SayHello:input_type -> common_proto.HelloRequest + 1, // 1: common_proto.ExampleGreeter.SayHello:output_type -> common_proto.HelloReply + 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_common_proto_init() } +func file_common_proto_init() { + if File_common_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_common_proto_rawDesc), len(file_common_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_common_proto_goTypes, + DependencyIndexes: file_common_proto_depIdxs, + MessageInfos: file_common_proto_msgTypes, + }.Build() + File_common_proto = out.File + file_common_proto_goTypes = nil + file_common_proto_depIdxs = nil +} diff --git a/api-service/grpc/pb/common/common_grpc.pb.go b/api-service/grpc/pb/common/common_grpc.pb.go new file mode 100644 index 0000000..4795f2b --- /dev/null +++ b/api-service/grpc/pb/common/common_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 v3.21.12 +// source: common.proto + +package common + +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 ( + ExampleGreeter_SayHello_FullMethodName = "/common_proto.ExampleGreeter/SayHello" +) + +// ExampleGreeterClient is the client API for ExampleGreeter 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 ExampleGreeterClient interface { + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type exampleGreeterClient struct { + cc grpc.ClientConnInterface +} + +func NewExampleGreeterClient(cc grpc.ClientConnInterface) ExampleGreeterClient { + return &exampleGreeterClient{cc} +} + +func (c *exampleGreeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(HelloReply) + err := c.cc.Invoke(ctx, ExampleGreeter_SayHello_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ExampleGreeterServer is the server API for ExampleGreeter service. +// All implementations must embed UnimplementedExampleGreeterServer +// for forward compatibility. +type ExampleGreeterServer interface { + SayHello(context.Context, *HelloRequest) (*HelloReply, error) + mustEmbedUnimplementedExampleGreeterServer() +} + +// UnimplementedExampleGreeterServer 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 UnimplementedExampleGreeterServer struct{} + +func (UnimplementedExampleGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") +} +func (UnimplementedExampleGreeterServer) mustEmbedUnimplementedExampleGreeterServer() {} +func (UnimplementedExampleGreeterServer) testEmbeddedByValue() {} + +// UnsafeExampleGreeterServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ExampleGreeterServer will +// result in compilation errors. +type UnsafeExampleGreeterServer interface { + mustEmbedUnimplementedExampleGreeterServer() +} + +func RegisterExampleGreeterServer(s grpc.ServiceRegistrar, srv ExampleGreeterServer) { + // If the following call pancis, it indicates UnimplementedExampleGreeterServer 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(&ExampleGreeter_ServiceDesc, srv) +} + +func _ExampleGreeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ExampleGreeterServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ExampleGreeter_SayHello_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ExampleGreeterServer).SayHello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ExampleGreeter_ServiceDesc is the grpc.ServiceDesc for ExampleGreeter service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ExampleGreeter_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "common_proto.ExampleGreeter", + HandlerType: (*ExampleGreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _ExampleGreeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "common.proto", +} diff --git a/api-service/grpc/pb/gemini/gemini.pb.go b/api-service/grpc/pb/gemini/gemini.pb.go new file mode 100644 index 0000000..41d2858 --- /dev/null +++ b/api-service/grpc/pb/gemini/gemini.pb.go @@ -0,0 +1,471 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.21.12 +// source: gemini.proto + +package gemini + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GeminiRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Prompt string `protobuf:"bytes,1,opt,name=prompt,proto3" json:"prompt,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeminiRequest) Reset() { + *x = GeminiRequest{} + mi := &file_gemini_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeminiRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiRequest) ProtoMessage() {} + +func (x *GeminiRequest) ProtoReflect() protoreflect.Message { + mi := &file_gemini_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 GeminiRequest.ProtoReflect.Descriptor instead. +func (*GeminiRequest) Descriptor() ([]byte, []int) { + return file_gemini_proto_rawDescGZIP(), []int{0} +} + +func (x *GeminiRequest) GetPrompt() string { + if x != nil { + return x.Prompt + } + return "" +} + +type GeminiResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Candidates []*GeminiResponse_Candidate `protobuf:"bytes,1,rep,name=candidates,proto3" json:"candidates,omitempty"` + PromptFeedback *GeminiResponse_PromptFeedback `protobuf:"bytes,2,opt,name=prompt_feedback,json=promptFeedback,proto3" json:"prompt_feedback,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeminiResponse) Reset() { + *x = GeminiResponse{} + mi := &file_gemini_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeminiResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse) ProtoMessage() {} + +func (x *GeminiResponse) ProtoReflect() protoreflect.Message { + mi := &file_gemini_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 GeminiResponse.ProtoReflect.Descriptor instead. +func (*GeminiResponse) Descriptor() ([]byte, []int) { + return file_gemini_proto_rawDescGZIP(), []int{1} +} + +func (x *GeminiResponse) GetCandidates() []*GeminiResponse_Candidate { + if x != nil { + return x.Candidates + } + return nil +} + +func (x *GeminiResponse) GetPromptFeedback() *GeminiResponse_PromptFeedback { + if x != nil { + return x.PromptFeedback + } + return nil +} + +type GeminiResponse_SafetyRating struct { + state protoimpl.MessageState `protogen:"open.v1"` + Category string `protobuf:"bytes,1,opt,name=category,proto3" json:"category,omitempty"` + Probability string `protobuf:"bytes,2,opt,name=probability,proto3" json:"probability,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeminiResponse_SafetyRating) Reset() { + *x = GeminiResponse_SafetyRating{} + mi := &file_gemini_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeminiResponse_SafetyRating) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_SafetyRating) ProtoMessage() {} + +func (x *GeminiResponse_SafetyRating) ProtoReflect() protoreflect.Message { + mi := &file_gemini_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 GeminiResponse_SafetyRating.ProtoReflect.Descriptor instead. +func (*GeminiResponse_SafetyRating) Descriptor() ([]byte, []int) { + return file_gemini_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *GeminiResponse_SafetyRating) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *GeminiResponse_SafetyRating) GetProbability() string { + if x != nil { + return x.Probability + } + return "" +} + +type GeminiResponse_ContentPart struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeminiResponse_ContentPart) Reset() { + *x = GeminiResponse_ContentPart{} + mi := &file_gemini_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeminiResponse_ContentPart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_ContentPart) ProtoMessage() {} + +func (x *GeminiResponse_ContentPart) ProtoReflect() protoreflect.Message { + mi := &file_gemini_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 GeminiResponse_ContentPart.ProtoReflect.Descriptor instead. +func (*GeminiResponse_ContentPart) Descriptor() ([]byte, []int) { + return file_gemini_proto_rawDescGZIP(), []int{1, 1} +} + +func (x *GeminiResponse_ContentPart) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +type GeminiResponse_Content struct { + state protoimpl.MessageState `protogen:"open.v1"` + Parts []*GeminiResponse_ContentPart `protobuf:"bytes,1,rep,name=parts,proto3" json:"parts,omitempty"` + Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeminiResponse_Content) Reset() { + *x = GeminiResponse_Content{} + mi := &file_gemini_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeminiResponse_Content) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_Content) ProtoMessage() {} + +func (x *GeminiResponse_Content) ProtoReflect() protoreflect.Message { + mi := &file_gemini_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 GeminiResponse_Content.ProtoReflect.Descriptor instead. +func (*GeminiResponse_Content) Descriptor() ([]byte, []int) { + return file_gemini_proto_rawDescGZIP(), []int{1, 2} +} + +func (x *GeminiResponse_Content) GetParts() []*GeminiResponse_ContentPart { + if x != nil { + return x.Parts + } + return nil +} + +func (x *GeminiResponse_Content) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +type GeminiResponse_Candidate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Content *GeminiResponse_Content `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + FinishReason string `protobuf:"bytes,2,opt,name=finish_reason,json=finishReason,proto3" json:"finish_reason,omitempty"` + Index int32 `protobuf:"varint,3,opt,name=index,proto3" json:"index,omitempty"` + SafetyRatings []*GeminiResponse_SafetyRating `protobuf:"bytes,4,rep,name=safety_ratings,json=safetyRatings,proto3" json:"safety_ratings,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeminiResponse_Candidate) Reset() { + *x = GeminiResponse_Candidate{} + mi := &file_gemini_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeminiResponse_Candidate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_Candidate) ProtoMessage() {} + +func (x *GeminiResponse_Candidate) ProtoReflect() protoreflect.Message { + mi := &file_gemini_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 GeminiResponse_Candidate.ProtoReflect.Descriptor instead. +func (*GeminiResponse_Candidate) Descriptor() ([]byte, []int) { + return file_gemini_proto_rawDescGZIP(), []int{1, 3} +} + +func (x *GeminiResponse_Candidate) GetContent() *GeminiResponse_Content { + if x != nil { + return x.Content + } + return nil +} + +func (x *GeminiResponse_Candidate) GetFinishReason() string { + if x != nil { + return x.FinishReason + } + return "" +} + +func (x *GeminiResponse_Candidate) GetIndex() int32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *GeminiResponse_Candidate) GetSafetyRatings() []*GeminiResponse_SafetyRating { + if x != nil { + return x.SafetyRatings + } + return nil +} + +type GeminiResponse_PromptFeedback struct { + state protoimpl.MessageState `protogen:"open.v1"` + SafetyRatings []*GeminiResponse_SafetyRating `protobuf:"bytes,2,rep,name=safety_ratings,json=safetyRatings,proto3" json:"safety_ratings,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeminiResponse_PromptFeedback) Reset() { + *x = GeminiResponse_PromptFeedback{} + mi := &file_gemini_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeminiResponse_PromptFeedback) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_PromptFeedback) ProtoMessage() {} + +func (x *GeminiResponse_PromptFeedback) ProtoReflect() protoreflect.Message { + mi := &file_gemini_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 GeminiResponse_PromptFeedback.ProtoReflect.Descriptor instead. +func (*GeminiResponse_PromptFeedback) Descriptor() ([]byte, []int) { + return file_gemini_proto_rawDescGZIP(), []int{1, 4} +} + +func (x *GeminiResponse_PromptFeedback) GetSafetyRatings() []*GeminiResponse_SafetyRating { + if x != nil { + return x.SafetyRatings + } + return nil +} + +var File_gemini_proto protoreflect.FileDescriptor + +const file_gemini_proto_rawDesc = "" + + "\n" + + "\fgemini.proto\x12\fgemini_proto\"'\n" + + "\rGeminiRequest\x12\x16\n" + + "\x06prompt\x18\x01 \x01(\tR\x06prompt\"\xbd\x05\n" + + "\x0eGeminiResponse\x12F\n" + + "\n" + + "candidates\x18\x01 \x03(\v2&.gemini_proto.GeminiResponse.CandidateR\n" + + "candidates\x12T\n" + + "\x0fprompt_feedback\x18\x02 \x01(\v2+.gemini_proto.GeminiResponse.PromptFeedbackR\x0epromptFeedback\x1aL\n" + + "\fSafetyRating\x12\x1a\n" + + "\bcategory\x18\x01 \x01(\tR\bcategory\x12 \n" + + "\vprobability\x18\x02 \x01(\tR\vprobability\x1a!\n" + + "\vContentPart\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\x1a]\n" + + "\aContent\x12>\n" + + "\x05parts\x18\x01 \x03(\v2(.gemini_proto.GeminiResponse.ContentPartR\x05parts\x12\x12\n" + + "\x04role\x18\x02 \x01(\tR\x04role\x1a\xd8\x01\n" + + "\tCandidate\x12>\n" + + "\acontent\x18\x01 \x01(\v2$.gemini_proto.GeminiResponse.ContentR\acontent\x12#\n" + + "\rfinish_reason\x18\x02 \x01(\tR\ffinishReason\x12\x14\n" + + "\x05index\x18\x03 \x01(\x05R\x05index\x12P\n" + + "\x0esafety_ratings\x18\x04 \x03(\v2).gemini_proto.GeminiResponse.SafetyRatingR\rsafetyRatings\x1ab\n" + + "\x0ePromptFeedback\x12P\n" + + "\x0esafety_ratings\x18\x02 \x03(\v2).gemini_proto.GeminiResponse.SafetyRatingR\rsafetyRatings2V\n" + + "\x06Gemini\x12L\n" + + "\x0fGenerateContent\x12\x1b.gemini_proto.GeminiRequest\x1a\x1c.gemini_proto.GeminiResponseBK\n" + + "+com.example.planning.grpc.apiservice.geminiP\x01Z\x1aapi-service/grpc/pb/geminib\x06proto3" + +var ( + file_gemini_proto_rawDescOnce sync.Once + file_gemini_proto_rawDescData []byte +) + +func file_gemini_proto_rawDescGZIP() []byte { + file_gemini_proto_rawDescOnce.Do(func() { + file_gemini_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gemini_proto_rawDesc), len(file_gemini_proto_rawDesc))) + }) + return file_gemini_proto_rawDescData +} + +var file_gemini_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_gemini_proto_goTypes = []any{ + (*GeminiRequest)(nil), // 0: gemini_proto.GeminiRequest + (*GeminiResponse)(nil), // 1: gemini_proto.GeminiResponse + (*GeminiResponse_SafetyRating)(nil), // 2: gemini_proto.GeminiResponse.SafetyRating + (*GeminiResponse_ContentPart)(nil), // 3: gemini_proto.GeminiResponse.ContentPart + (*GeminiResponse_Content)(nil), // 4: gemini_proto.GeminiResponse.Content + (*GeminiResponse_Candidate)(nil), // 5: gemini_proto.GeminiResponse.Candidate + (*GeminiResponse_PromptFeedback)(nil), // 6: gemini_proto.GeminiResponse.PromptFeedback +} +var file_gemini_proto_depIdxs = []int32{ + 5, // 0: gemini_proto.GeminiResponse.candidates:type_name -> gemini_proto.GeminiResponse.Candidate + 6, // 1: gemini_proto.GeminiResponse.prompt_feedback:type_name -> gemini_proto.GeminiResponse.PromptFeedback + 3, // 2: gemini_proto.GeminiResponse.Content.parts:type_name -> gemini_proto.GeminiResponse.ContentPart + 4, // 3: gemini_proto.GeminiResponse.Candidate.content:type_name -> gemini_proto.GeminiResponse.Content + 2, // 4: gemini_proto.GeminiResponse.Candidate.safety_ratings:type_name -> gemini_proto.GeminiResponse.SafetyRating + 2, // 5: gemini_proto.GeminiResponse.PromptFeedback.safety_ratings:type_name -> gemini_proto.GeminiResponse.SafetyRating + 0, // 6: gemini_proto.Gemini.GenerateContent:input_type -> gemini_proto.GeminiRequest + 1, // 7: gemini_proto.Gemini.GenerateContent:output_type -> gemini_proto.GeminiResponse + 7, // [7:8] is the sub-list for method output_type + 6, // [6:7] 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_gemini_proto_init() } +func file_gemini_proto_init() { + if File_gemini_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_gemini_proto_rawDesc), len(file_gemini_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_gemini_proto_goTypes, + DependencyIndexes: file_gemini_proto_depIdxs, + MessageInfos: file_gemini_proto_msgTypes, + }.Build() + File_gemini_proto = out.File + file_gemini_proto_goTypes = nil + file_gemini_proto_depIdxs = nil +} diff --git a/api-service/grpc/pb/gemini/gemini_grpc.pb.go b/api-service/grpc/pb/gemini/gemini_grpc.pb.go new file mode 100644 index 0000000..1b9e10b --- /dev/null +++ b/api-service/grpc/pb/gemini/gemini_grpc.pb.go @@ -0,0 +1,125 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.21.12 +// source: gemini.proto + +package gemini + +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 ( + Gemini_GenerateContent_FullMethodName = "/gemini_proto.Gemini/GenerateContent" +) + +// GeminiClient is the client API for Gemini 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. +// +// Gemini Service +type GeminiClient interface { + GenerateContent(ctx context.Context, in *GeminiRequest, opts ...grpc.CallOption) (*GeminiResponse, error) +} + +type geminiClient struct { + cc grpc.ClientConnInterface +} + +func NewGeminiClient(cc grpc.ClientConnInterface) GeminiClient { + return &geminiClient{cc} +} + +func (c *geminiClient) GenerateContent(ctx context.Context, in *GeminiRequest, opts ...grpc.CallOption) (*GeminiResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GeminiResponse) + err := c.cc.Invoke(ctx, Gemini_GenerateContent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GeminiServer is the server API for Gemini service. +// All implementations must embed UnimplementedGeminiServer +// for forward compatibility. +// +// Gemini Service +type GeminiServer interface { + GenerateContent(context.Context, *GeminiRequest) (*GeminiResponse, error) + mustEmbedUnimplementedGeminiServer() +} + +// UnimplementedGeminiServer 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 UnimplementedGeminiServer struct{} + +func (UnimplementedGeminiServer) GenerateContent(context.Context, *GeminiRequest) (*GeminiResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateContent not implemented") +} +func (UnimplementedGeminiServer) mustEmbedUnimplementedGeminiServer() {} +func (UnimplementedGeminiServer) testEmbeddedByValue() {} + +// UnsafeGeminiServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GeminiServer will +// result in compilation errors. +type UnsafeGeminiServer interface { + mustEmbedUnimplementedGeminiServer() +} + +func RegisterGeminiServer(s grpc.ServiceRegistrar, srv GeminiServer) { + // If the following call pancis, it indicates UnimplementedGeminiServer 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(&Gemini_ServiceDesc, srv) +} + +func _Gemini_GenerateContent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeminiRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GeminiServer).GenerateContent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gemini_GenerateContent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GeminiServer).GenerateContent(ctx, req.(*GeminiRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Gemini_ServiceDesc is the grpc.ServiceDesc for Gemini service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Gemini_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "gemini_proto.Gemini", + HandlerType: (*GeminiServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GenerateContent", + Handler: _Gemini_GenerateContent_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "gemini.proto", +} diff --git a/api-service/grpc/pb/maps/maps.pb.go b/api-service/grpc/pb/maps/maps.pb.go new file mode 100644 index 0000000..5d8b251 --- /dev/null +++ b/api-service/grpc/pb/maps/maps.pb.go @@ -0,0 +1,1770 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.21.12 +// source: maps.proto + +package maps + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// --- Geocoding --- +type GeocodeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeocodeRequest) Reset() { + *x = GeocodeRequest{} + mi := &file_maps_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeocodeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeRequest) ProtoMessage() {} + +func (x *GeocodeRequest) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 GeocodeRequest.ProtoReflect.Descriptor instead. +func (*GeocodeRequest) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{0} +} + +func (x *GeocodeRequest) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +type GeocodeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Results []*GeocodeResponse_Result `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeocodeResponse) Reset() { + *x = GeocodeResponse{} + mi := &file_maps_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeocodeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse) ProtoMessage() {} + +func (x *GeocodeResponse) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 GeocodeResponse.ProtoReflect.Descriptor instead. +func (*GeocodeResponse) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{1} +} + +func (x *GeocodeResponse) GetResults() []*GeocodeResponse_Result { + if x != nil { + return x.Results + } + return nil +} + +func (x *GeocodeResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +// --- Places Search --- +type SearchPlacesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SearchPlacesRequest) Reset() { + *x = SearchPlacesRequest{} + mi := &file_maps_proto_msgTypes[2] + 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_maps_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 SearchPlacesRequest.ProtoReflect.Descriptor instead. +func (*SearchPlacesRequest) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{2} +} + +func (x *SearchPlacesRequest) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *SearchPlacesRequest) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +type Place struct { + state protoimpl.MessageState `protogen:"open.v1"` + PlaceId string `protobuf:"bytes,1,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Vicinity string `protobuf:"bytes,3,opt,name=vicinity,proto3" json:"vicinity,omitempty"` + Rating float64 `protobuf:"fixed64,4,opt,name=rating,proto3" json:"rating,omitempty"` + UserRatingsTotal int32 `protobuf:"varint,5,opt,name=user_ratings_total,json=userRatingsTotal,proto3" json:"user_ratings_total,omitempty"` + GeometryLocation *Place_Location `protobuf:"bytes,6,opt,name=geometry_location,json=geometryLocation,proto3" json:"geometry_location,omitempty"` + OpeningHours *Place_OpeningHours `protobuf:"bytes,7,opt,name=opening_hours,json=openingHours,proto3" json:"opening_hours,omitempty"` + Photos []*Place_Photo `protobuf:"bytes,8,rep,name=photos,proto3" json:"photos,omitempty"` + PhotoUrls []string `protobuf:"bytes,9,rep,name=photo_urls,json=photoUrls,proto3" json:"photo_urls,omitempty"` + Types []string `protobuf:"bytes,10,rep,name=types,proto3" json:"types,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Place) Reset() { + *x = Place{} + mi := &file_maps_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Place) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place) ProtoMessage() {} + +func (x *Place) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 Place.ProtoReflect.Descriptor instead. +func (*Place) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{3} +} + +func (x *Place) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *Place) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Place) GetVicinity() string { + if x != nil { + return x.Vicinity + } + return "" +} + +func (x *Place) GetRating() float64 { + if x != nil { + return x.Rating + } + return 0 +} + +func (x *Place) GetUserRatingsTotal() int32 { + if x != nil { + return x.UserRatingsTotal + } + return 0 +} + +func (x *Place) GetGeometryLocation() *Place_Location { + if x != nil { + return x.GeometryLocation + } + return nil +} + +func (x *Place) GetOpeningHours() *Place_OpeningHours { + if x != nil { + return x.OpeningHours + } + return nil +} + +func (x *Place) GetPhotos() []*Place_Photo { + if x != nil { + return x.Photos + } + return nil +} + +func (x *Place) GetPhotoUrls() []string { + if x != nil { + return x.PhotoUrls + } + return nil +} + +func (x *Place) GetTypes() []string { + if x != nil { + return x.Types + } + return nil +} + +type SearchPlacesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Results []*Place `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SearchPlacesResponse) Reset() { + *x = SearchPlacesResponse{} + mi := &file_maps_proto_msgTypes[4] + 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_maps_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 SearchPlacesResponse.ProtoReflect.Descriptor instead. +func (*SearchPlacesResponse) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{4} +} + +func (x *SearchPlacesResponse) GetResults() []*Place { + if x != nil { + return x.Results + } + return nil +} + +func (x *SearchPlacesResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +// --- Place Details --- +type PlaceDetailsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + PlaceId string `protobuf:"bytes,1,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlaceDetailsRequest) Reset() { + *x = PlaceDetailsRequest{} + mi := &file_maps_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlaceDetailsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlaceDetailsRequest) ProtoMessage() {} + +func (x *PlaceDetailsRequest) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 PlaceDetailsRequest.ProtoReflect.Descriptor instead. +func (*PlaceDetailsRequest) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{5} +} + +func (x *PlaceDetailsRequest) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +type PlaceDetailsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Result *Place `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlaceDetailsResponse) Reset() { + *x = PlaceDetailsResponse{} + mi := &file_maps_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlaceDetailsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlaceDetailsResponse) ProtoMessage() {} + +func (x *PlaceDetailsResponse) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 PlaceDetailsResponse.ProtoReflect.Descriptor instead. +func (*PlaceDetailsResponse) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{6} +} + +func (x *PlaceDetailsResponse) GetResult() *Place { + if x != nil { + return x.Result + } + return nil +} + +func (x *PlaceDetailsResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +// --- Directions --- +type DirectionsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Origin string `protobuf:"bytes,1,opt,name=origin,proto3" json:"origin,omitempty"` + Destination string `protobuf:"bytes,2,opt,name=destination,proto3" json:"destination,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsRequest) Reset() { + *x = DirectionsRequest{} + mi := &file_maps_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsRequest) ProtoMessage() {} + +func (x *DirectionsRequest) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DirectionsRequest.ProtoReflect.Descriptor instead. +func (*DirectionsRequest) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{7} +} + +func (x *DirectionsRequest) GetOrigin() string { + if x != nil { + return x.Origin + } + return "" +} + +func (x *DirectionsRequest) GetDestination() string { + if x != nil { + return x.Destination + } + return "" +} + +type DirectionsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Routes []*DirectionsResponse_Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + GeocodedWaypoints []*DirectionsResponse_GeocodedWaypoint `protobuf:"bytes,2,rep,name=geocoded_waypoints,json=geocodedWaypoints,proto3" json:"geocoded_waypoints,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse) Reset() { + *x = DirectionsResponse{} + mi := &file_maps_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse) ProtoMessage() {} + +func (x *DirectionsResponse) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DirectionsResponse.ProtoReflect.Descriptor instead. +func (*DirectionsResponse) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8} +} + +func (x *DirectionsResponse) GetRoutes() []*DirectionsResponse_Route { + if x != nil { + return x.Routes + } + return nil +} + +func (x *DirectionsResponse) GetGeocodedWaypoints() []*DirectionsResponse_GeocodedWaypoint { + if x != nil { + return x.GeocodedWaypoints + } + return nil +} + +func (x *DirectionsResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +// --- Distance Matrix --- +type DistanceMatrixRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Origins string `protobuf:"bytes,1,opt,name=origins,proto3" json:"origins,omitempty"` + Destinations string `protobuf:"bytes,2,opt,name=destinations,proto3" json:"destinations,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistanceMatrixRequest) Reset() { + *x = DistanceMatrixRequest{} + mi := &file_maps_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistanceMatrixRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixRequest) ProtoMessage() {} + +func (x *DistanceMatrixRequest) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DistanceMatrixRequest.ProtoReflect.Descriptor instead. +func (*DistanceMatrixRequest) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{9} +} + +func (x *DistanceMatrixRequest) GetOrigins() string { + if x != nil { + return x.Origins + } + return "" +} + +func (x *DistanceMatrixRequest) GetDestinations() string { + if x != nil { + return x.Destinations + } + return "" +} + +type DistanceMatrixResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + OriginAddresses []string `protobuf:"bytes,1,rep,name=origin_addresses,json=originAddresses,proto3" json:"origin_addresses,omitempty"` + DestinationAddresses []string `protobuf:"bytes,2,rep,name=destination_addresses,json=destinationAddresses,proto3" json:"destination_addresses,omitempty"` + Rows []*DistanceMatrixResponse_Row `protobuf:"bytes,3,rep,name=rows,proto3" json:"rows,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistanceMatrixResponse) Reset() { + *x = DistanceMatrixResponse{} + mi := &file_maps_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistanceMatrixResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse) ProtoMessage() {} + +func (x *DistanceMatrixResponse) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DistanceMatrixResponse.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{10} +} + +func (x *DistanceMatrixResponse) GetOriginAddresses() []string { + if x != nil { + return x.OriginAddresses + } + return nil +} + +func (x *DistanceMatrixResponse) GetDestinationAddresses() []string { + if x != nil { + return x.DestinationAddresses + } + return nil +} + +func (x *DistanceMatrixResponse) GetRows() []*DistanceMatrixResponse_Row { + if x != nil { + return x.Rows + } + return nil +} + +func (x *DistanceMatrixResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type GeocodeResponse_Location struct { + state protoimpl.MessageState `protogen:"open.v1"` + Lat float64 `protobuf:"fixed64,1,opt,name=lat,proto3" json:"lat,omitempty"` + Lng float64 `protobuf:"fixed64,2,opt,name=lng,proto3" json:"lng,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeocodeResponse_Location) Reset() { + *x = GeocodeResponse_Location{} + mi := &file_maps_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeocodeResponse_Location) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse_Location) ProtoMessage() {} + +func (x *GeocodeResponse_Location) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 GeocodeResponse_Location.ProtoReflect.Descriptor instead. +func (*GeocodeResponse_Location) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *GeocodeResponse_Location) GetLat() float64 { + if x != nil { + return x.Lat + } + return 0 +} + +func (x *GeocodeResponse_Location) GetLng() float64 { + if x != nil { + return x.Lng + } + return 0 +} + +type GeocodeResponse_Result struct { + state protoimpl.MessageState `protogen:"open.v1"` + FormattedAddress string `protobuf:"bytes,1,opt,name=formatted_address,json=formattedAddress,proto3" json:"formatted_address,omitempty"` + Location *GeocodeResponse_Location `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GeocodeResponse_Result) Reset() { + *x = GeocodeResponse_Result{} + mi := &file_maps_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GeocodeResponse_Result) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse_Result) ProtoMessage() {} + +func (x *GeocodeResponse_Result) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 GeocodeResponse_Result.ProtoReflect.Descriptor instead. +func (*GeocodeResponse_Result) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{1, 1} +} + +func (x *GeocodeResponse_Result) GetFormattedAddress() string { + if x != nil { + return x.FormattedAddress + } + return "" +} + +func (x *GeocodeResponse_Result) GetLocation() *GeocodeResponse_Location { + if x != nil { + return x.Location + } + return nil +} + +type Place_Location struct { + state protoimpl.MessageState `protogen:"open.v1"` + Lat float64 `protobuf:"fixed64,1,opt,name=lat,proto3" json:"lat,omitempty"` + Lng float64 `protobuf:"fixed64,2,opt,name=lng,proto3" json:"lng,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Place_Location) Reset() { + *x = Place_Location{} + mi := &file_maps_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Place_Location) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_Location) ProtoMessage() {} + +func (x *Place_Location) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 Place_Location.ProtoReflect.Descriptor instead. +func (*Place_Location) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *Place_Location) GetLat() float64 { + if x != nil { + return x.Lat + } + return 0 +} + +func (x *Place_Location) GetLng() float64 { + if x != nil { + return x.Lng + } + return 0 +} + +type Place_OpeningHours struct { + state protoimpl.MessageState `protogen:"open.v1"` + OpenNow bool `protobuf:"varint,1,opt,name=open_now,json=openNow,proto3" json:"open_now,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Place_OpeningHours) Reset() { + *x = Place_OpeningHours{} + mi := &file_maps_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Place_OpeningHours) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_OpeningHours) ProtoMessage() {} + +func (x *Place_OpeningHours) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 Place_OpeningHours.ProtoReflect.Descriptor instead. +func (*Place_OpeningHours) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{3, 1} +} + +func (x *Place_OpeningHours) GetOpenNow() bool { + if x != nil { + return x.OpenNow + } + return false +} + +type Place_Photo struct { + state protoimpl.MessageState `protogen:"open.v1"` + PhotoReference string `protobuf:"bytes,1,opt,name=photo_reference,json=photoReference,proto3" json:"photo_reference,omitempty"` + Height int32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + Width int32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Place_Photo) Reset() { + *x = Place_Photo{} + mi := &file_maps_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Place_Photo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_Photo) ProtoMessage() {} + +func (x *Place_Photo) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 Place_Photo.ProtoReflect.Descriptor instead. +func (*Place_Photo) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{3, 2} +} + +func (x *Place_Photo) GetPhotoReference() string { + if x != nil { + return x.PhotoReference + } + return "" +} + +func (x *Place_Photo) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +func (x *Place_Photo) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +type DirectionsResponse_Distance struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // meters + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse_Distance) Reset() { + *x = DirectionsResponse_Distance{} + mi := &file_maps_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse_Distance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Distance) ProtoMessage() {} + +func (x *DirectionsResponse_Distance) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DirectionsResponse_Distance.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Distance) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8, 0} +} + +func (x *DirectionsResponse_Distance) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DirectionsResponse_Distance) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DirectionsResponse_Duration struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // seconds + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse_Duration) Reset() { + *x = DirectionsResponse_Duration{} + mi := &file_maps_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse_Duration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Duration) ProtoMessage() {} + +func (x *DirectionsResponse_Duration) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DirectionsResponse_Duration.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Duration) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8, 1} +} + +func (x *DirectionsResponse_Duration) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DirectionsResponse_Duration) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DirectionsResponse_Polyline struct { + state protoimpl.MessageState `protogen:"open.v1"` + Points string `protobuf:"bytes,1,opt,name=points,proto3" json:"points,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse_Polyline) Reset() { + *x = DirectionsResponse_Polyline{} + mi := &file_maps_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse_Polyline) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Polyline) ProtoMessage() {} + +func (x *DirectionsResponse_Polyline) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DirectionsResponse_Polyline.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Polyline) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8, 2} +} + +func (x *DirectionsResponse_Polyline) GetPoints() string { + if x != nil { + return x.Points + } + return "" +} + +type DirectionsResponse_Step struct { + state protoimpl.MessageState `protogen:"open.v1"` + HtmlInstructions string `protobuf:"bytes,1,opt,name=html_instructions,json=htmlInstructions,proto3" json:"html_instructions,omitempty"` + Distance *DirectionsResponse_Distance `protobuf:"bytes,2,opt,name=distance,proto3" json:"distance,omitempty"` + Duration *DirectionsResponse_Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + Polyline *DirectionsResponse_Polyline `protobuf:"bytes,4,opt,name=polyline,proto3" json:"polyline,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse_Step) Reset() { + *x = DirectionsResponse_Step{} + mi := &file_maps_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse_Step) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Step) ProtoMessage() {} + +func (x *DirectionsResponse_Step) ProtoReflect() protoreflect.Message { + mi := &file_maps_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 DirectionsResponse_Step.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Step) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8, 3} +} + +func (x *DirectionsResponse_Step) GetHtmlInstructions() string { + if x != nil { + return x.HtmlInstructions + } + return "" +} + +func (x *DirectionsResponse_Step) GetDistance() *DirectionsResponse_Distance { + if x != nil { + return x.Distance + } + return nil +} + +func (x *DirectionsResponse_Step) GetDuration() *DirectionsResponse_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DirectionsResponse_Step) GetPolyline() *DirectionsResponse_Polyline { + if x != nil { + return x.Polyline + } + return nil +} + +type DirectionsResponse_Leg struct { + state protoimpl.MessageState `protogen:"open.v1"` + Distance *DirectionsResponse_Distance `protobuf:"bytes,1,opt,name=distance,proto3" json:"distance,omitempty"` + Duration *DirectionsResponse_Duration `protobuf:"bytes,2,opt,name=duration,proto3" json:"duration,omitempty"` + StartAddress string `protobuf:"bytes,3,opt,name=start_address,json=startAddress,proto3" json:"start_address,omitempty"` + EndAddress string `protobuf:"bytes,4,opt,name=end_address,json=endAddress,proto3" json:"end_address,omitempty"` + Steps []*DirectionsResponse_Step `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse_Leg) Reset() { + *x = DirectionsResponse_Leg{} + mi := &file_maps_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse_Leg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Leg) ProtoMessage() {} + +func (x *DirectionsResponse_Leg) ProtoReflect() protoreflect.Message { + mi := &file_maps_proto_msgTypes[20] + 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 DirectionsResponse_Leg.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Leg) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8, 4} +} + +func (x *DirectionsResponse_Leg) GetDistance() *DirectionsResponse_Distance { + if x != nil { + return x.Distance + } + return nil +} + +func (x *DirectionsResponse_Leg) GetDuration() *DirectionsResponse_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DirectionsResponse_Leg) GetStartAddress() string { + if x != nil { + return x.StartAddress + } + return "" +} + +func (x *DirectionsResponse_Leg) GetEndAddress() string { + if x != nil { + return x.EndAddress + } + return "" +} + +func (x *DirectionsResponse_Leg) GetSteps() []*DirectionsResponse_Step { + if x != nil { + return x.Steps + } + return nil +} + +type DirectionsResponse_Route struct { + state protoimpl.MessageState `protogen:"open.v1"` + Summary string `protobuf:"bytes,1,opt,name=summary,proto3" json:"summary,omitempty"` + Legs []*DirectionsResponse_Leg `protobuf:"bytes,2,rep,name=legs,proto3" json:"legs,omitempty"` + OverviewPolyline *DirectionsResponse_Polyline `protobuf:"bytes,3,opt,name=overview_polyline,json=overviewPolyline,proto3" json:"overview_polyline,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse_Route) Reset() { + *x = DirectionsResponse_Route{} + mi := &file_maps_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse_Route) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Route) ProtoMessage() {} + +func (x *DirectionsResponse_Route) ProtoReflect() protoreflect.Message { + mi := &file_maps_proto_msgTypes[21] + 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 DirectionsResponse_Route.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Route) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8, 5} +} + +func (x *DirectionsResponse_Route) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *DirectionsResponse_Route) GetLegs() []*DirectionsResponse_Leg { + if x != nil { + return x.Legs + } + return nil +} + +func (x *DirectionsResponse_Route) GetOverviewPolyline() *DirectionsResponse_Polyline { + if x != nil { + return x.OverviewPolyline + } + return nil +} + +type DirectionsResponse_GeocodedWaypoint struct { + state protoimpl.MessageState `protogen:"open.v1"` + GeocoderStatus string `protobuf:"bytes,1,opt,name=geocoder_status,json=geocoderStatus,proto3" json:"geocoder_status,omitempty"` + PlaceId string `protobuf:"bytes,2,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + Types []string `protobuf:"bytes,3,rep,name=types,proto3" json:"types,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectionsResponse_GeocodedWaypoint) Reset() { + *x = DirectionsResponse_GeocodedWaypoint{} + mi := &file_maps_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectionsResponse_GeocodedWaypoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_GeocodedWaypoint) ProtoMessage() {} + +func (x *DirectionsResponse_GeocodedWaypoint) ProtoReflect() protoreflect.Message { + mi := &file_maps_proto_msgTypes[22] + 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 DirectionsResponse_GeocodedWaypoint.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_GeocodedWaypoint) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{8, 6} +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetGeocoderStatus() string { + if x != nil { + return x.GeocoderStatus + } + return "" +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetTypes() []string { + if x != nil { + return x.Types + } + return nil +} + +type DistanceMatrixResponse_Element struct { + state protoimpl.MessageState `protogen:"open.v1"` + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + Duration *DistanceMatrixResponse_Element_Duration `protobuf:"bytes,2,opt,name=duration,proto3" json:"duration,omitempty"` + Distance *DistanceMatrixResponse_Element_Distance `protobuf:"bytes,3,opt,name=distance,proto3" json:"distance,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistanceMatrixResponse_Element) Reset() { + *x = DistanceMatrixResponse_Element{} + mi := &file_maps_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistanceMatrixResponse_Element) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element) ProtoReflect() protoreflect.Message { + mi := &file_maps_proto_msgTypes[23] + 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 DistanceMatrixResponse_Element.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{10, 0} +} + +func (x *DistanceMatrixResponse_Element) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *DistanceMatrixResponse_Element) GetDuration() *DistanceMatrixResponse_Element_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DistanceMatrixResponse_Element) GetDistance() *DistanceMatrixResponse_Element_Distance { + if x != nil { + return x.Distance + } + return nil +} + +type DistanceMatrixResponse_Row struct { + state protoimpl.MessageState `protogen:"open.v1"` + Elements []*DistanceMatrixResponse_Element `protobuf:"bytes,1,rep,name=elements,proto3" json:"elements,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistanceMatrixResponse_Row) Reset() { + *x = DistanceMatrixResponse_Row{} + mi := &file_maps_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistanceMatrixResponse_Row) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Row) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Row) ProtoReflect() protoreflect.Message { + mi := &file_maps_proto_msgTypes[24] + 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 DistanceMatrixResponse_Row.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Row) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{10, 1} +} + +func (x *DistanceMatrixResponse_Row) GetElements() []*DistanceMatrixResponse_Element { + if x != nil { + return x.Elements + } + return nil +} + +type DistanceMatrixResponse_Element_Duration struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // seconds + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistanceMatrixResponse_Element_Duration) Reset() { + *x = DistanceMatrixResponse_Element_Duration{} + mi := &file_maps_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistanceMatrixResponse_Element_Duration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element_Duration) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element_Duration) ProtoReflect() protoreflect.Message { + mi := &file_maps_proto_msgTypes[25] + 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 DistanceMatrixResponse_Element_Duration.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element_Duration) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{10, 0, 0} +} + +func (x *DistanceMatrixResponse_Element_Duration) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DistanceMatrixResponse_Element_Duration) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DistanceMatrixResponse_Element_Distance struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // meters + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistanceMatrixResponse_Element_Distance) Reset() { + *x = DistanceMatrixResponse_Element_Distance{} + mi := &file_maps_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistanceMatrixResponse_Element_Distance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element_Distance) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element_Distance) ProtoReflect() protoreflect.Message { + mi := &file_maps_proto_msgTypes[26] + 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 DistanceMatrixResponse_Element_Distance.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element_Distance) Descriptor() ([]byte, []int) { + return file_maps_proto_rawDescGZIP(), []int{10, 0, 1} +} + +func (x *DistanceMatrixResponse_Element_Distance) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DistanceMatrixResponse_Element_Distance) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +var File_maps_proto protoreflect.FileDescriptor + +const file_maps_proto_rawDesc = "" + + "\n" + + "\n" + + "maps.proto\x12\n" + + "maps_proto\"*\n" + + "\x0eGeocodeRequest\x12\x18\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\"\x90\x02\n" + + "\x0fGeocodeResponse\x12<\n" + + "\aresults\x18\x01 \x03(\v2\".maps_proto.GeocodeResponse.ResultR\aresults\x12\x16\n" + + "\x06status\x18\x02 \x01(\tR\x06status\x1a.\n" + + "\bLocation\x12\x10\n" + + "\x03lat\x18\x01 \x01(\x01R\x03lat\x12\x10\n" + + "\x03lng\x18\x02 \x01(\x01R\x03lng\x1aw\n" + + "\x06Result\x12+\n" + + "\x11formatted_address\x18\x01 \x01(\tR\x10formattedAddress\x12@\n" + + "\blocation\x18\x02 \x01(\v2$.maps_proto.GeocodeResponse.LocationR\blocation\"G\n" + + "\x13SearchPlacesRequest\x12\x14\n" + + "\x05query\x18\x01 \x01(\tR\x05query\x12\x1a\n" + + "\blocation\x18\x02 \x01(\tR\blocation\"\xc7\x04\n" + + "\x05Place\x12\x19\n" + + "\bplace_id\x18\x01 \x01(\tR\aplaceId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1a\n" + + "\bvicinity\x18\x03 \x01(\tR\bvicinity\x12\x16\n" + + "\x06rating\x18\x04 \x01(\x01R\x06rating\x12,\n" + + "\x12user_ratings_total\x18\x05 \x01(\x05R\x10userRatingsTotal\x12G\n" + + "\x11geometry_location\x18\x06 \x01(\v2\x1a.maps_proto.Place.LocationR\x10geometryLocation\x12C\n" + + "\ropening_hours\x18\a \x01(\v2\x1e.maps_proto.Place.OpeningHoursR\fopeningHours\x12/\n" + + "\x06photos\x18\b \x03(\v2\x17.maps_proto.Place.PhotoR\x06photos\x12\x1d\n" + + "\n" + + "photo_urls\x18\t \x03(\tR\tphotoUrls\x12\x14\n" + + "\x05types\x18\n" + + " \x03(\tR\x05types\x1a.\n" + + "\bLocation\x12\x10\n" + + "\x03lat\x18\x01 \x01(\x01R\x03lat\x12\x10\n" + + "\x03lng\x18\x02 \x01(\x01R\x03lng\x1a)\n" + + "\fOpeningHours\x12\x19\n" + + "\bopen_now\x18\x01 \x01(\bR\aopenNow\x1a^\n" + + "\x05Photo\x12'\n" + + "\x0fphoto_reference\x18\x01 \x01(\tR\x0ephotoReference\x12\x16\n" + + "\x06height\x18\x02 \x01(\x05R\x06height\x12\x14\n" + + "\x05width\x18\x03 \x01(\x05R\x05width\"[\n" + + "\x14SearchPlacesResponse\x12+\n" + + "\aresults\x18\x01 \x03(\v2\x11.maps_proto.PlaceR\aresults\x12\x16\n" + + "\x06status\x18\x02 \x01(\tR\x06status\"0\n" + + "\x13PlaceDetailsRequest\x12\x19\n" + + "\bplace_id\x18\x01 \x01(\tR\aplaceId\"Y\n" + + "\x14PlaceDetailsResponse\x12)\n" + + "\x06result\x18\x01 \x01(\v2\x11.maps_proto.PlaceR\x06result\x12\x16\n" + + "\x06status\x18\x02 \x01(\tR\x06status\"M\n" + + "\x11DirectionsRequest\x12\x16\n" + + "\x06origin\x18\x01 \x01(\tR\x06origin\x12 \n" + + "\vdestination\x18\x02 \x01(\tR\vdestination\"\x92\t\n" + + "\x12DirectionsResponse\x12<\n" + + "\x06routes\x18\x01 \x03(\v2$.maps_proto.DirectionsResponse.RouteR\x06routes\x12^\n" + + "\x12geocoded_waypoints\x18\x02 \x03(\v2/.maps_proto.DirectionsResponse.GeocodedWaypointR\x11geocodedWaypoints\x12\x16\n" + + "\x06status\x18\x03 \x01(\tR\x06status\x1a4\n" + + "\bDistance\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\x12\x14\n" + + "\x05value\x18\x02 \x01(\x05R\x05value\x1a4\n" + + "\bDuration\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\x12\x14\n" + + "\x05value\x18\x02 \x01(\x05R\x05value\x1a\"\n" + + "\bPolyline\x12\x16\n" + + "\x06points\x18\x01 \x01(\tR\x06points\x1a\x82\x02\n" + + "\x04Step\x12+\n" + + "\x11html_instructions\x18\x01 \x01(\tR\x10htmlInstructions\x12C\n" + + "\bdistance\x18\x02 \x01(\v2'.maps_proto.DirectionsResponse.DistanceR\bdistance\x12C\n" + + "\bduration\x18\x03 \x01(\v2'.maps_proto.DirectionsResponse.DurationR\bduration\x12C\n" + + "\bpolyline\x18\x04 \x01(\v2'.maps_proto.DirectionsResponse.PolylineR\bpolyline\x1a\x90\x02\n" + + "\x03Leg\x12C\n" + + "\bdistance\x18\x01 \x01(\v2'.maps_proto.DirectionsResponse.DistanceR\bdistance\x12C\n" + + "\bduration\x18\x02 \x01(\v2'.maps_proto.DirectionsResponse.DurationR\bduration\x12#\n" + + "\rstart_address\x18\x03 \x01(\tR\fstartAddress\x12\x1f\n" + + "\vend_address\x18\x04 \x01(\tR\n" + + "endAddress\x129\n" + + "\x05steps\x18\x05 \x03(\v2#.maps_proto.DirectionsResponse.StepR\x05steps\x1a\xaf\x01\n" + + "\x05Route\x12\x18\n" + + "\asummary\x18\x01 \x01(\tR\asummary\x126\n" + + "\x04legs\x18\x02 \x03(\v2\".maps_proto.DirectionsResponse.LegR\x04legs\x12T\n" + + "\x11overview_polyline\x18\x03 \x01(\v2'.maps_proto.DirectionsResponse.PolylineR\x10overviewPolyline\x1al\n" + + "\x10GeocodedWaypoint\x12'\n" + + "\x0fgeocoder_status\x18\x01 \x01(\tR\x0egeocoderStatus\x12\x19\n" + + "\bplace_id\x18\x02 \x01(\tR\aplaceId\x12\x14\n" + + "\x05types\x18\x03 \x03(\tR\x05types\"U\n" + + "\x15DistanceMatrixRequest\x12\x18\n" + + "\aorigins\x18\x01 \x01(\tR\aorigins\x12\"\n" + + "\fdestinations\x18\x02 \x01(\tR\fdestinations\"\xcd\x04\n" + + "\x16DistanceMatrixResponse\x12)\n" + + "\x10origin_addresses\x18\x01 \x03(\tR\x0foriginAddresses\x123\n" + + "\x15destination_addresses\x18\x02 \x03(\tR\x14destinationAddresses\x12:\n" + + "\x04rows\x18\x03 \x03(\v2&.maps_proto.DistanceMatrixResponse.RowR\x04rows\x12\x16\n" + + "\x06status\x18\x04 \x01(\tR\x06status\x1a\xaf\x02\n" + + "\aElement\x12\x16\n" + + "\x06status\x18\x01 \x01(\tR\x06status\x12O\n" + + "\bduration\x18\x02 \x01(\v23.maps_proto.DistanceMatrixResponse.Element.DurationR\bduration\x12O\n" + + "\bdistance\x18\x03 \x01(\v23.maps_proto.DistanceMatrixResponse.Element.DistanceR\bdistance\x1a4\n" + + "\bDuration\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\x12\x14\n" + + "\x05value\x18\x02 \x01(\x05R\x05value\x1a4\n" + + "\bDistance\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\x12\x14\n" + + "\x05value\x18\x02 \x01(\x05R\x05value\x1aM\n" + + "\x03Row\x12F\n" + + "\belements\x18\x01 \x03(\v2*.maps_proto.DistanceMatrixResponse.ElementR\belements2\x9f\x03\n" + + "\x04Maps\x12B\n" + + "\aGeocode\x12\x1a.maps_proto.GeocodeRequest\x1a\x1b.maps_proto.GeocodeResponse\x12Q\n" + + "\fSearchPlaces\x12\x1f.maps_proto.SearchPlacesRequest\x1a .maps_proto.SearchPlacesResponse\x12T\n" + + "\x0fGetPlaceDetails\x12\x1f.maps_proto.PlaceDetailsRequest\x1a .maps_proto.PlaceDetailsResponse\x12N\n" + + "\rGetDirections\x12\x1d.maps_proto.DirectionsRequest\x1a\x1e.maps_proto.DirectionsResponse\x12Z\n" + + "\x11GetDistanceMatrix\x12!.maps_proto.DistanceMatrixRequest\x1a\".maps_proto.DistanceMatrixResponseBG\n" + + ")com.example.planning.grpc.apiservice.mapsP\x01Z\x18api-service/grpc/pb/mapsb\x06proto3" + +var ( + file_maps_proto_rawDescOnce sync.Once + file_maps_proto_rawDescData []byte +) + +func file_maps_proto_rawDescGZIP() []byte { + file_maps_proto_rawDescOnce.Do(func() { + file_maps_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_maps_proto_rawDesc), len(file_maps_proto_rawDesc))) + }) + return file_maps_proto_rawDescData +} + +var file_maps_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_maps_proto_goTypes = []any{ + (*GeocodeRequest)(nil), // 0: maps_proto.GeocodeRequest + (*GeocodeResponse)(nil), // 1: maps_proto.GeocodeResponse + (*SearchPlacesRequest)(nil), // 2: maps_proto.SearchPlacesRequest + (*Place)(nil), // 3: maps_proto.Place + (*SearchPlacesResponse)(nil), // 4: maps_proto.SearchPlacesResponse + (*PlaceDetailsRequest)(nil), // 5: maps_proto.PlaceDetailsRequest + (*PlaceDetailsResponse)(nil), // 6: maps_proto.PlaceDetailsResponse + (*DirectionsRequest)(nil), // 7: maps_proto.DirectionsRequest + (*DirectionsResponse)(nil), // 8: maps_proto.DirectionsResponse + (*DistanceMatrixRequest)(nil), // 9: maps_proto.DistanceMatrixRequest + (*DistanceMatrixResponse)(nil), // 10: maps_proto.DistanceMatrixResponse + (*GeocodeResponse_Location)(nil), // 11: maps_proto.GeocodeResponse.Location + (*GeocodeResponse_Result)(nil), // 12: maps_proto.GeocodeResponse.Result + (*Place_Location)(nil), // 13: maps_proto.Place.Location + (*Place_OpeningHours)(nil), // 14: maps_proto.Place.OpeningHours + (*Place_Photo)(nil), // 15: maps_proto.Place.Photo + (*DirectionsResponse_Distance)(nil), // 16: maps_proto.DirectionsResponse.Distance + (*DirectionsResponse_Duration)(nil), // 17: maps_proto.DirectionsResponse.Duration + (*DirectionsResponse_Polyline)(nil), // 18: maps_proto.DirectionsResponse.Polyline + (*DirectionsResponse_Step)(nil), // 19: maps_proto.DirectionsResponse.Step + (*DirectionsResponse_Leg)(nil), // 20: maps_proto.DirectionsResponse.Leg + (*DirectionsResponse_Route)(nil), // 21: maps_proto.DirectionsResponse.Route + (*DirectionsResponse_GeocodedWaypoint)(nil), // 22: maps_proto.DirectionsResponse.GeocodedWaypoint + (*DistanceMatrixResponse_Element)(nil), // 23: maps_proto.DistanceMatrixResponse.Element + (*DistanceMatrixResponse_Row)(nil), // 24: maps_proto.DistanceMatrixResponse.Row + (*DistanceMatrixResponse_Element_Duration)(nil), // 25: maps_proto.DistanceMatrixResponse.Element.Duration + (*DistanceMatrixResponse_Element_Distance)(nil), // 26: maps_proto.DistanceMatrixResponse.Element.Distance +} +var file_maps_proto_depIdxs = []int32{ + 12, // 0: maps_proto.GeocodeResponse.results:type_name -> maps_proto.GeocodeResponse.Result + 13, // 1: maps_proto.Place.geometry_location:type_name -> maps_proto.Place.Location + 14, // 2: maps_proto.Place.opening_hours:type_name -> maps_proto.Place.OpeningHours + 15, // 3: maps_proto.Place.photos:type_name -> maps_proto.Place.Photo + 3, // 4: maps_proto.SearchPlacesResponse.results:type_name -> maps_proto.Place + 3, // 5: maps_proto.PlaceDetailsResponse.result:type_name -> maps_proto.Place + 21, // 6: maps_proto.DirectionsResponse.routes:type_name -> maps_proto.DirectionsResponse.Route + 22, // 7: maps_proto.DirectionsResponse.geocoded_waypoints:type_name -> maps_proto.DirectionsResponse.GeocodedWaypoint + 24, // 8: maps_proto.DistanceMatrixResponse.rows:type_name -> maps_proto.DistanceMatrixResponse.Row + 11, // 9: maps_proto.GeocodeResponse.Result.location:type_name -> maps_proto.GeocodeResponse.Location + 16, // 10: maps_proto.DirectionsResponse.Step.distance:type_name -> maps_proto.DirectionsResponse.Distance + 17, // 11: maps_proto.DirectionsResponse.Step.duration:type_name -> maps_proto.DirectionsResponse.Duration + 18, // 12: maps_proto.DirectionsResponse.Step.polyline:type_name -> maps_proto.DirectionsResponse.Polyline + 16, // 13: maps_proto.DirectionsResponse.Leg.distance:type_name -> maps_proto.DirectionsResponse.Distance + 17, // 14: maps_proto.DirectionsResponse.Leg.duration:type_name -> maps_proto.DirectionsResponse.Duration + 19, // 15: maps_proto.DirectionsResponse.Leg.steps:type_name -> maps_proto.DirectionsResponse.Step + 20, // 16: maps_proto.DirectionsResponse.Route.legs:type_name -> maps_proto.DirectionsResponse.Leg + 18, // 17: maps_proto.DirectionsResponse.Route.overview_polyline:type_name -> maps_proto.DirectionsResponse.Polyline + 25, // 18: maps_proto.DistanceMatrixResponse.Element.duration:type_name -> maps_proto.DistanceMatrixResponse.Element.Duration + 26, // 19: maps_proto.DistanceMatrixResponse.Element.distance:type_name -> maps_proto.DistanceMatrixResponse.Element.Distance + 23, // 20: maps_proto.DistanceMatrixResponse.Row.elements:type_name -> maps_proto.DistanceMatrixResponse.Element + 0, // 21: maps_proto.Maps.Geocode:input_type -> maps_proto.GeocodeRequest + 2, // 22: maps_proto.Maps.SearchPlaces:input_type -> maps_proto.SearchPlacesRequest + 5, // 23: maps_proto.Maps.GetPlaceDetails:input_type -> maps_proto.PlaceDetailsRequest + 7, // 24: maps_proto.Maps.GetDirections:input_type -> maps_proto.DirectionsRequest + 9, // 25: maps_proto.Maps.GetDistanceMatrix:input_type -> maps_proto.DistanceMatrixRequest + 1, // 26: maps_proto.Maps.Geocode:output_type -> maps_proto.GeocodeResponse + 4, // 27: maps_proto.Maps.SearchPlaces:output_type -> maps_proto.SearchPlacesResponse + 6, // 28: maps_proto.Maps.GetPlaceDetails:output_type -> maps_proto.PlaceDetailsResponse + 8, // 29: maps_proto.Maps.GetDirections:output_type -> maps_proto.DirectionsResponse + 10, // 30: maps_proto.Maps.GetDistanceMatrix:output_type -> maps_proto.DistanceMatrixResponse + 26, // [26:31] is the sub-list for method output_type + 21, // [21:26] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name +} + +func init() { file_maps_proto_init() } +func file_maps_proto_init() { + if File_maps_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_maps_proto_rawDesc), len(file_maps_proto_rawDesc)), + NumEnums: 0, + NumMessages: 27, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_maps_proto_goTypes, + DependencyIndexes: file_maps_proto_depIdxs, + MessageInfos: file_maps_proto_msgTypes, + }.Build() + File_maps_proto = out.File + file_maps_proto_goTypes = nil + file_maps_proto_depIdxs = nil +} diff --git a/api-service/grpc/pb/maps/maps_grpc.pb.go b/api-service/grpc/pb/maps/maps_grpc.pb.go new file mode 100644 index 0000000..9a539b7 --- /dev/null +++ b/api-service/grpc/pb/maps/maps_grpc.pb.go @@ -0,0 +1,277 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.21.12 +// source: maps.proto + +package maps + +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 ( + Maps_Geocode_FullMethodName = "/maps_proto.Maps/Geocode" + Maps_SearchPlaces_FullMethodName = "/maps_proto.Maps/SearchPlaces" + Maps_GetPlaceDetails_FullMethodName = "/maps_proto.Maps/GetPlaceDetails" + Maps_GetDirections_FullMethodName = "/maps_proto.Maps/GetDirections" + Maps_GetDistanceMatrix_FullMethodName = "/maps_proto.Maps/GetDistanceMatrix" +) + +// MapsClient is the client API for Maps 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. +// +// Maps Service +type MapsClient interface { + Geocode(ctx context.Context, in *GeocodeRequest, opts ...grpc.CallOption) (*GeocodeResponse, error) + SearchPlaces(ctx context.Context, in *SearchPlacesRequest, opts ...grpc.CallOption) (*SearchPlacesResponse, error) + GetPlaceDetails(ctx context.Context, in *PlaceDetailsRequest, opts ...grpc.CallOption) (*PlaceDetailsResponse, error) + GetDirections(ctx context.Context, in *DirectionsRequest, opts ...grpc.CallOption) (*DirectionsResponse, error) + GetDistanceMatrix(ctx context.Context, in *DistanceMatrixRequest, opts ...grpc.CallOption) (*DistanceMatrixResponse, error) +} + +type mapsClient struct { + cc grpc.ClientConnInterface +} + +func NewMapsClient(cc grpc.ClientConnInterface) MapsClient { + return &mapsClient{cc} +} + +func (c *mapsClient) Geocode(ctx context.Context, in *GeocodeRequest, opts ...grpc.CallOption) (*GeocodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GeocodeResponse) + err := c.cc.Invoke(ctx, Maps_Geocode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) 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, Maps_SearchPlaces_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) GetPlaceDetails(ctx context.Context, in *PlaceDetailsRequest, opts ...grpc.CallOption) (*PlaceDetailsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PlaceDetailsResponse) + err := c.cc.Invoke(ctx, Maps_GetPlaceDetails_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) GetDirections(ctx context.Context, in *DirectionsRequest, opts ...grpc.CallOption) (*DirectionsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DirectionsResponse) + err := c.cc.Invoke(ctx, Maps_GetDirections_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) GetDistanceMatrix(ctx context.Context, in *DistanceMatrixRequest, opts ...grpc.CallOption) (*DistanceMatrixResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DistanceMatrixResponse) + err := c.cc.Invoke(ctx, Maps_GetDistanceMatrix_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MapsServer is the server API for Maps service. +// All implementations must embed UnimplementedMapsServer +// for forward compatibility. +// +// Maps Service +type MapsServer interface { + Geocode(context.Context, *GeocodeRequest) (*GeocodeResponse, error) + SearchPlaces(context.Context, *SearchPlacesRequest) (*SearchPlacesResponse, error) + GetPlaceDetails(context.Context, *PlaceDetailsRequest) (*PlaceDetailsResponse, error) + GetDirections(context.Context, *DirectionsRequest) (*DirectionsResponse, error) + GetDistanceMatrix(context.Context, *DistanceMatrixRequest) (*DistanceMatrixResponse, error) + mustEmbedUnimplementedMapsServer() +} + +// UnimplementedMapsServer 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 UnimplementedMapsServer struct{} + +func (UnimplementedMapsServer) Geocode(context.Context, *GeocodeRequest) (*GeocodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Geocode not implemented") +} +func (UnimplementedMapsServer) SearchPlaces(context.Context, *SearchPlacesRequest) (*SearchPlacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchPlaces not implemented") +} +func (UnimplementedMapsServer) GetPlaceDetails(context.Context, *PlaceDetailsRequest) (*PlaceDetailsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPlaceDetails not implemented") +} +func (UnimplementedMapsServer) GetDirections(context.Context, *DirectionsRequest) (*DirectionsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDirections not implemented") +} +func (UnimplementedMapsServer) GetDistanceMatrix(context.Context, *DistanceMatrixRequest) (*DistanceMatrixResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDistanceMatrix not implemented") +} +func (UnimplementedMapsServer) mustEmbedUnimplementedMapsServer() {} +func (UnimplementedMapsServer) testEmbeddedByValue() {} + +// UnsafeMapsServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MapsServer will +// result in compilation errors. +type UnsafeMapsServer interface { + mustEmbedUnimplementedMapsServer() +} + +func RegisterMapsServer(s grpc.ServiceRegistrar, srv MapsServer) { + // If the following call pancis, it indicates UnimplementedMapsServer 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(&Maps_ServiceDesc, srv) +} + +func _Maps_Geocode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeocodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).Geocode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Maps_Geocode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).Geocode(ctx, req.(*GeocodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_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.(MapsServer).SearchPlaces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Maps_SearchPlaces_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).SearchPlaces(ctx, req.(*SearchPlacesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_GetPlaceDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PlaceDetailsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).GetPlaceDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Maps_GetPlaceDetails_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).GetPlaceDetails(ctx, req.(*PlaceDetailsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_GetDirections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DirectionsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).GetDirections(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Maps_GetDirections_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).GetDirections(ctx, req.(*DirectionsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_GetDistanceMatrix_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DistanceMatrixRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).GetDistanceMatrix(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Maps_GetDistanceMatrix_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).GetDistanceMatrix(ctx, req.(*DistanceMatrixRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Maps_ServiceDesc is the grpc.ServiceDesc for Maps service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Maps_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "maps_proto.Maps", + HandlerType: (*MapsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Geocode", + Handler: _Maps_Geocode_Handler, + }, + { + MethodName: "SearchPlaces", + Handler: _Maps_SearchPlaces_Handler, + }, + { + MethodName: "GetPlaceDetails", + Handler: _Maps_GetPlaceDetails_Handler, + }, + { + MethodName: "GetDirections", + Handler: _Maps_GetDirections_Handler, + }, + { + MethodName: "GetDistanceMatrix", + Handler: _Maps_GetDistanceMatrix_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "maps.proto", +} diff --git a/api-service/main.go b/api-service/main.go new file mode 100644 index 0000000..0cb8ac9 --- /dev/null +++ b/api-service/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "api-service/config" + grpchandler "api-service/grpc" // Alias for your gRPC server package + + // pb "api-service/grpc/pb" // Old import - REMOVE + pb_common "api-service/grpc/pb/common" // New + pb_gemini "api-service/grpc/pb/gemini" // New + pb_maps "api-service/grpc/pb/maps" // New + "api-service/routes" + "log" + "net" + + // "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + "google.golang.org/grpc" +) + +func main() { + config.LoadEnv() + port := config.GetEnv("PORT", "8000") + + // Start gRPC server in a goroutine + go func() { + lis, err := net.Listen("tcp", ":50051") // gRPC server port + if err != nil { + log.Fatalf("failed to listen for gRPC: %v", err) + } + s := grpc.NewServer() + // Register all new services + pb_common.RegisterExampleGreeterServer(s, &grpchandler.ExampleGreeterServerImpl{}) // Updated + pb_maps.RegisterMapsServer(s, &grpchandler.MapsServerImpl{}) // Updated + pb_gemini.RegisterGeminiServer(s, &grpchandler.GeminiServerImpl{}) // Updated + log.Printf("gRPC server listening at %v", lis.Addr()) + if err := s.Serve(lis); err != nil { + log.Fatalf("failed to serve gRPC: %v", err) + } + }() + + r := gin.Default() + + // // CORS Middleware Configuration + // configCors := cors.DefaultConfig() + // configCors.AllowAllOrigins = true + // configCors.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"} + // configCors.AllowHeaders = []string{"Origin", "Content-Type", "Accept", "Authorization"} + // configCors.ExposeHeaders = []string{"Content-Length"} + // configCors.AllowCredentials = true + + // r.Use(cors.New(configCors)) + routes.RegisterRoutes(r) + + log.Printf("HTTP server listening on port %s", port) + r.Run(":" + port) +} diff --git a/api-service/models/geocode_model.go b/api-service/models/geocode_model.go new file mode 100644 index 0000000..fbad719 --- /dev/null +++ b/api-service/models/geocode_model.go @@ -0,0 +1,14 @@ +package models + +type GeocodeResponse struct { + Results []struct { + FormattedAddress string `json:"formatted_address"` + Geometry struct { + Location struct { + Lat float64 `json:"lat"` + Lng float64 `json:"lng"` + } `json:"location"` + } `json:"geometry"` + } `json:"results"` + Status string `json:"status"` +} diff --git a/api-service/models/places_model.go b/api-service/models/places_model.go new file mode 100644 index 0000000..f8b4dc6 --- /dev/null +++ b/api-service/models/places_model.go @@ -0,0 +1,110 @@ +package models + +type PlacesResponse struct { + Results []struct { + Name string `json:"name"` + Address string `json:"vicinity"` + Rating float64 `json:"rating,omitempty"` + UserRatingsTotal int `json:"user_ratings_total,omitempty"` + PlaceID string `json:"place_id"` + Types []string `json:"types,omitempty"` + Geometry struct { + Location struct { + Lat float64 `json:"lat"` + Lng float64 `json:"lng"` + } `json:"location"` + } `json:"geometry"` + OpeningHours struct { + OpenNow bool `json:"open_now,omitempty"` + } `json:"opening_hours,omitempty"` + Photos []struct { + PhotoReference string `json:"photo_reference"` + Height int `json:"height"` + Width int `json:"width"` + } `json:"photos,omitempty"` + PhotoURLs []string `json:"photo_urls,omitempty"` + } `json:"results"` + Status string `json:"status"` +} + +// Geometry defines the geographic coordinates. +type Geometry struct { + Location struct { + Lat float64 `json:"lat"` + Lng float64 `json:"lng"` + } `json:"location"` +} + +// PlacePhoto defines the structure for individual photos as returned by Google, +// which we use to build our full URLs. +type PlacePhoto struct { + PhotoReference string `json:"photo_reference"` + Height int `json:"height"` + Width int `json:"width"` + HTMLAttribution []string `json:"html_attributions,omitempty"` +} + +// PlaceReview defines the structure for user reviews. +type PlaceReview struct { + AuthorName string `json:"author_name"` + AuthorURL string `json:"author_url,omitempty"` + Language string `json:"language,omitempty"` + ProfilePhotoURL string `json:"profile_photo_url,omitempty"` + Rating int `json:"rating"` // Usually 1-5 + RelativeTimeDescription string `json:"relative_time_description"` + Text string `json:"text"` + Time int64 `json:"time"` // Unix timestamp +} + +// OpeningHoursPeriodDetail defines when a place opens or closes. +type OpeningHoursPeriodDetail struct { + Day int `json:"day"` // 0-6, Sunday to Saturday + Time string `json:"time"` // "HHMM" +} + +// OpeningHoursPeriod defines a period when a place is open. +type OpeningHoursPeriod struct { + Open OpeningHoursPeriodDetail `json:"open"` + Close OpeningHoursPeriodDetail `json:"close,omitempty"` // Close might not be present if open 24 hours +} + +// PlaceOpeningHours defines the opening hours structure. +type PlaceOpeningHours struct { + OpenNow bool `json:"open_now,omitempty"` + Periods []OpeningHoursPeriod `json:"periods,omitempty"` + WeekdayText []string `json:"weekday_text,omitempty"` // e.g., "Monday: 9:00 AM โ€“ 5:00 PM" + PermanentlyClosed bool `json:"permanently_closed,omitempty"` +} + +// PlaceDetailResult contains the detailed information for a single place. +type PlaceDetailResult struct { + Name string `json:"name,omitempty"` + FormattedAddress string `json:"formatted_address,omitempty"` + PlaceID string `json:"place_id"` + Types []string `json:"types,omitempty"` + Geometry Geometry `json:"geometry,omitempty"` + Rating float64 `json:"rating,omitempty"` + UserRatingsTotal int `json:"user_ratings_total,omitempty"` + Photos []PlacePhoto `json:"photos,omitempty"` // Original photos from Google + PhotoURLs []string `json:"photo_urls,omitempty"` // Our constructed URLs + Reviews []PlaceReview `json:"reviews,omitempty"` + Website string `json:"website,omitempty"` + InternationalPhoneNumber string `json:"international_phone_number,omitempty"` + FormattedPhoneNumber string `json:"formatted_phone_number,omitempty"` + OpeningHours *PlaceOpeningHours `json:"opening_hours,omitempty"` // Pointer as it can be null + Vicinity string `json:"vicinity,omitempty"` + UTCOffset int `json:"utc_offset,omitempty"` // UTC offset in minutes + AddressComponents []struct { + LongName string `json:"long_name"` + ShortName string `json:"short_name"` + Types []string `json:"types"` + } `json:"address_components,omitempty"` +} + +// PlaceDetailResponse wraps the place detail result and status. +type PlaceDetailResponse struct { + Result PlaceDetailResult `json:"result"` + Status string `json:"status"` // e.g., "OK", "NOT_FOUND" + HTMLAttributions []string `json:"html_attributions,omitempty"` + ErrorMessage string `json:"error_message,omitempty"` // For status codes other than OK +} diff --git a/api-service/routes/routes.go b/api-service/routes/routes.go new file mode 100644 index 0000000..7988718 --- /dev/null +++ b/api-service/routes/routes.go @@ -0,0 +1,43 @@ +package routes + +import ( + "api-service/controllers" + + "github.com/gin-gonic/gin" +) + +func RegisterRoutes(r *gin.Engine) { + + maps := r.Group("/maps") + { + // Example: GET /maps/geocode?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA + maps.GET("/geocode", controllers.GeocodeController) + // Example: GET /maps/places?query=restaurant&location=37.4224764,-122.0842499 + maps.GET("/places", controllers.LocationDataController) + // New route for place details by ID: + // Example: GET /maps/place/ChIJN1t_tDeuEmsRUsoyG83frY4 + maps.GET("/place/:place_id", controllers.PlaceDetailsController) + // Example: GET /maps/directions?origin=Toronto&destination=Montreal + maps.GET("/directions", controllers.DirectionsController) + // Example: GET /maps/distance-matrix?origins=Seattle&destinations=San+Francisco + maps.GET("/distance-matrix", controllers.DistanceMatrixController) + } + gemini := r.Group("/gemini") + { + // Example: GET /gemini?prompt=explain+about+life+100+words + gemini.GET("/", controllers.GeminiController) + } + + test := r.Group("/test") + { + test.GET("/", func(c *gin.Context) { + c.String(200, "hello world") + }) + } + + r.GET("/healthz", func(c *gin.Context) { + c.JSON(200, gin.H{ + "status": "ok", + }) + }) +} diff --git a/api-service/services/gemini/gemini.go b/api-service/services/gemini/gemini.go new file mode 100644 index 0000000..df86d77 --- /dev/null +++ b/api-service/services/gemini/gemini.go @@ -0,0 +1,44 @@ +package gemini + +import ( + "api-service/config" + "context" + "net/http" + "time" + + "google.golang.org/genai" +) + +type AIService struct { + client *http.Client + apiKey string +} + +func NewAIService(apiKey string) *AIService { + return &AIService{ + client: &http.Client{Timeout: 10 * time.Second}, + apiKey: apiKey, + } +} + +func (ais *AIService) GetAIResponse(prompt string) (interface{}, error) { + ctx := context.Background() + client, err := genai.NewClient(ctx, &genai.ClientConfig{ + APIKey: config.GetEnv("GOOGLE_GEMINI_API_KEY", ""), + Backend: genai.BackendGeminiAPI, + }) + if err != nil { + return nil, err + } + resp, err := client.Models.GenerateContent( + ctx, + "gemini-2.0-flash", + genai.Text(prompt), + nil, + ) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/api-service/services/maps/directions_service.go b/api-service/services/maps/directions_service.go new file mode 100644 index 0000000..585e411 --- /dev/null +++ b/api-service/services/maps/directions_service.go @@ -0,0 +1,40 @@ +package maps + +import ( + "api-service/config" + "encoding/json" + "fmt" + "net/http" + "time" +) + +type DirectionsService struct { + client *http.Client +} + +func NewDirectionsService() *DirectionsService { + return &DirectionsService{ + client: &http.Client{Timeout: 10 * time.Second}, + } +} + +func (ds *DirectionsService) GetDirections(origin, destination string) (interface{}, error) { + url := fmt.Sprintf("https://maps.googleapis.com/maps/api/directions/json?origin=%s&destination=%s&key=%s", origin, destination, config.GetEnv("GOOGLE_MAPS_API_KEY", "")) + + resp, err := ds.client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to get directions: %s", resp.Status) + } + + var result interface{} + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return nil, err + } + + return result, nil +} diff --git a/api-service/services/maps/distance_matrix_service.go b/api-service/services/maps/distance_matrix_service.go new file mode 100644 index 0000000..484b2b5 --- /dev/null +++ b/api-service/services/maps/distance_matrix_service.go @@ -0,0 +1,60 @@ +package maps + +import ( + "api-service/config" + "encoding/json" + "fmt" + "net/http" + "time" +) + +type DistanceMatrixService struct { + client *http.Client +} + +type DistanceMatrixResponse struct { + Rows []DistanceMatrixRow `json:"rows"` +} + +type DistanceMatrixRow struct { + Elements []DistanceMatrixElement `json:"elements"` +} + +type DistanceMatrixElement struct { + Status string `json:"status"` + Duration struct { + Text string `json:"text"` + Value int `json:"value"` + } `json:"duration"` + Distance struct { + Text string `json:"text"` + Value int `json:"value"` + } `json:"distance"` +} + +func NewDistanceMatrixService() *DistanceMatrixService { + return &DistanceMatrixService{ + client: &http.Client{Timeout: 10 * time.Second}, + } +} + +func (d *DistanceMatrixService) GetDistanceMatrix(origins, destinations string) (*DistanceMatrixResponse, error) { + url := fmt.Sprintf("https://maps.googleapis.com/maps/api/distancematrix/json?origins=%s&destinations=%s&key=%s", origins, destinations, config.GetEnv("GOOGLE_MAPS_API_KEY", "")) + + resp, err := d.client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to get distance matrix: %s", resp.Status) + } + + var distanceMatrixResponse DistanceMatrixResponse + if err := json.NewDecoder(resp.Body).Decode(&distanceMatrixResponse); err != nil { + return nil, err + } + + return &distanceMatrixResponse, nil +} diff --git a/api-service/services/maps/geocode_service.go b/api-service/services/maps/geocode_service.go new file mode 100644 index 0000000..06a71c8 --- /dev/null +++ b/api-service/services/maps/geocode_service.go @@ -0,0 +1,37 @@ +package maps + +import ( + "api-service/config" + "encoding/json" + "fmt" + "net/http" +) + +type GeocodeService struct { + apiKey string +} + +func NewGeocodeService() *GeocodeService { + return &GeocodeService{apiKey: ""} +} + +func (g *GeocodeService) Geocode(address string) (map[string]interface{}, error) { + url := fmt.Sprintf("https://maps.googleapis.com/maps/api/geocode/json?address=%s&key=%s", address, config.GetEnv("GOOGLE_MAPS_API_KEY", "")) + + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to get geocode: %s", resp.Status) + } + + var result map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return nil, err + } + + return result, nil +} diff --git a/api-service/services/maps/maps_client.go b/api-service/services/maps/maps_client.go new file mode 100644 index 0000000..2bfdd92 --- /dev/null +++ b/api-service/services/maps/maps_client.go @@ -0,0 +1,40 @@ +package maps + +import ( + "net/http" + "time" +) + +type MapsClient struct { + httpClient *http.Client + apiKey string +} + +func NewMapsClient() *MapsClient { + return &MapsClient{ + httpClient: &http.Client{ + Timeout: 10 * time.Second, + }, + apiKey: "", + } +} + +func (client *MapsClient) GetGeocode(address string) (string, error) { + // Implementation for geocoding + return "", nil +} + +func (client *MapsClient) GetPlaces(location string) (string, error) { + // Implementation for places + return "", nil +} + +func (client *MapsClient) GetDirections(origin, destination string) (string, error) { + // Implementation for directions + return "", nil +} + +func (client *MapsClient) GetDistanceMatrix(origins, destinations string) (string, error) { + // Implementation for distance matrix + return "", nil +} diff --git a/api-service/services/maps/places_service.go b/api-service/services/maps/places_service.go new file mode 100644 index 0000000..580367a --- /dev/null +++ b/api-service/services/maps/places_service.go @@ -0,0 +1,140 @@ +package maps + +import ( + "api-service/config" + "api-service/models" + "encoding/json" + "fmt" + "net/http" + "time" +) + +type PlacesService struct { + client *http.Client + apiKey string +} + +func NewPlacesService() *PlacesService { + return &PlacesService{ + client: &http.Client{Timeout: 10 * time.Second}, + apiKey: "", + } +} + +func (s *PlacesService) FindPlaceByID(placeID string) (*models.PlaceDetailResponse, error) { + var response models.PlaceDetailResponse // Initialize response struct + + fields := "name,rating,formatted_phone_number,photo,review,website,opening_hours,geometry,place_id,type,vicinity,address_component,utc_offset,user_ratings_total,formatted_address,international_phone_number" + url := fmt.Sprintf("https://maps.googleapis.com/maps/api/place/details/json?place_id=%s&fields=%s&key=%s", placeID, fields, config.GetEnv("GOOGLE_MAPS_API_KEY", "")) + + resp, err := s.client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + decodeErr := json.NewDecoder(resp.Body).Decode(&response) + + if resp.StatusCode != http.StatusOK { + if decodeErr != nil { + return nil, fmt.Errorf("failed to get place details: status %s. Additionally, failed to decode error response body: %v", resp.Status, decodeErr) + } + // Use response.Status and response.ErrorMessage from the decoded Google error response + return &response, fmt.Errorf("failed to get place details: Google API status %s, message: %s", response.Status, response.ErrorMessage) + } + + if decodeErr != nil { + return nil, fmt.Errorf("failed to decode successful place details response: %v", decodeErr) + } + + // Populate PhotoURLs if Photos exist and status is OK + if response.Status == "OK" { + if response.Result.Photos != nil && len(response.Result.Photos) > 0 { + response.Result.PhotoURLs = []string{} // Initialize PhotoURLs + apiKey := config.GetEnv("GOOGLE_MAPS_API_KEY", "") + for _, photo := range response.Result.Photos { + if photo.PhotoReference != "" { + photoURL := fmt.Sprintf("https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=%s&key=%s", photo.PhotoReference, apiKey) + response.Result.PhotoURLs = append(response.Result.PhotoURLs, photoURL) + } + } + } + } + + return &response, nil +} + +func (s *PlacesService) NearbySearch(location string, radius int) (*models.PlacesResponse, error) { + url := fmt.Sprintf("https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=%s&radius=%d&key=%s", location, radius, config.GetEnv("GOOGLE_MAPS_API_KEY", "")) + resp, err := s.client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to search nearby places: %s", resp.Status) + } + + var response models.PlacesResponse + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { + return nil, err + } + + apiKey := config.GetEnv("GOOGLE_MAPS_API_KEY", "") + for i := range response.Results { + response.Results[i].PhotoURLs = []string{} // Initialize + if response.Results[i].Photos != nil { + for _, photo := range response.Results[i].Photos { + if photo.PhotoReference != "" { + photoURL := fmt.Sprintf("https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=%s&key=%s", photo.PhotoReference, apiKey) + response.Results[i].PhotoURLs = append(response.Results[i].PhotoURLs, photoURL) + } + } + } + } + return &response, nil +} + +func (s *PlacesService) TextSearch(query string) (*models.PlacesResponse, error) { + url := fmt.Sprintf("https://maps.googleapis.com/maps/api/place/textsearch/json?query=%s&key=%s", query, config.GetEnv("GOOGLE_MAPS_API_KEY", "")) + resp, err := s.client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to search places: %s", resp.Status) + } + + var response models.PlacesResponse + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { + return nil, err + } + + apiKey := config.GetEnv("GOOGLE_MAPS_API_KEY", "") + for i := range response.Results { + response.Results[i].PhotoURLs = []string{} // Initialize + if response.Results[i].Photos != nil { + for _, photo := range response.Results[i].Photos { + if photo.PhotoReference != "" { + photoURL := fmt.Sprintf("https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=%s&key=%s", photo.PhotoReference, apiKey) + response.Results[i].PhotoURLs = append(response.Results[i].PhotoURLs, photoURL) + } + } + } + } + return &response, nil +} + +// SearchPlaces combines text and nearby search based on provided parameters +func (s *PlacesService) SearchPlaces(query, location string) (*models.PlacesResponse, error) { + if query != "" { + return s.TextSearch(query) + } else if location != "" { + // Default radius for nearby search (in meters) + return s.NearbySearch(location, 1000) + } + return nil, fmt.Errorf("either query or location must be provided") +} diff --git a/auth-service/Dockerfile.keycloak b/auth-service/Dockerfile.keycloak new file mode 100644 index 0000000..6ca824c --- /dev/null +++ b/auth-service/Dockerfile.keycloak @@ -0,0 +1,9 @@ +FROM quay.io/keycloak/keycloak:24.0 + +USER root +RUN mkdir -p /opt/keycloak-scripts +COPY keycloak-setup.sh /opt/keycloak-scripts/keycloak-setup.sh +RUN chmod +x /opt/keycloak-scripts/keycloak-setup.sh + +USER keycloak +ENTRYPOINT ["/opt/keycloak-scripts/keycloak-setup.sh"] \ No newline at end of file diff --git a/auth-service/README.txt b/auth-service/README.txt new file mode 100644 index 0000000..bde55ff --- /dev/null +++ b/auth-service/README.txt @@ -0,0 +1,7 @@ +1. Run the scripts in sequence +2. Use user with administrator access (Windows) or root access (Mac / Linux) +3. You don't have to use "root" for Mac / Linux, user with "sudo" access will do + In such case, you need to add "sudo" for each scripts + Example: + + $> sudo docker network create --subnet=172.1.1.0/24 kong-net \ No newline at end of file diff --git a/auth-service/docker-compose.yml b/auth-service/docker-compose.yml new file mode 100644 index 0000000..899427f --- /dev/null +++ b/auth-service/docker-compose.yml @@ -0,0 +1,172 @@ +version: "3" + +x-kong-config: &kong-env + KONG_DATABASE: ${KONG_DATABASE:-postgres} + KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong} + KONG_PG_HOST: kong-database + KONG_PG_USER: ${KONG_PG_USER:-kong} + KONG_PG_PASSWORD: mykongpassword + +volumes: + keycloak_db: {} + kong_data: {} + kong_prefix_vol: + driver_opts: + type: tmpfs + device: tmpfs + kong_tmp_vol: + driver_opts: + type: tmpfs + device: tmpfs + +networks: + kong-net: + external: false + ipam: + config: + - subnet: 172.1.1.0/24 + +services: + ################################################ + # Keycloak # + ################################################ + # keycloak-db: + # image: postgres:16-alpine + # environment: + # POSTGRES_DB: keycloak + # POSTGRES_USER: keycloak + # POSTGRES_PASSWORD: mykeycloakpassword + # volumes: + # - keycloak_db:/var/lib/postgresql/data + # networks: + # - kong-net + # healthcheck: + # test: ["CMD", "pg_isready", "-d", "keycloak", "-U", "keycloak"] + # interval: 30s + # timeout: 10s + # retries: 5 + # restart: unless-stopped + + keycloak: + build: + context: . + dockerfile: Dockerfile.keycloak + command: + - start-dev + - --http-enabled=true + - --hostname-strict=false + - --hostname-strict-https=false + # - import + # - --import-realm + # - --import-path=/opt/keycloak/data/import + environment: + KC_DB: postgres + KC_DB_URL: "jdbc:postgresql://aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres?sslmode=require&connectTimeout=10" + KC_DB_USERNAME: postgres.ucutsnncgapnsylikrxk + KC_DB_PASSWORD: Postgres@2025 + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + KC_HOSTNAME_URL: http://localhost:8081 + KEYCLOAK_IMPORT: /opt/keycloak/data/import/kong-realm.json + volumes: + - ./keycloak-import:/opt/keycloak/data/import + networks: + - kong-net + ports: + - "8445:8443" + - "8081:8080" + # depends_on: + # keycloak-db: + # condition: service_healthy + restart: unless-stopped + ################################################ + # Kong components (Kong & PostgreSQL Database) # + ################################################ + + # kong-migrations: + # image: custom/kong-oidc:latest + # # image: kong:3.5 + # command: kong migrations bootstrap + # environment: + # <<: *kong-env + # networks: + # - kong-net + # restart: on-failure + # depends_on: + # - kong-database + + # kong-migrations-up: + # image: kong:3.5 + # command: kong migrations up && kong migrations finish + # environment: + # <<: *kong-env + # networks: + # - kong-net + # restart: on-failure + # depends_on: + # - kong-database + + # kong: + # image: custom/kong-oidc:latest + # # image: kong:3.5 + # user: "${KONG_USER:-kong}" + # environment: + # <<: *kong-env + # KONG_ADMIN_ACCESS_LOG: /dev/stdout + # KONG_ADMIN_ERROR_LOG: /dev/stderr + # KONG_PROXY_LISTEN: "${KONG_PROXY_LISTEN:-0.0.0.0:8000, 0.0.0.0:8443 ssl}" + # KONG_ADMIN_LISTEN: "${KONG_ADMIN_LISTEN:-0.0.0.0:8001}" + # KONG_ADMIN_GUI_LISTEN: "${KONG_ADMIN_GUI_LISTEN:-0.0.0.0:8002}" + # KONG_PROXY_ACCESS_LOG: /dev/stdout + # KONG_PROXY_ERROR_LOG: /dev/stderr + # KONG_PREFIX: ${KONG_PREFIX:-/var/run/kong} + # KONG_TRACING_INSTRUMENTATIONS: "request" + # KONG_CONF: /etc/kong/kong.conf + + # networks: + # - kong-net + # ports: + # - "${KONG_INBOUND_PROXY_LISTEN:-0.0.0.0}:8000:8000/tcp" + # - "${KONG_INBOUND_SSL_PROXY_LISTEN:-0.0.0.0}:8443:8443/tcp" + # - "127.0.0.1:8001:8001/tcp" + # - "127.0.0.1:8444:8444/tcp" + # - "127.0.0.1:8002:8002/tcp" + # healthcheck: + # test: [ "CMD", "kong", "health" ] + # interval: 10s + # timeout: 10s + # retries: 10 + # restart: on-failure:5 + # read_only: true + # volumes: + # - kong_prefix_vol:${KONG_PREFIX:-/var/run/kong} + # - kong_tmp_vol:/tmp + # security_opt: + # - no-new-privileges + + # kong-database: + # image: postgres:16-alpine + # environment: + # POSTGRES_DB: ${KONG_PG_DATABASE:-kong} + # POSTGRES_USER: ${KONG_PG_USER:-kong} + # POSTGRES_PASSWORD: ${KONG_PG_PASSWORD:-mykongpassword} + # healthcheck: + # test: + # [ + # "CMD", + # "pg_isready", + # "-d", + # "${KONG_PG_DATABASE:-kong}", + # "-U", + # "${KONG_PG_USER:-kong}" + # ] + # interval: 30s + # timeout: 10s + # retries: 3 + # restart: unless-stopped + # stdin_open: true + # tty: true + # networks: + # - kong-net + # volumes: + # - kong_data:/var/lib/postgresql/data diff --git a/auth-service/keycloak-import/kong-realm.json b/auth-service/keycloak-import/kong-realm.json new file mode 100644 index 0000000..0d5d5eb --- /dev/null +++ b/auth-service/keycloak-import/kong-realm.json @@ -0,0 +1,1829 @@ +{ + "id" : "fe536a4f-9764-4b29-8287-745c18fc3778", + "realm" : "kong", + "notBefore" : 0, + "defaultSignatureAlgorithm" : "RS256", + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 0, + "accessTokenLifespan" : 300, + "accessTokenLifespanForImplicitFlow" : 900, + "ssoSessionIdleTimeout" : 1800, + "ssoSessionMaxLifespan" : 36000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 300, + "oauth2DeviceCodeLifespan" : 600, + "oauth2DevicePollingInterval" : 5, + "enabled" : true, + "sslRequired" : "none", + "registrationAllowed" : true, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : true, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxTemporaryLockouts" : 0, + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ { + "id" : "c231543d-fad6-4b0f-b5bf-54a7cedec760", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "fe536a4f-9764-4b29-8287-745c18fc3778", + "attributes" : { } + }, { + "id" : "2ab764ec-2fd7-4735-b893-1457f516ee0f", + "name" : "default-roles-kong", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "manage-account", "view-profile" ] + } + }, + "clientRole" : false, + "containerId" : "fe536a4f-9764-4b29-8287-745c18fc3778", + "attributes" : { } + }, { + "id" : "0a9574a4-bf6f-4f86-9624-70b942531c95", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "fe536a4f-9764-4b29-8287-745c18fc3778", + "attributes" : { } + } ], + "client" : { + "kong-oidc" : [ ], + "realm-management" : [ { + "id" : "2b007fc7-8646-4771-987c-d00758d284ae", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "f12d45a0-25a6-4aaf-adf5-8d99cf6ecf6a", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-groups", "query-users" ] + } + }, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "1e454f0c-3aca-47b4-9711-16468c2d44b6", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "aa380d16-4b3d-49a6-9d84-4d9b6a4bef0b", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "f1249a1a-9aa4-4734-9fc9-985c4e302ec8", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "1864f5ac-8a66-4496-8943-366d1bfe1793", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "30142c4b-abd8-423c-88a5-db28f00501de", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "3fdac547-1ea5-40c6-98bf-16e35a6c7f2f", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "ea1c291d-b10b-4511-b1bf-4b9db1914d89", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "impersonation", "view-users", "view-realm", "view-clients", "manage-realm", "query-users", "view-identity-providers", "manage-clients", "view-authorization", "create-client", "query-clients", "manage-users", "query-realms", "query-groups", "view-events", "manage-authorization", "manage-events", "manage-identity-providers" ] + } + }, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "1dd2e6a2-2eb4-466f-b24d-d11d83a89f91", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "c9fff176-3b00-4558-8ba6-431ec153d052", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "956ab296-b320-47f3-ad43-bd60f984ec1d", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "0715a933-81ed-40f9-9638-9151de7139ee", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "fae9cd52-4608-4230-a153-173835bada00", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "520077eb-fa5d-4c6e-8b81-226a569b1120", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "ff45306b-6db9-44e7-bf2a-bdfa35687c5c", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "5bde37a8-834b-4a2c-9eda-9e53c4d568e9", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "dba1939f-8ba0-4856-88ee-8c0f9874d8e3", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + }, { + "id" : "ed5d1f83-4fb6-4ecf-9a17-ab5110bd5536", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes" : { } + } ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "dc185c95-4bbe-4c90-94a1-0b8dab908ab4", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "fe01a72d-ed99-44e3-9112-a0f2642da6c3", + "attributes" : { } + } ], + "account" : [ { + "id" : "ecc49be2-7f2a-4a46-add7-8910d7e073a7", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + }, { + "id" : "0e9c57c3-9253-42cf-9267-0eeb1a26ef3c", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + }, { + "id" : "c2ae61d5-8169-4f71-b6cb-1e43ccb11cd0", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + }, { + "id" : "87d3b78e-ca6b-4ca2-ab62-274f4357cf9c", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + }, { + "id" : "f8c61736-8b4a-4daf-9668-4e043e503d84", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + }, { + "id" : "45381f22-225d-4f4f-97e9-ab5cdbbcc7b5", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + }, { + "id" : "aa07dcc1-a077-4f83-9ba1-7f711df541fe", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + }, { + "id" : "96f12df8-83c2-432a-afe5-5ddf4b9bb3c8", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes" : { } + } ] + } + }, + "groups" : [ ], + "defaultRole" : { + "id" : "2ab764ec-2fd7-4735-b893-1457f516ee0f", + "name" : "default-roles-kong", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "fe536a4f-9764-4b29-8287-745c18fc3778" + }, + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpPolicyCodeReusable" : false, + "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], + "localizationTexts" : { }, + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyExtraOrigins" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessExtraOrigins" : [ ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account", "view-groups" ] + } ] + }, + "clients" : [ { + "id" : "722377fa-d1b4-4e3b-b0be-555f50b01153", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/kong/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/kong/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "e16a7dc2-5708-4643-b1a1-5bb39d2c5974", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/kong/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/kong/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "42b765a3-3ba8-4d53-a3dc-d9a5364eea38", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "b9729e4d-28d7-4cf9-acb3-6247c1f676d0", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "fe01a72d-ed99-44e3-9112-a0f2642da6c3", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "4c18c3dc-25fe-4926-9163-4a0ad55e72c6", + "clientId" : "kong-oidc", + "name" : "kong-oidc", + "description" : "", + "rootUrl" : "http://localhost:3000", + "adminUrl" : "http://localhost:3000", + "baseUrl" : "http://localhost:3000/*", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "fBHJFdikM0ERtTXnvebguHRz6iPUfJfV", + "redirectUris" : [ "http://localhost:3000/login" ], + "webOrigins" : [ "http://localhost:3000" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "oidc.ciba.grant.enabled" : "false", + "client.secret.creation.time" : "1743921958", + "backchannel.logout.session.required" : "true", + "backchannel.logout.url" : "http://localhost:3000/login", + "login_theme" : "keycloak", + "frontchannel.logout.url" : "http://localhost:3000/login", + "post.logout.redirect.uris" : "http://localhost:3000/login", + "display.on.consent.screen" : "false", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "0525d0e7-187f-49bb-8eff-b36b9667b991", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/kong/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/kong/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "6e0a00e4-1412-4627-9754-cb8b001d54c9", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + } ], + "clientScopes" : [ { + "id" : "e987e875-9d89-4a26-96b6-41303eb481c8", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "28be87f7-c996-4f88-97aa-5bd40274f4f7", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + }, { + "id" : "19bb0b29-8341-42be-9051-df8089439bf3", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${phoneScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "7c614f88-1631-4169-8f17-323d50c51cba", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + }, { + "id" : "efad8e19-1dae-42cd-aa9f-1955310fbe5d", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "4f412537-57d6-4d7d-8d68-e4442a265068", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "20cafdb3-b497-429c-8d27-9eaae409f44e", + "name" : "acr", + "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "a195ac65-96e4-471f-b29e-19ec218c6feb", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + }, { + "id" : "7fe201c5-3ac5-49ce-92f3-99eaa07f266d", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "e5796d6d-921d-4bfb-a786-410d8311a651", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + }, { + "id" : "ca33a7fb-6c2e-4da2-9e79-30ec7b48c300", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "multivalued" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "73cbda9d-42ad-49f6-8d4e-dc95b333a619", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${addressScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "d8060a09-3b67-477b-a704-f9deb82b0bc4", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "introspection.token.claim" : "true", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "47a2f9af-b1e4-4b03-981b-0ae9da9bcc86", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${profileScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "4516baaf-cd97-4a28-8c5d-17a35e590293", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + }, { + "id" : "68cdc4b0-3b8a-4c9d-ba2e-dcc334a69c80", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "227fe568-c468-4019-913e-68d18a4e8a19", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "ed2ba3eb-b005-401d-91ac-f4102d4bb979", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "305c66e4-6531-4e6f-8986-8cd81e08bf46", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "f5393ba4-37a3-4673-ad40-66eb2b2e0428", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + }, { + "id" : "1370c80f-feef-418b-806d-1dec97e73aa2", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "71945b38-17a4-4a3c-b416-e7701e1af2cd", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + }, { + "id" : "fdf50c0d-1767-4427-8706-72b79cf51756", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + }, { + "id" : "cc945235-670d-4a12-a429-6e0c6d51cd71", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "f8bd340d-febb-407d-8c93-578aa4055146", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "long" + } + }, { + "id" : "965b8107-e85a-4325-a24c-512ecad9bcb6", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + }, { + "id" : "02a6cca1-ed04-4828-a2aa-0bc9cef1b4b6", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + }, { + "id" : "ec5a3595-9a6e-4fb0-baee-aba406920c1c", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "88c16e80-5038-4219-a3f0-f8e5d11b2d85", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "03da4fe1-64b5-4db4-ab72-0bc855e09871", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "dd63b2bf-5850-4ebf-be19-e194e5ec334f", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${rolesScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "6d56a241-aa41-441c-a867-595443294557", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "multivalued" : "true", + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String" + } + }, { + "id" : "54fc6e1c-34fe-4aa3-88eb-46ffdeb70fe5", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "multivalued" : "true", + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String" + } + }, { + "id" : "1dd52096-01d5-42cf-940a-78bc527a5100", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + }, { + "id" : "9e8a5630-ab90-4d20-a702-b1a083e1aab8", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${emailScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "097d9f32-aa95-4ca7-9e59-551a648cb2f3", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + }, { + "id" : "245835c6-d274-46a6-af28-578e99de654a", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins", "acr" ], + "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "referrerPolicy" : "no-referrer", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "12fc9eb4-d127-412e-9d49-299ff633bceb", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "bf81b717-215b-4f49-9720-9c5f68ddff5b", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "6f6de768-29b4-4711-85f8-7072621bc7dd", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper" ] + } + }, { + "id" : "29c345fd-1a15-4886-ba50-9ab389d4d66a", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + }, { + "id" : "a6bd777b-7176-4c86-98b0-cee4d9b280e6", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "6c264b28-83f4-4e6d-b7b6-872c8515c8b3", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "c364f868-4588-4d65-80b1-3afb35c4e12f", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "43f44171-bc8c-4d45-9d4b-2ba798f209a3", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "77471f51-2188-4945-98bd-2457efc0cc9b", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "4fe64883-c3f1-4c4d-845b-105ffd64410e" ], + "secret" : [ "OlBabWbo9PnkTN-ptWWc6g" ], + "priority" : [ "100" ] + } + }, { + "id" : "f1965169-0444-4599-980a-e71cfbc6a792", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEowIBAAKCAQEAxyObP/3+5ywz5w+nh01Ydr2SWwzdlcRrstPAzOFr4I5nyR+J5Ev0GX2BkmoH6xwKcyceroHwlwTy/LBglZrVHEopYoELY9I4wfEXl91bpzNP1gxS4QAUx/kT9nJul4ioAsGINGnFxi7xtpCBO4mIanX81RJ103qeSqfw/Jkyz312j3YHt0K0axaQZxO/nG7WVD+XzktKeVklngZydx6m5bDyzOqNbfBcjIKiSTfBxFUM+XFBheeqeYuaszGGz3+BwbTNInL5J5O9Q/yhD1PtriXja+kUNru1fPufU1S+aSs72MdYKbWKOz2wdBm3WnFyh107bltMFXnbCIlDqIQK9QIDAQABAoIBACHvgS4tSmJaP8kNO6MczOnFQfrmrR8v3xuVJtqzQoc8tVaKm5zOTb2HTAynqYxJFcXMYZfi+F1AAGmL5BWykkUVJUrOS2LaKQZx36+nTw5l+eGz7W6+7Qur+Fkr5IlJxjncAapO6R9uEg5mv0MmW5sq2qhz0iT1FSMLTg+5yrUdcxuD51JJcZs5qq3mW0j29rHqbsDmnuhfvXMyAwueJ/POnjp8xUeACTofDNM+ldZ/NhDhqbFoGHYFiGiR3bS1OkCQoGC/64R/orQvUCAxM3b76311g4Smp2xtvDJF1XxcTRdIyEtGHW5QaHTO3h1JqNBFWrQ80y0U2cKzWcKiBQECgYEA546LPBJasXwrhADFgnq+ext706z26hRCmK5XjehlYN8JHeNaeeswdgni4wxHWpqERz8yOAZCjLGNDci75BHfRzxZf2uVonF309LB8c2ojclNMMO2dB8K4FPDtMfffJYDLagZ67YzXxoY3ZhgcnqX1P3W7bLnaSHNjQJ5Xh4hqQECgYEA3CkGX+IFpX+zEa6A9hJGF2jOenTiNLGn8xiN36qZH6e7xHOsoY2M14hjZ+AFRBW6mAHZhlelHo7SK0nGXejdQQHE7hYHykN+siQc9AXUWCLjSdqnrX4S/rSZNkYGtwnTK5GRAQ9M/vRVtGJVCcEz3+jpQ8a0744ww45Bz3p4TfUCgYAXn4U45a52+PH/j4yW2SrhqFYjrDusedCpfu/TvGfLUDW/5NfwJDxXbn7FJxWIescP9bSL3qefbuWzCE2S4PfkbpW62CD155mP9KpwnsiZXnYPiYftpNUZObJ3mQSF01ATsliioX3wL9tlkAwW4cbnpdXtfhj5sscjoaL8JRrOAQKBgQDDqf5NVu4XwR9floxspZ7/jRj8wkaL+FxAc9EbOF4wQP1iwj9psQi8QS2/ktx7Pyh/kh1GBTztpJbq+/09VwjUjoL76j5wJ35BSlElGs02q4L/D0I4sbSmA9Gq559uK2Au94c8vuF6MaK91yqmqbu1wyUVJFOIGAIEuriIcdrbxQKBgA4/ljnSTGnid0Ob4bc18EvzNTZFqNcbnNJ+2UC8n8LwsD4EPS5ZzpRrTNMrfY3H44PPUpYPHLd4Ahq4SoVQ1rG4ZsJGbXRAH3/cLVfs1fVMuVp/nNXIYIGAiRaGwTgXkIK4ysTlhyMCf8vNcjXsguiGUBnVVPIVF4HbglfNdEym" ], + "keyUse" : [ "ENC" ], + "certificate" : [ "MIIClzCCAX8CBgGWCcd0NjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARrb25nMB4XDTI1MDQwNjA2MjQ0OFoXDTM1MDQwNjA2MjYyOFowDzENMAsGA1UEAwwEa29uZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcjmz/9/ucsM+cPp4dNWHa9klsM3ZXEa7LTwMzha+COZ8kfieRL9Bl9gZJqB+scCnMnHq6B8JcE8vywYJWa1RxKKWKBC2PSOMHxF5fdW6czT9YMUuEAFMf5E/ZybpeIqALBiDRpxcYu8baQgTuJiGp1/NUSddN6nkqn8PyZMs99do92B7dCtGsWkGcTv5xu1lQ/l85LSnlZJZ4GcncepuWw8szqjW3wXIyCokk3wcRVDPlxQYXnqnmLmrMxhs9/gcG0zSJy+SeTvUP8oQ9T7a4l42vpFDa7tXz7n1NUvmkrO9jHWCm1ijs9sHQZt1pxcoddO25bTBV52wiJQ6iECvUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAM++gZrKYt2V4vPQr55xta9NXtBGqtp6DBR6MmzaLW7tnZZMe1hULy1/J8ID9eH5zJs1zclV1rTQXBEvIbO3pA7jpj5W3RSa3rHhlpy1hA7KOWofpkHwo0zU/sfo49A77SswSw7Ob0ZCVr5GWhORQFWoq3+mHRvWFuoFOrfgWaQ6sbFv9w8p/JuYL/r+omPLRUwzH6F8ur4H8WpPbJrTJZuewNy0pJ01HqKWcfYmCuG2ZpAze6o3j3sJgq1ychDyDGBWv/zbdYBEpWgaauGRSax63Thu3rQ0/Iub0hB36KJV4njWsHpVmBWt6keSvo1GduNgM0aDqKxeu5CxWIVWsw==" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + }, { + "id" : "61600c4f-e031-44d4-8f06-b8e21f0f2aac", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEpAIBAAKCAQEAq0CDA+eNNBsKhxHj7x0W7KKGYsUdzMgtO7FzJ34kWtggtN9IGM4yY83+L8JqNfk9e2rM2g1BVOEY6VxhJlimOQT0oeUGaMQEL3jO3CQ8F34+SjfGX2cFfd7965wwj0B7PY6EddHRW4k8Mh6ZmcAW2n9kTHlVKkYaPX8QcXbTN4OBJ0AM6DSMdI8u/c+FMa8j4Tbq+J+Q0ucQKC15C2sIyISL/cF9Ixrbs0/ToONLZbcUulqGo0RY3SipPxPIqlayN6AEqRHY6eaUDDMrkEIn0oUAjNMzcumg2mUa0uQtJnd7E5GgsywiUYUPAUEMDlwzA/yW1G6So1uliBoKqh63GQIDAQABAoIBAEN+dgSEbrkCDViluu2DTAUwmwFziearYHR94BJJG3/4XY+bzrkED4UZa1ycZarnFA2/zoQEJGMVInHa2Gk6GC0x4E6sSqXg13t0RCcsWsixl1A+Aj+YhWgSCoahNNxIwCnHMTqUWsyWXnSsbcJUnE06VyfyzBeQsIfbO/pUKDPgyZ0xTvp3dW2E9E/1M6nTpiljo3ZMfO5CyEVvbORqOt4+3b+GLf2A6Dd8oOtobAxQFHx7umckoDI2IflALaZymQGu8/mD0p3Gl0K13gNXEe83VGwaAOBbrcbqUPGzueSz3d3cLRmKcXHvbiOQGXB0h38D30mffixPKvys5BcLol8CgYEA3n5lAfWIPs4f3GE5829fYNn2453xNhjHnUjgX7ztoMz0UzBHN/bKsEmMzJMQ77+6G3jvfJUMlWWJzg33V6EfASlY8trt+TG49xFw/9dnGY4dy72x0oBuSDk8lwjHWBsltqbvcFeYfozdInlCIATT5ormRvsKhERTbHRUrOxZABcCgYEAxQqjyVLRGDRZSrknKvrqfqpxsKRn2B7T8f2RX54snhuRsFUJvmyc3WTEpN0nkxG3VHtpPJBj+9VlhLVUSrabDSR1i9s8GbQh41DilT541WJgddtNUKZRravTodXAZ6QF2OI4D4tyd51/jNbTopNEmJ1tfMQ82D5Sa3oa0ooz0E8CgYEArN+WSdxl/S6ZENm2dlA90nno29h3d+nvB2V9eMXJ+NvmptBnNbOarzimnrlSOoZE612e7rS8r0PSu/icC0lUVsmypBe5OZsJtWam3xKVuAR1YD3G8eD6T0Gxs0SN5wZI2k+A0VAuW33FwChpWYmGv6WC4PnjpPuVujn1JNsLGAcCgYEAl8ieapM1JuQMdJc0KNOol3JMqbm7lKwKsDqYJYP+8rxh+edH3jxkidb589W4in33L0jxxAmmO3QjA5t7FyKbRgBz3AxBu7sa77R7FmRNSHLDw4XvhNTZzmKyX9P8ptme93croC3XO3VDsAY8eNvg139Nu/KevCUl8EzbJJv5VdkCgYBcdzNMO9+oBg6NIvKN/y3McYZe1s1nQKKf41EoGbXenmCrpe0kR2Mkh88jCJXmVMtFP54Q5tf/Fq/Bumvw60zRLFUd5VTlR0PNsasADup/zxP11+VgpXjlf3zidTgraH8hmb5BSlbMlEWUnyJL1RXlrpcyD7+X79oAfnTAn6WMwA==" ], + "keyUse" : [ "SIG" ], + "certificate" : [ "MIIClzCCAX8CBgGWCcdzhzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARrb25nMB4XDTI1MDQwNjA2MjQ0OFoXDTM1MDQwNjA2MjYyOFowDzENMAsGA1UEAwwEa29uZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtAgwPnjTQbCocR4+8dFuyihmLFHczILTuxcyd+JFrYILTfSBjOMmPN/i/CajX5PXtqzNoNQVThGOlcYSZYpjkE9KHlBmjEBC94ztwkPBd+Pko3xl9nBX3e/eucMI9Aez2OhHXR0VuJPDIemZnAFtp/ZEx5VSpGGj1/EHF20zeDgSdADOg0jHSPLv3PhTGvI+E26vifkNLnECgteQtrCMiEi/3BfSMa27NP06DjS2W3FLpahqNEWN0oqT8TyKpWsjegBKkR2OnmlAwzK5BCJ9KFAIzTM3LpoNplGtLkLSZ3exORoLMsIlGFDwFBDA5cMwP8ltRukqNbpYgaCqoetxkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAR8mRWKep0doyETLy+BA4ZdWtTlggrf0BZ2DbiEPAyFGtPhexwNWVchv4hMPJcEi8fqwFloP49UeJ/cFqXlu86piwshcCFYowLRUnXd8nkByflt9M2G7znYQMnExK2f5BEfauorYKbCaz/Ar4t4X/PVqm/bXyQ/HzKK6Y6KUWKYtiR1GVFq36vc6awgcIh7zN/OdJts4jfE+9MYTeJ0y87E7FidfW+57v6gyvmIA382qH+DwfmnXnr2tUwTsOGE1B9x7wzeFcunqkKLN1A9a+b1eMdpI+n0HJkkz5iW7HNeBxha9bZJc1n9maATeseLMv8G8vD/T1Od0/u7SkMIA7XA==" ], + "priority" : [ "100" ] + } + }, { + "id" : "77a5fcb2-7c41-4695-aaeb-952c15395241", + "name" : "hmac-generated-hs512", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "0e91674a-5029-4ced-ae39-eb0a5600394c" ], + "secret" : [ "YY4YqGaZm3OBn6xvTfKzu14nJsmgrOVTfAc455y0_s_IRaT3YWAW8KkEzjY8AH2HfKCqMgT3ddLsAEkYYYLq6mN3RyQAyh9xn85SGVM4vQoUBm8XX4u3C4rTHjn9CeNXbg_GPmm5b0bC6DGXiviDuAlYyQoa3xMSzKEsEXg0qCk" ], + "priority" : [ "100" ], + "algorithm" : [ "HS512" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "9b65acf6-146c-485c-91df-dd31f2fd8eb7", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false + } ] + }, { + "id" : "443a352f-2d01-4875-821d-19477722214d", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "6bfd707c-bb2c-4e80-9055-91f94f8c2cf6", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "0d2a8b4b-2b70-4161-ac5f-e8277f24dd2e", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "c8649ba0-e5d0-48e9-a583-b60b0cafa1bc", + "alias" : "Handle Existing Account", + "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false + } ] + }, { + "id" : "f32cbfcb-e0b9-4e9b-b546-6ffc03dbcd12", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "8ffe11b3-b956-497d-adab-04a8c6448103", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false + } ] + }, { + "id" : "b56de38d-eb79-475e-ac5a-4d067830c8b3", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "6dc77e4a-7890-4f2a-9685-cedbc060dde2", + "alias" : "browser", + "description" : "browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-spnego", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "identity-provider-redirector", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 25, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "forms", + "userSetupAllowed" : false + } ] + }, { + "id" : "d25fda31-c6d7-4421-abed-368c4e6e4fb9", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-secret-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-x509", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "a139285b-586f-44d1-8315-d528b6ff2547", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "1c796dd6-f18b-4bb5-beb4-20823d53ecf8", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "569b7d92-df20-4d2d-a31d-aea585a181ab", + "alias" : "first broker login", + "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false + } ] + }, { + "id" : "8f7d708f-7415-43e9-a7fd-3f5666cb4486", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "efc2f602-a1af-4123-9419-413ac09e9b1e", + "alias" : "registration", + "description" : "registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "registration form", + "userSetupAllowed" : false + } ] + }, { + "id" : "d40f94e2-3bcc-4568-a34f-4f41de723f1b", + "alias" : "registration form", + "description" : "registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-password-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 50, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-recaptcha-action", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 60, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-terms-and-conditions", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 70, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "20bb50fb-df76-490b-9baf-31866c80f6d0", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-credential-email", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 40, + "autheticatorFlow" : true, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "86382434-b1be-4011-9f38-b6e70a8267ba", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "b3ec8805-a97b-427f-8756-32910764ec73", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "894f7efd-e17b-49ee-8022-c117826e696a", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "TERMS_AND_CONDITIONS", + "name" : "Terms and Conditions", + "providerId" : "TERMS_AND_CONDITIONS", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : true, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : true, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "webauthn-register", + "name" : "Webauthn Register", + "providerId" : "webauthn-register", + "enabled" : true, + "defaultAction" : false, + "priority" : 70, + "config" : { } + }, { + "alias" : "webauthn-register-passwordless", + "name" : "Webauthn Register Passwordless", + "providerId" : "webauthn-register-passwordless", + "enabled" : true, + "defaultAction" : false, + "priority" : 80, + "config" : { } + }, { + "alias" : "VERIFY_PROFILE", + "name" : "Verify Profile", + "providerId" : "VERIFY_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 90, + "config" : { } + }, { + "alias" : "delete_credential", + "name" : "Delete Credential", + "providerId" : "delete_credential", + "enabled" : true, + "defaultAction" : false, + "priority" : 100, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "firstBrokerLoginFlow" : "first broker login", + "attributes" : { + "cibaBackchannelTokenDeliveryMode" : "poll", + "cibaExpiresIn" : "120", + "cibaAuthRequestedUserHint" : "login_hint", + "oauth2DeviceCodeLifespan" : "600", + "oauth2DevicePollingInterval" : "5", + "clientOfflineSessionMaxLifespan" : "0", + "clientSessionIdleTimeout" : "0", + "parRequestUriLifespan" : "60", + "clientSessionMaxLifespan" : "0", + "clientOfflineSessionIdleTimeout" : "0", + "cibaInterval" : "5", + "realmReusableOtpCode" : "false" + }, + "keycloakVersion" : "24.0.5", + "userManagedAccessAllowed" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} \ No newline at end of file diff --git a/auth-service/keycloak-import/realm-export.json b/auth-service/keycloak-import/realm-export.json new file mode 100644 index 0000000..a31a577 --- /dev/null +++ b/auth-service/keycloak-import/realm-export.json @@ -0,0 +1,2307 @@ +{ + "id": "fe536a4f-9764-4b29-8287-745c18fc3778", + "realm": "kong", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "none", + "registrationAllowed": true, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "c231543d-fad6-4b0f-b5bf-54a7cedec760", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "fe536a4f-9764-4b29-8287-745c18fc3778", + "attributes": {} + }, + { + "id": "2ab764ec-2fd7-4735-b893-1457f516ee0f", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "manage-account", + "view-profile" + ] + } + }, + "clientRole": false, + "containerId": "fe536a4f-9764-4b29-8287-745c18fc3778", + "attributes": {} + }, + { + "id": "0a9574a4-bf6f-4f86-9624-70b942531c95", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "fe536a4f-9764-4b29-8287-745c18fc3778", + "attributes": {} + } + ], + "client": { + "kong-oidc": [], + "realm-management": [ + { + "id": "2b007fc7-8646-4771-987c-d00758d284ae", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "f12d45a0-25a6-4aaf-adf5-8d99cf6ecf6a", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-groups", + "query-users" + ] + } + }, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "1e454f0c-3aca-47b4-9711-16468c2d44b6", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "aa380d16-4b3d-49a6-9d84-4d9b6a4bef0b", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "f1249a1a-9aa4-4734-9fc9-985c4e302ec8", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "1864f5ac-8a66-4496-8943-366d1bfe1793", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "30142c4b-abd8-423c-88a5-db28f00501de", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "3fdac547-1ea5-40c6-98bf-16e35a6c7f2f", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "ea1c291d-b10b-4511-b1bf-4b9db1914d89", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "impersonation", + "view-users", + "view-clients", + "view-realm", + "manage-realm", + "query-users", + "manage-clients", + "view-identity-providers", + "view-authorization", + "create-client", + "query-clients", + "manage-users", + "query-realms", + "query-groups", + "manage-authorization", + "view-events", + "manage-events", + "manage-identity-providers" + ] + } + }, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "1dd2e6a2-2eb4-466f-b24d-d11d83a89f91", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "c9fff176-3b00-4558-8ba6-431ec153d052", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "956ab296-b320-47f3-ad43-bd60f984ec1d", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "0715a933-81ed-40f9-9638-9151de7139ee", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "fae9cd52-4608-4230-a153-173835bada00", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "520077eb-fa5d-4c6e-8b81-226a569b1120", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "ff45306b-6db9-44e7-bf2a-bdfa35687c5c", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "5bde37a8-834b-4a2c-9eda-9e53c4d568e9", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "dba1939f-8ba0-4856-88ee-8c0f9874d8e3", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + }, + { + "id": "ed5d1f83-4fb6-4ecf-9a17-ab5110bd5536", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "dc185c95-4bbe-4c90-94a1-0b8dab908ab4", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "fe01a72d-ed99-44e3-9112-a0f2642da6c3", + "attributes": {} + } + ], + "account": [ + { + "id": "ecc49be2-7f2a-4a46-add7-8910d7e073a7", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + }, + { + "id": "0e9c57c3-9253-42cf-9267-0eeb1a26ef3c", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + }, + { + "id": "c2ae61d5-8169-4f71-b6cb-1e43ccb11cd0", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + }, + { + "id": "87d3b78e-ca6b-4ca2-ab62-274f4357cf9c", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + }, + { + "id": "f8c61736-8b4a-4daf-9668-4e043e503d84", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + }, + { + "id": "45381f22-225d-4f4f-97e9-ab5cdbbcc7b5", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + }, + { + "id": "aa07dcc1-a077-4f83-9ba1-7f711df541fe", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + }, + { + "id": "96f12df8-83c2-432a-afe5-5ddf4b9bb3c8", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRole": { + "id": "2ab764ec-2fd7-4735-b893-1457f516ee0f", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "fe536a4f-9764-4b29-8287-745c18fc3778" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": [ + "totpAppFreeOTPName", + "totpAppGoogleName", + "totpAppMicrosoftAuthenticatorName" + ], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account", + "view-groups" + ] + } + ] + }, + "clients": [ + { + "id": "722377fa-d1b4-4e3b-b0be-555f50b01153", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "e16a7dc2-5708-4643-b1a1-5bb39d2c5974", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "42b765a3-3ba8-4d53-a3dc-d9a5364eea38", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "b9729e4d-28d7-4cf9-acb3-6247c1f676d0", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "fe01a72d-ed99-44e3-9112-a0f2642da6c3", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "4c18c3dc-25fe-4926-9163-4a0ad55e72c6", + "clientId": "kong-oidc", + "name": "kong-oidc", + "description": "", + "rootUrl": "http://localhost:3000", + "adminUrl": "http://localhost:3000", + "baseUrl": "http://localhost:3000/*", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "http://localhost:3000/login" + ], + "webOrigins": [ + "http://localhost:3000" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "access.token.lifespan": "1800", + "client.secret.creation.time": "1743921958", + "login_theme": "keycloak", + "frontchannel.logout.url": "http://localhost:3000/login", + "post.logout.redirect.uris": "http://localhost:3000/login", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "use.refresh.tokens": "true", + "oidc.ciba.grant.enabled": "false", + "client.use.lightweight.access.token.enabled": "false", + "backchannel.logout.session.required": "true", + "backchannel.logout.url": "http://localhost:3000/login", + "client_credentials.use_refresh_token": "false", + "client.offline.session.idle.timeout": "2592000", + "acr.loa.map": "{}", + "require.pushed.authorization.requests": "false", + "tls.client.certificate.bound.access.tokens": "false", + "client.offline.session.max.lifespan": "2592000", + "display.on.consent.screen": "false", + "client.session.max.lifespan": "28800", + "client.session.idle.timeout": "216000", + "token.response.type.bearer.lower-case": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "d5bb3e14-a7fb-412d-b5ea-83777a8c8320", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "0525d0e7-187f-49bb-8eff-b36b9667b991", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/kong/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/kong/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "6e0a00e4-1412-4627-9754-cb8b001d54c9", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "e987e875-9d89-4a26-96b6-41303eb481c8", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "28be87f7-c996-4f88-97aa-5bd40274f4f7", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "19bb0b29-8341-42be-9051-df8089439bf3", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "7c614f88-1631-4169-8f17-323d50c51cba", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "efad8e19-1dae-42cd-aa9f-1955310fbe5d", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "4f412537-57d6-4d7d-8d68-e4442a265068", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "20cafdb3-b497-429c-8d27-9eaae409f44e", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "a195ac65-96e4-471f-b29e-19ec218c6feb", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "7fe201c5-3ac5-49ce-92f3-99eaa07f266d", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "e5796d6d-921d-4bfb-a786-410d8311a651", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "ca33a7fb-6c2e-4da2-9e79-30ec7b48c300", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "73cbda9d-42ad-49f6-8d4e-dc95b333a619", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "d8060a09-3b67-477b-a704-f9deb82b0bc4", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "introspection.token.claim": "true", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "47a2f9af-b1e4-4b03-981b-0ae9da9bcc86", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "4516baaf-cd97-4a28-8c5d-17a35e590293", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "68cdc4b0-3b8a-4c9d-ba2e-dcc334a69c80", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "227fe568-c468-4019-913e-68d18a4e8a19", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "ed2ba3eb-b005-401d-91ac-f4102d4bb979", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "305c66e4-6531-4e6f-8986-8cd81e08bf46", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "f5393ba4-37a3-4673-ad40-66eb2b2e0428", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "1370c80f-feef-418b-806d-1dec97e73aa2", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "71945b38-17a4-4a3c-b416-e7701e1af2cd", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "fdf50c0d-1767-4427-8706-72b79cf51756", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "cc945235-670d-4a12-a429-6e0c6d51cd71", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "f8bd340d-febb-407d-8c93-578aa4055146", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "965b8107-e85a-4325-a24c-512ecad9bcb6", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "02a6cca1-ed04-4828-a2aa-0bc9cef1b4b6", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "ec5a3595-9a6e-4fb0-baee-aba406920c1c", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "88c16e80-5038-4219-a3f0-f8e5d11b2d85", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "03da4fe1-64b5-4db4-ab72-0bc855e09871", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "dd63b2bf-5850-4ebf-be19-e194e5ec334f", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "6d56a241-aa41-441c-a867-595443294557", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String" + } + }, + { + "id": "54fc6e1c-34fe-4aa3-88eb-46ffdeb70fe5", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String" + } + }, + { + "id": "1dd52096-01d5-42cf-940a-78bc527a5100", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "9e8a5630-ab90-4d20-a702-b1a083e1aab8", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "097d9f32-aa95-4ca7-9e59-551a648cb2f3", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "245835c6-d274-46a6-af28-578e99de654a", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins", + "acr" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [ + { + "alias": "google", + "internalId": "7b540734-06ee-4074-a547-7659f5900f4d", + "providerId": "google", + "enabled": true, + "updateProfileFirstLoginMode": "on", + "trustEmail": false, + "storeToken": true, + "addReadTokenRoleOnCreate": false, + "authenticateByDefault": false, + "linkOnly": false, + "config": { + "hideOnLoginPage": "false", + "offlineAccess": "true", + "acceptsPromptNoneForwardFromClient": "false", + "clientId": "785994007278-lr2k84dv19513frlhkid2dvnf396mpa0.apps.googleusercontent.com", + "disableUserInfo": "false", + "filteredByClaim": "false", + "syncMode": "IMPORT", + "userIp": "false", + "clientSecret": "**********", + "defaultScope": "openid profile email" + } + } + ], + "identityProviderMappers": [ + { + "id": "7520964c-391b-4fa9-a59f-b260ce31e9cd", + "name": "Google Email", + "identityProviderAlias": "google", + "identityProviderMapper": "google-user-attribute-mapper", + "config": { + "syncMode": "INHERIT", + "jsonField": "email", + "userAttribute": "email" + } + }, + { + "id": "aa1327e9-4840-417d-b24c-776cee722ca7", + "name": "Google Last Name", + "identityProviderAlias": "google", + "identityProviderMapper": "google-user-attribute-mapper", + "config": { + "syncMode": "INHERIT", + "jsonField": "family_name", + "userAttribute": "lastName" + } + }, + { + "id": "5f02ac40-c451-4f4e-b50c-8cfedd505055", + "name": "Google First Name", + "identityProviderAlias": "google", + "identityProviderMapper": "google-user-attribute-mapper", + "config": { + "syncMode": "INHERIT", + "jsonField": "given_name", + "userAttribute": "firstName" + } + }, + { + "id": "b31f6a50-bbcd-429b-9f17-b99c764b1250", + "name": "Google Username from Email", + "identityProviderAlias": "google", + "identityProviderMapper": "google-user-attribute-mapper", + "config": { + "syncMode": "INHERIT", + "jsonField": "name", + "userAttribute": "username" + } + } + ], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "12fc9eb4-d127-412e-9d49-299ff633bceb", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "bf81b717-215b-4f49-9720-9c5f68ddff5b", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "6f6de768-29b4-4711-85f8-7072621bc7dd", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper", + "saml-role-list-mapper", + "saml-user-attribute-mapper", + "oidc-address-mapper", + "oidc-full-name-mapper", + "saml-user-property-mapper" + ] + } + }, + { + "id": "29c345fd-1a15-4886-ba50-9ab389d4d66a", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "a6bd777b-7176-4c86-98b0-cee4d9b280e6", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "6c264b28-83f4-4e6d-b7b6-872c8515c8b3", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "c364f868-4588-4d65-80b1-3afb35c4e12f", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "43f44171-bc8c-4d45-9d4b-2ba798f209a3", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-attribute-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-full-name-mapper", + "saml-role-list-mapper", + "saml-user-property-mapper", + "oidc-address-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "77471f51-2188-4945-98bd-2457efc0cc9b", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "f1965169-0444-4599-980a-e71cfbc6a792", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "61600c4f-e031-44d4-8f06-b8e21f0f2aac", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "77a5fcb2-7c41-4695-aaeb-952c15395241", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS512" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "9b65acf6-146c-485c-91df-dd31f2fd8eb7", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "443a352f-2d01-4875-821d-19477722214d", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "6bfd707c-bb2c-4e80-9055-91f94f8c2cf6", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "0d2a8b4b-2b70-4161-ac5f-e8277f24dd2e", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "c8649ba0-e5d0-48e9-a583-b60b0cafa1bc", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "f32cbfcb-e0b9-4e9b-b546-6ffc03dbcd12", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "8ffe11b3-b956-497d-adab-04a8c6448103", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "b56de38d-eb79-475e-ac5a-4d067830c8b3", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "6dc77e4a-7890-4f2a-9685-cedbc060dde2", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "d25fda31-c6d7-4421-abed-368c4e6e4fb9", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "a139285b-586f-44d1-8315-d528b6ff2547", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "1c796dd6-f18b-4bb5-beb4-20823d53ecf8", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "569b7d92-df20-4d2d-a31d-aea585a181ab", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "8f7d708f-7415-43e9-a7fd-3f5666cb4486", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "efc2f602-a1af-4123-9419-413ac09e9b1e", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "d40f94e2-3bcc-4568-a34f-4f41de723f1b", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "20bb50fb-df76-490b-9baf-31866c80f6d0", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "86382434-b1be-4011-9f38-b6e70a8267ba", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "b3ec8805-a97b-427f-8756-32910764ec73", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "894f7efd-e17b-49ee-8022-c117826e696a", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", + "clientSessionIdleTimeout": "0", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5", + "realmReusableOtpCode": "false" + }, + "keycloakVersion": "24.0.5", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/auth-service/keycloak-setup.sh b/auth-service/keycloak-setup.sh new file mode 100644 index 0000000..ae1ce2d --- /dev/null +++ b/auth-service/keycloak-setup.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# Start Keycloak in background +/opt/keycloak/bin/kc.sh start-dev \ + --http-enabled=true \ + --hostname-strict=false \ + --hostname-strict-https=false & +KEYCLOAK_PID=$! + +# Wait for Keycloak to become ready +echo "โณ Waiting for Keycloak to start (checking kcadm connection)..." +until /opt/keycloak/bin/kcadm.sh config credentials \ + --server http://localhost:8080 \ + --realm master \ + --user ${KEYCLOAK_ADMIN:-admin} \ + --password ${KEYCLOAK_ADMIN_PASSWORD:-admin} \ + --config /tmp/kcadm.config >/dev/null 2>&1; do + sleep 2 +done +echo "โœ… Keycloak is up and authenticated." + +# Disable SSL requirement in master realm +/opt/keycloak/bin/kcadm.sh update realms/master \ + -s sslRequired=NONE \ + --config /tmp/kcadm.config + +# โœ… Import the realm file if it exists +if [ -f "/opt/keycloak/data/import/kong-realm.json" ]; then + echo "๐Ÿ“ฆ Importing realm from kong-realm.json..." + /opt/keycloak/bin/kcadm.sh create realms \ + -f /opt/keycloak/data/import/kong-realm.json \ + --config /tmp/kcadm.config || echo "โš ๏ธ Realm import may have failed or already exists." +else + echo "โŒ kong-realm.json not found at /opt/keycloak/data/import/" +fi + +# Keep Keycloak running +wait $KEYCLOAK_PID diff --git a/communication.pb.go b/communication.pb.go new file mode 100644 index 0000000..7edc974 --- /dev/null +++ b/communication.pb.go @@ -0,0 +1,2972 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.12 +// source: communication.proto + +package pb + +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) +) + +// The request message containing the user's name. +type HelloRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *HelloRequest) Reset() { + *x = HelloRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloRequest) ProtoMessage() {} + +func (x *HelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. +func (*HelloRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{0} +} + +func (x *HelloRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// The response message containing the greetings +type HelloReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *HelloReply) Reset() { + *x = HelloReply{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HelloReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloReply) ProtoMessage() {} + +func (x *HelloReply) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. +func (*HelloReply) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{1} +} + +func (x *HelloReply) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type GeocodeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (x *GeocodeRequest) Reset() { + *x = GeocodeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeRequest) ProtoMessage() {} + +func (x *GeocodeRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeRequest.ProtoReflect.Descriptor instead. +func (*GeocodeRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{2} +} + +func (x *GeocodeRequest) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +type GeocodeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Results []*GeocodeResponse_Result `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "ZERO_RESULTS" +} + +func (x *GeocodeResponse) Reset() { + *x = GeocodeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse) ProtoMessage() {} + +func (x *GeocodeResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeResponse.ProtoReflect.Descriptor instead. +func (*GeocodeResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{3} +} + +func (x *GeocodeResponse) GetResults() []*GeocodeResponse_Result { + if x != nil { + return x.Results + } + return nil +} + +func (x *GeocodeResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type SearchPlacesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` // Text string to search for + Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` // Lat,Lng coordinates (e.g., "37.4224764,-122.0842499") +} + +func (x *SearchPlacesRequest) Reset() { + *x = SearchPlacesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[4] + 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_communication_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchPlacesRequest.ProtoReflect.Descriptor instead. +func (*SearchPlacesRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{4} +} + +func (x *SearchPlacesRequest) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *SearchPlacesRequest) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +type Place 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"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Vicinity string `protobuf:"bytes,3,opt,name=vicinity,proto3" json:"vicinity,omitempty"` // Or address + Rating float64 `protobuf:"fixed64,4,opt,name=rating,proto3" json:"rating,omitempty"` + UserRatingsTotal int32 `protobuf:"varint,5,opt,name=user_ratings_total,json=userRatingsTotal,proto3" json:"user_ratings_total,omitempty"` + GeometryLocation *Place_Location `protobuf:"bytes,6,opt,name=geometry_location,json=geometryLocation,proto3" json:"geometry_location,omitempty"` // Simplified, directly embedding Location + OpeningHours *Place_OpeningHours `protobuf:"bytes,7,opt,name=opening_hours,json=openingHours,proto3" json:"opening_hours,omitempty"` + Photos []*Place_Photo `protobuf:"bytes,8,rep,name=photos,proto3" json:"photos,omitempty"` + PhotoUrls []string `protobuf:"bytes,9,rep,name=photo_urls,json=photoUrls,proto3" json:"photo_urls,omitempty"` // New field from existing API + Types []string `protobuf:"bytes,10,rep,name=types,proto3" json:"types,omitempty"` +} + +func (x *Place) Reset() { + *x = Place{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place) ProtoMessage() {} + +func (x *Place) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place.ProtoReflect.Descriptor instead. +func (*Place) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5} +} + +func (x *Place) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *Place) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Place) GetVicinity() string { + if x != nil { + return x.Vicinity + } + return "" +} + +func (x *Place) GetRating() float64 { + if x != nil { + return x.Rating + } + return 0 +} + +func (x *Place) GetUserRatingsTotal() int32 { + if x != nil { + return x.UserRatingsTotal + } + return 0 +} + +func (x *Place) GetGeometryLocation() *Place_Location { + if x != nil { + return x.GeometryLocation + } + return nil +} + +func (x *Place) GetOpeningHours() *Place_OpeningHours { + if x != nil { + return x.OpeningHours + } + return nil +} + +func (x *Place) GetPhotos() []*Place_Photo { + if x != nil { + return x.Photos + } + return nil +} + +func (x *Place) GetPhotoUrls() []string { + if x != nil { + return x.PhotoUrls + } + return nil +} + +func (x *Place) GetTypes() []string { + if x != nil { + return x.Types + } + return nil +} + +type SearchPlacesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Results []*Place `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "ZERO_RESULTS" +} + +func (x *SearchPlacesResponse) Reset() { + *x = SearchPlacesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[6] + 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_communication_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchPlacesResponse.ProtoReflect.Descriptor instead. +func (*SearchPlacesResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{6} +} + +func (x *SearchPlacesResponse) GetResults() []*Place { + if x != nil { + return x.Results + } + return nil +} + +func (x *SearchPlacesResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type PlaceDetailsRequest 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 *PlaceDetailsRequest) Reset() { + *x = PlaceDetailsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlaceDetailsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlaceDetailsRequest) ProtoMessage() {} + +func (x *PlaceDetailsRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlaceDetailsRequest.ProtoReflect.Descriptor instead. +func (*PlaceDetailsRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{7} +} + +func (x *PlaceDetailsRequest) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +// Using the existing Place message for the main result, but we need a wrapper for the "result" field and status. +type PlaceDetailsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result *Place `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` // Contains most of the details + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "NOT_FOUND" +} + +func (x *PlaceDetailsResponse) Reset() { + *x = PlaceDetailsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlaceDetailsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlaceDetailsResponse) ProtoMessage() {} + +func (x *PlaceDetailsResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlaceDetailsResponse.ProtoReflect.Descriptor instead. +func (*PlaceDetailsResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{8} +} + +func (x *PlaceDetailsResponse) GetResult() *Place { + if x != nil { + return x.Result + } + return nil +} + +func (x *PlaceDetailsResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type DirectionsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Origin string `protobuf:"bytes,1,opt,name=origin,proto3" json:"origin,omitempty"` + Destination string `protobuf:"bytes,2,opt,name=destination,proto3" json:"destination,omitempty"` +} + +func (x *DirectionsRequest) Reset() { + *x = DirectionsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsRequest) ProtoMessage() {} + +func (x *DirectionsRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsRequest.ProtoReflect.Descriptor instead. +func (*DirectionsRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{9} +} + +func (x *DirectionsRequest) GetOrigin() string { + if x != nil { + return x.Origin + } + return "" +} + +func (x *DirectionsRequest) GetDestination() string { + if x != nil { + return x.Destination + } + return "" +} + +type DirectionsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Routes []*DirectionsResponse_Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + GeocodedWaypoints []*DirectionsResponse_GeocodedWaypoint `protobuf:"bytes,2,rep,name=geocoded_waypoints,json=geocodedWaypoints,proto3" json:"geocoded_waypoints,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "NOT_FOUND" +} + +func (x *DirectionsResponse) Reset() { + *x = DirectionsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse) ProtoMessage() {} + +func (x *DirectionsResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse.ProtoReflect.Descriptor instead. +func (*DirectionsResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10} +} + +func (x *DirectionsResponse) GetRoutes() []*DirectionsResponse_Route { + if x != nil { + return x.Routes + } + return nil +} + +func (x *DirectionsResponse) GetGeocodedWaypoints() []*DirectionsResponse_GeocodedWaypoint { + if x != nil { + return x.GeocodedWaypoints + } + return nil +} + +func (x *DirectionsResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type DistanceMatrixRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Origins string `protobuf:"bytes,1,opt,name=origins,proto3" json:"origins,omitempty"` // Pipe-separated + Destinations string `protobuf:"bytes,2,opt,name=destinations,proto3" json:"destinations,omitempty"` // Pipe-separated +} + +func (x *DistanceMatrixRequest) Reset() { + *x = DistanceMatrixRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixRequest) ProtoMessage() {} + +func (x *DistanceMatrixRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixRequest.ProtoReflect.Descriptor instead. +func (*DistanceMatrixRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{11} +} + +func (x *DistanceMatrixRequest) GetOrigins() string { + if x != nil { + return x.Origins + } + return "" +} + +func (x *DistanceMatrixRequest) GetDestinations() string { + if x != nil { + return x.Destinations + } + return "" +} + +type DistanceMatrixResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Based on Google's API: origin_addresses and destination_addresses are top-level + OriginAddresses []string `protobuf:"bytes,1,rep,name=origin_addresses,json=originAddresses,proto3" json:"origin_addresses,omitempty"` + DestinationAddresses []string `protobuf:"bytes,2,rep,name=destination_addresses,json=destinationAddresses,proto3" json:"destination_addresses,omitempty"` + Rows []*DistanceMatrixResponse_Row `protobuf:"bytes,3,rep,name=rows,proto3" json:"rows,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` // Overall status for the request, not explicitly in current Go model but good to have. +} + +func (x *DistanceMatrixResponse) Reset() { + *x = DistanceMatrixResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse) ProtoMessage() {} + +func (x *DistanceMatrixResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12} +} + +func (x *DistanceMatrixResponse) GetOriginAddresses() []string { + if x != nil { + return x.OriginAddresses + } + return nil +} + +func (x *DistanceMatrixResponse) GetDestinationAddresses() []string { + if x != nil { + return x.DestinationAddresses + } + return nil +} + +func (x *DistanceMatrixResponse) GetRows() []*DistanceMatrixResponse_Row { + if x != nil { + return x.Rows + } + return nil +} + +func (x *DistanceMatrixResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type GeminiRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Prompt string `protobuf:"bytes,1,opt,name=prompt,proto3" json:"prompt,omitempty"` +} + +func (x *GeminiRequest) Reset() { + *x = GeminiRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiRequest) ProtoMessage() {} + +func (x *GeminiRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiRequest.ProtoReflect.Descriptor instead. +func (*GeminiRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{13} +} + +func (x *GeminiRequest) GetPrompt() string { + if x != nil { + return x.Prompt + } + return "" +} + +type GeminiResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Candidates []*GeminiResponse_Candidate `protobuf:"bytes,1,rep,name=candidates,proto3" json:"candidates,omitempty"` + PromptFeedback *GeminiResponse_PromptFeedback `protobuf:"bytes,2,opt,name=prompt_feedback,json=promptFeedback,proto3" json:"prompt_feedback,omitempty"` // UsageMetadata usage_metadata = 3; // If token count, etc., is needed +} + +func (x *GeminiResponse) Reset() { + *x = GeminiResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse) ProtoMessage() {} + +func (x *GeminiResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse.ProtoReflect.Descriptor instead. +func (*GeminiResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14} +} + +func (x *GeminiResponse) GetCandidates() []*GeminiResponse_Candidate { + if x != nil { + return x.Candidates + } + return nil +} + +func (x *GeminiResponse) GetPromptFeedback() *GeminiResponse_PromptFeedback { + if x != nil { + return x.PromptFeedback + } + return nil +} + +type GeocodeResponse_Location struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Lat float64 `protobuf:"fixed64,1,opt,name=lat,proto3" json:"lat,omitempty"` + Lng float64 `protobuf:"fixed64,2,opt,name=lng,proto3" json:"lng,omitempty"` +} + +func (x *GeocodeResponse_Location) Reset() { + *x = GeocodeResponse_Location{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeResponse_Location) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse_Location) ProtoMessage() {} + +func (x *GeocodeResponse_Location) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeResponse_Location.ProtoReflect.Descriptor instead. +func (*GeocodeResponse_Location) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *GeocodeResponse_Location) GetLat() float64 { + if x != nil { + return x.Lat + } + return 0 +} + +func (x *GeocodeResponse_Location) GetLng() float64 { + if x != nil { + return x.Lng + } + return 0 +} + +type GeocodeResponse_Result struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FormattedAddress string `protobuf:"bytes,1,opt,name=formatted_address,json=formattedAddress,proto3" json:"formatted_address,omitempty"` + Location *GeocodeResponse_Location `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` // Add other relevant fields from Geocoding API if needed +} + +func (x *GeocodeResponse_Result) Reset() { + *x = GeocodeResponse_Result{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeResponse_Result) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse_Result) ProtoMessage() {} + +func (x *GeocodeResponse_Result) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeResponse_Result.ProtoReflect.Descriptor instead. +func (*GeocodeResponse_Result) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{3, 1} +} + +func (x *GeocodeResponse_Result) GetFormattedAddress() string { + if x != nil { + return x.FormattedAddress + } + return "" +} + +func (x *GeocodeResponse_Result) GetLocation() *GeocodeResponse_Location { + if x != nil { + return x.Location + } + return nil +} + +type Place_Location struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Lat float64 `protobuf:"fixed64,1,opt,name=lat,proto3" json:"lat,omitempty"` + Lng float64 `protobuf:"fixed64,2,opt,name=lng,proto3" json:"lng,omitempty"` +} + +func (x *Place_Location) Reset() { + *x = Place_Location{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place_Location) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_Location) ProtoMessage() {} + +func (x *Place_Location) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place_Location.ProtoReflect.Descriptor instead. +func (*Place_Location) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *Place_Location) GetLat() float64 { + if x != nil { + return x.Lat + } + return 0 +} + +func (x *Place_Location) GetLng() float64 { + if x != nil { + return x.Lng + } + return 0 +} + +type Place_OpeningHours struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpenNow bool `protobuf:"varint,1,opt,name=open_now,json=openNow,proto3" json:"open_now,omitempty"` +} + +func (x *Place_OpeningHours) Reset() { + *x = Place_OpeningHours{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place_OpeningHours) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_OpeningHours) ProtoMessage() {} + +func (x *Place_OpeningHours) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place_OpeningHours.ProtoReflect.Descriptor instead. +func (*Place_OpeningHours) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5, 1} +} + +func (x *Place_OpeningHours) GetOpenNow() bool { + if x != nil { + return x.OpenNow + } + return false +} + +type Place_Photo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PhotoReference string `protobuf:"bytes,1,opt,name=photo_reference,json=photoReference,proto3" json:"photo_reference,omitempty"` + Height int32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + Width int32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` // repeated string html_attributions = 4; // Usually not needed for direct display +} + +func (x *Place_Photo) Reset() { + *x = Place_Photo{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place_Photo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_Photo) ProtoMessage() {} + +func (x *Place_Photo) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place_Photo.ProtoReflect.Descriptor instead. +func (*Place_Photo) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5, 2} +} + +func (x *Place_Photo) GetPhotoReference() string { + if x != nil { + return x.PhotoReference + } + return "" +} + +func (x *Place_Photo) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +func (x *Place_Photo) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +type DirectionsResponse_Distance struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // meters +} + +func (x *DirectionsResponse_Distance) Reset() { + *x = DirectionsResponse_Distance{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Distance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Distance) ProtoMessage() {} + +func (x *DirectionsResponse_Distance) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Distance.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Distance) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 0} +} + +func (x *DirectionsResponse_Distance) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DirectionsResponse_Distance) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DirectionsResponse_Duration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // seconds +} + +func (x *DirectionsResponse_Duration) Reset() { + *x = DirectionsResponse_Duration{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Duration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Duration) ProtoMessage() {} + +func (x *DirectionsResponse_Duration) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Duration.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Duration) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 1} +} + +func (x *DirectionsResponse_Duration) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DirectionsResponse_Duration) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DirectionsResponse_Polyline struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Points string `protobuf:"bytes,1,opt,name=points,proto3" json:"points,omitempty"` +} + +func (x *DirectionsResponse_Polyline) Reset() { + *x = DirectionsResponse_Polyline{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Polyline) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Polyline) ProtoMessage() {} + +func (x *DirectionsResponse_Polyline) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Polyline.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Polyline) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 2} +} + +func (x *DirectionsResponse_Polyline) GetPoints() string { + if x != nil { + return x.Points + } + return "" +} + +type DirectionsResponse_Step struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HtmlInstructions string `protobuf:"bytes,1,opt,name=html_instructions,json=htmlInstructions,proto3" json:"html_instructions,omitempty"` + Distance *DirectionsResponse_Distance `protobuf:"bytes,2,opt,name=distance,proto3" json:"distance,omitempty"` + Duration *DirectionsResponse_Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + Polyline *DirectionsResponse_Polyline `protobuf:"bytes,4,opt,name=polyline,proto3" json:"polyline,omitempty"` // Add start_location, end_location if needed +} + +func (x *DirectionsResponse_Step) Reset() { + *x = DirectionsResponse_Step{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Step) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Step) ProtoMessage() {} + +func (x *DirectionsResponse_Step) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Step.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Step) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 3} +} + +func (x *DirectionsResponse_Step) GetHtmlInstructions() string { + if x != nil { + return x.HtmlInstructions + } + return "" +} + +func (x *DirectionsResponse_Step) GetDistance() *DirectionsResponse_Distance { + if x != nil { + return x.Distance + } + return nil +} + +func (x *DirectionsResponse_Step) GetDuration() *DirectionsResponse_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DirectionsResponse_Step) GetPolyline() *DirectionsResponse_Polyline { + if x != nil { + return x.Polyline + } + return nil +} + +type DirectionsResponse_Leg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Distance *DirectionsResponse_Distance `protobuf:"bytes,1,opt,name=distance,proto3" json:"distance,omitempty"` + Duration *DirectionsResponse_Duration `protobuf:"bytes,2,opt,name=duration,proto3" json:"duration,omitempty"` + StartAddress string `protobuf:"bytes,3,opt,name=start_address,json=startAddress,proto3" json:"start_address,omitempty"` + EndAddress string `protobuf:"bytes,4,opt,name=end_address,json=endAddress,proto3" json:"end_address,omitempty"` + Steps []*DirectionsResponse_Step `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"` // Add start_location, end_location if needed +} + +func (x *DirectionsResponse_Leg) Reset() { + *x = DirectionsResponse_Leg{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Leg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Leg) ProtoMessage() {} + +func (x *DirectionsResponse_Leg) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Leg.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Leg) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 4} +} + +func (x *DirectionsResponse_Leg) GetDistance() *DirectionsResponse_Distance { + if x != nil { + return x.Distance + } + return nil +} + +func (x *DirectionsResponse_Leg) GetDuration() *DirectionsResponse_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DirectionsResponse_Leg) GetStartAddress() string { + if x != nil { + return x.StartAddress + } + return "" +} + +func (x *DirectionsResponse_Leg) GetEndAddress() string { + if x != nil { + return x.EndAddress + } + return "" +} + +func (x *DirectionsResponse_Leg) GetSteps() []*DirectionsResponse_Step { + if x != nil { + return x.Steps + } + return nil +} + +type DirectionsResponse_Route struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Summary string `protobuf:"bytes,1,opt,name=summary,proto3" json:"summary,omitempty"` + Legs []*DirectionsResponse_Leg `protobuf:"bytes,2,rep,name=legs,proto3" json:"legs,omitempty"` + OverviewPolyline *DirectionsResponse_Polyline `protobuf:"bytes,3,opt,name=overview_polyline,json=overviewPolyline,proto3" json:"overview_polyline,omitempty"` // Add warnings, bounds if needed +} + +func (x *DirectionsResponse_Route) Reset() { + *x = DirectionsResponse_Route{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Route) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Route) ProtoMessage() {} + +func (x *DirectionsResponse_Route) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Route.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Route) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 5} +} + +func (x *DirectionsResponse_Route) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *DirectionsResponse_Route) GetLegs() []*DirectionsResponse_Leg { + if x != nil { + return x.Legs + } + return nil +} + +func (x *DirectionsResponse_Route) GetOverviewPolyline() *DirectionsResponse_Polyline { + if x != nil { + return x.OverviewPolyline + } + return nil +} + +type DirectionsResponse_GeocodedWaypoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GeocoderStatus string `protobuf:"bytes,1,opt,name=geocoder_status,json=geocoderStatus,proto3" json:"geocoder_status,omitempty"` + PlaceId string `protobuf:"bytes,2,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + Types []string `protobuf:"bytes,3,rep,name=types,proto3" json:"types,omitempty"` +} + +func (x *DirectionsResponse_GeocodedWaypoint) Reset() { + *x = DirectionsResponse_GeocodedWaypoint{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_GeocodedWaypoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_GeocodedWaypoint) ProtoMessage() {} + +func (x *DirectionsResponse_GeocodedWaypoint) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_GeocodedWaypoint.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_GeocodedWaypoint) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 6} +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetGeocoderStatus() string { + if x != nil { + return x.GeocoderStatus + } + return "" +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetTypes() []string { + if x != nil { + return x.Types + } + return nil +} + +type DistanceMatrixResponse_Element struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "NOT_FOUND", "ZERO_RESULTS" + Duration *DistanceMatrixResponse_Element_Duration `protobuf:"bytes,2,opt,name=duration,proto3" json:"duration,omitempty"` + Distance *DistanceMatrixResponse_Element_Distance `protobuf:"bytes,3,opt,name=distance,proto3" json:"distance,omitempty"` +} + +func (x *DistanceMatrixResponse_Element) Reset() { + *x = DistanceMatrixResponse_Element{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Element) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Element.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 0} +} + +func (x *DistanceMatrixResponse_Element) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *DistanceMatrixResponse_Element) GetDuration() *DistanceMatrixResponse_Element_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DistanceMatrixResponse_Element) GetDistance() *DistanceMatrixResponse_Element_Distance { + if x != nil { + return x.Distance + } + return nil +} + +type DistanceMatrixResponse_Row struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Elements []*DistanceMatrixResponse_Element `protobuf:"bytes,1,rep,name=elements,proto3" json:"elements,omitempty"` +} + +func (x *DistanceMatrixResponse_Row) Reset() { + *x = DistanceMatrixResponse_Row{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Row) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Row) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Row) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Row.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Row) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 1} +} + +func (x *DistanceMatrixResponse_Row) GetElements() []*DistanceMatrixResponse_Element { + if x != nil { + return x.Elements + } + return nil +} + +type DistanceMatrixResponse_Element_Duration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // seconds +} + +func (x *DistanceMatrixResponse_Element_Duration) Reset() { + *x = DistanceMatrixResponse_Element_Duration{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Element_Duration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element_Duration) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element_Duration) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Element_Duration.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element_Duration) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 0, 0} +} + +func (x *DistanceMatrixResponse_Element_Duration) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DistanceMatrixResponse_Element_Duration) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DistanceMatrixResponse_Element_Distance struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // meters +} + +func (x *DistanceMatrixResponse_Element_Distance) Reset() { + *x = DistanceMatrixResponse_Element_Distance{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Element_Distance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element_Distance) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element_Distance) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Element_Distance.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element_Distance) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 0, 1} +} + +func (x *DistanceMatrixResponse_Element_Distance) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DistanceMatrixResponse_Element_Distance) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type GeminiResponse_SafetyRating struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Category string `protobuf:"bytes,1,opt,name=category,proto3" json:"category,omitempty"` // e.g., "HARM_CATEGORY_SEXUALLY_EXPLICIT" + Probability string `protobuf:"bytes,2,opt,name=probability,proto3" json:"probability,omitempty"` // e.g., "NEGLIGIBLE", "LOW", "MEDIUM", "HIGH" +} + +func (x *GeminiResponse_SafetyRating) Reset() { + *x = GeminiResponse_SafetyRating{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_SafetyRating) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_SafetyRating) ProtoMessage() {} + +func (x *GeminiResponse_SafetyRating) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_SafetyRating.ProtoReflect.Descriptor instead. +func (*GeminiResponse_SafetyRating) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 0} +} + +func (x *GeminiResponse_SafetyRating) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *GeminiResponse_SafetyRating) GetProbability() string { + if x != nil { + return x.Probability + } + return "" +} + +type GeminiResponse_ContentPart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` // Potentially add other part types like 'inline_data' if needed in the future +} + +func (x *GeminiResponse_ContentPart) Reset() { + *x = GeminiResponse_ContentPart{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_ContentPart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_ContentPart) ProtoMessage() {} + +func (x *GeminiResponse_ContentPart) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_ContentPart.ProtoReflect.Descriptor instead. +func (*GeminiResponse_ContentPart) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 1} +} + +func (x *GeminiResponse_ContentPart) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +type GeminiResponse_Content struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Parts []*GeminiResponse_ContentPart `protobuf:"bytes,1,rep,name=parts,proto3" json:"parts,omitempty"` + Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` // e.g., "user", "model" +} + +func (x *GeminiResponse_Content) Reset() { + *x = GeminiResponse_Content{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_Content) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_Content) ProtoMessage() {} + +func (x *GeminiResponse_Content) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_Content.ProtoReflect.Descriptor instead. +func (*GeminiResponse_Content) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 2} +} + +func (x *GeminiResponse_Content) GetParts() []*GeminiResponse_ContentPart { + if x != nil { + return x.Parts + } + return nil +} + +func (x *GeminiResponse_Content) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +type GeminiResponse_Candidate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Content *GeminiResponse_Content `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + FinishReason string `protobuf:"bytes,2,opt,name=finish_reason,json=finishReason,proto3" json:"finish_reason,omitempty"` // e.g., "STOP", "MAX_TOKENS", "SAFETY" + Index int32 `protobuf:"varint,3,opt,name=index,proto3" json:"index,omitempty"` + SafetyRatings []*GeminiResponse_SafetyRating `protobuf:"bytes,4,rep,name=safety_ratings,json=safetyRatings,proto3" json:"safety_ratings,omitempty"` // Potentially add 'citation_metadata' if needed +} + +func (x *GeminiResponse_Candidate) Reset() { + *x = GeminiResponse_Candidate{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_Candidate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_Candidate) ProtoMessage() {} + +func (x *GeminiResponse_Candidate) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_Candidate.ProtoReflect.Descriptor instead. +func (*GeminiResponse_Candidate) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 3} +} + +func (x *GeminiResponse_Candidate) GetContent() *GeminiResponse_Content { + if x != nil { + return x.Content + } + return nil +} + +func (x *GeminiResponse_Candidate) GetFinishReason() string { + if x != nil { + return x.FinishReason + } + return "" +} + +func (x *GeminiResponse_Candidate) GetIndex() int32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *GeminiResponse_Candidate) GetSafetyRatings() []*GeminiResponse_SafetyRating { + if x != nil { + return x.SafetyRatings + } + return nil +} + +type GeminiResponse_PromptFeedback struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // string block_reason = 1; // If prompt was blocked + SafetyRatings []*GeminiResponse_SafetyRating `protobuf:"bytes,2,rep,name=safety_ratings,json=safetyRatings,proto3" json:"safety_ratings,omitempty"` +} + +func (x *GeminiResponse_PromptFeedback) Reset() { + *x = GeminiResponse_PromptFeedback{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_PromptFeedback) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_PromptFeedback) ProtoMessage() {} + +func (x *GeminiResponse_PromptFeedback) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_PromptFeedback.ProtoReflect.Descriptor instead. +func (*GeminiResponse_PromptFeedback) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 4} +} + +func (x *GeminiResponse_PromptFeedback) GetSafetyRatings() []*GeminiResponse_SafetyRating { + if x != nil { + return x.SafetyRatings + } + return nil +} + +var File_communication_proto protoreflect.FileDescriptor + +var file_communication_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0c, 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, 0x26, 0x0a, 0x0a, 0x48, + 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 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, 0x2a, 0x0a, 0x0e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0x9c, 0x02, 0x0a, 0x0f, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, + 0x2e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6c, + 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x61, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x6c, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6e, 0x67, 0x1a, + 0x7d, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x64, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x46, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x63, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x47, + 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, 0x1a, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xd9, 0x04, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x63, + 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, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x69, 0x63, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x76, 0x69, 0x63, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x72, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x72, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x10, 0x75, 0x73, 0x65, 0x72, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x54, 0x6f, 0x74, + 0x61, 0x6c, 0x12, 0x4d, 0x0a, 0x11, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x10, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x49, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x6f, 0x75, + 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, 0x63, + 0x65, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x52, 0x0c, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x12, 0x35, 0x0a, 0x06, + 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, + 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x50, 0x6c, 0x61, 0x63, 0x65, 0x2e, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x52, 0x06, 0x70, 0x68, 0x6f, + 0x74, 0x6f, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x5f, 0x75, 0x72, 0x6c, + 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x55, 0x72, + 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x1a, 0x2e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x03, 0x6c, 0x61, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6e, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6e, 0x67, 0x1a, 0x29, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x6e, + 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x6e, + 0x5f, 0x6e, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6f, 0x70, 0x65, 0x6e, + 0x4e, 0x6f, 0x77, 0x1a, 0x5e, 0x0a, 0x05, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x12, 0x27, 0x0a, 0x0f, + 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x22, 0x61, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, + 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x50, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x30, 0x0a, 0x13, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 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, 0x5f, 0x0a, 0x14, 0x50, 0x6c, 0x61, 0x63, + 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xce, 0x09, 0x0a, 0x12, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x42, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x12, 0x64, 0x0a, 0x12, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, + 0x77, 0x61, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x57, 0x61, + 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x11, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, + 0x57, 0x61, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x1a, 0x34, 0x0a, 0x08, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x34, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x22, 0x0a, + 0x08, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x1a, 0x94, 0x02, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x2b, 0x0a, 0x11, 0x68, 0x74, + 0x6d, 0x6c, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x68, 0x74, 0x6d, 0x6c, 0x49, 0x6e, 0x73, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x49, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, + 0x08, 0x70, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x52, 0x08, + 0x70, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0xa2, 0x02, 0x0a, 0x03, 0x4c, 0x65, 0x67, + 0x12, 0x49, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, + 0x6e, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x65, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x05, + 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a, 0xbb, 0x01, + 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x12, 0x3c, 0x0a, 0x04, 0x6c, 0x65, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, 0x65, 0x67, 0x52, 0x04, 0x6c, 0x65, 0x67, 0x73, 0x12, + 0x5a, 0x0a, 0x11, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x6f, 0x6c, 0x79, + 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x52, 0x10, 0x6f, 0x76, 0x65, 0x72, 0x76, + 0x69, 0x65, 0x77, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0x6c, 0x0a, 0x10, 0x47, + 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x57, 0x61, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x27, 0x0a, 0x0f, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x55, 0x0a, 0x15, 0x44, 0x69, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0c, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0xe5, 0x04, 0x0a, 0x16, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, + 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x33, 0x0a, 0x15, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x04, 0x72, + 0x6f, 0x77, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0xbb, 0x02, 0x0a, 0x07, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x55, 0x0a, 0x08, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x55, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, + 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x64, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x1a, 0x34, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x34, 0x0a, + 0x08, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x1a, 0x53, 0x0a, 0x03, 0x52, 0x6f, 0x77, 0x12, 0x4c, 0x0a, 0x08, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x61, + 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x27, 0x0a, 0x0d, 0x47, 0x65, 0x6d, 0x69, + 0x6e, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, + 0x74, 0x22, 0xd5, 0x05, 0x0a, 0x0e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, + 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, + 0x12, 0x58, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, + 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x1a, 0x4c, 0x0a, 0x0c, 0x53, 0x61, + 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, + 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x1a, 0x21, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x1a, 0x61, 0x0a, 0x07, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x50, + 0x61, 0x72, 0x74, 0x52, 0x05, 0x70, 0x61, 0x72, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x1a, 0xe0, + 0x01, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x42, 0x0a, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x52, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x54, 0x0a, 0x0e, 0x73, + 0x61, 0x66, 0x65, 0x74, 0x79, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x61, 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x52, 0x0d, 0x73, 0x61, 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x1a, 0x66, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x12, 0x54, 0x0a, 0x0e, 0x73, 0x61, 0x66, 0x65, 0x74, 0x79, 0x5f, 0x72, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, + 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x61, + 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0d, 0x73, 0x61, 0x66, 0x65, + 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x32, 0x5c, 0x0a, 0x0e, 0x45, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x08, 0x53, + 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0xdb, 0x03, 0x0a, 0x04, 0x4d, 0x61, 0x70, 0x73, + 0x12, 0x4e, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, + 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5d, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, + 0x12, 0x25, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x60, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x12, 0x25, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, + 0x63, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, + 0x11, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, + 0x69, 0x78, 0x12, 0x27, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, + 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x5e, 0x0a, 0x06, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x12, + 0x54, 0x0a, 0x0f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d, 0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x01, 0x5a, + 0x13, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x67, 0x72, 0x70, + 0x63, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_communication_proto_rawDescOnce sync.Once + file_communication_proto_rawDescData = file_communication_proto_rawDesc +) + +func file_communication_proto_rawDescGZIP() []byte { + file_communication_proto_rawDescOnce.Do(func() { + file_communication_proto_rawDescData = protoimpl.X.CompressGZIP(file_communication_proto_rawDescData) + }) + return file_communication_proto_rawDescData +} + +var file_communication_proto_msgTypes = make([]protoimpl.MessageInfo, 36) +var file_communication_proto_goTypes = []interface{}{ + (*HelloRequest)(nil), // 0: apiservice_proto.HelloRequest + (*HelloReply)(nil), // 1: apiservice_proto.HelloReply + (*GeocodeRequest)(nil), // 2: apiservice_proto.GeocodeRequest + (*GeocodeResponse)(nil), // 3: apiservice_proto.GeocodeResponse + (*SearchPlacesRequest)(nil), // 4: apiservice_proto.SearchPlacesRequest + (*Place)(nil), // 5: apiservice_proto.Place + (*SearchPlacesResponse)(nil), // 6: apiservice_proto.SearchPlacesResponse + (*PlaceDetailsRequest)(nil), // 7: apiservice_proto.PlaceDetailsRequest + (*PlaceDetailsResponse)(nil), // 8: apiservice_proto.PlaceDetailsResponse + (*DirectionsRequest)(nil), // 9: apiservice_proto.DirectionsRequest + (*DirectionsResponse)(nil), // 10: apiservice_proto.DirectionsResponse + (*DistanceMatrixRequest)(nil), // 11: apiservice_proto.DistanceMatrixRequest + (*DistanceMatrixResponse)(nil), // 12: apiservice_proto.DistanceMatrixResponse + (*GeminiRequest)(nil), // 13: apiservice_proto.GeminiRequest + (*GeminiResponse)(nil), // 14: apiservice_proto.GeminiResponse + (*GeocodeResponse_Location)(nil), // 15: apiservice_proto.GeocodeResponse.Location + (*GeocodeResponse_Result)(nil), // 16: apiservice_proto.GeocodeResponse.Result + (*Place_Location)(nil), // 17: apiservice_proto.Place.Location + (*Place_OpeningHours)(nil), // 18: apiservice_proto.Place.OpeningHours + (*Place_Photo)(nil), // 19: apiservice_proto.Place.Photo + (*DirectionsResponse_Distance)(nil), // 20: apiservice_proto.DirectionsResponse.Distance + (*DirectionsResponse_Duration)(nil), // 21: apiservice_proto.DirectionsResponse.Duration + (*DirectionsResponse_Polyline)(nil), // 22: apiservice_proto.DirectionsResponse.Polyline + (*DirectionsResponse_Step)(nil), // 23: apiservice_proto.DirectionsResponse.Step + (*DirectionsResponse_Leg)(nil), // 24: apiservice_proto.DirectionsResponse.Leg + (*DirectionsResponse_Route)(nil), // 25: apiservice_proto.DirectionsResponse.Route + (*DirectionsResponse_GeocodedWaypoint)(nil), // 26: apiservice_proto.DirectionsResponse.GeocodedWaypoint + (*DistanceMatrixResponse_Element)(nil), // 27: apiservice_proto.DistanceMatrixResponse.Element + (*DistanceMatrixResponse_Row)(nil), // 28: apiservice_proto.DistanceMatrixResponse.Row + (*DistanceMatrixResponse_Element_Duration)(nil), // 29: apiservice_proto.DistanceMatrixResponse.Element.Duration + (*DistanceMatrixResponse_Element_Distance)(nil), // 30: apiservice_proto.DistanceMatrixResponse.Element.Distance + (*GeminiResponse_SafetyRating)(nil), // 31: apiservice_proto.GeminiResponse.SafetyRating + (*GeminiResponse_ContentPart)(nil), // 32: apiservice_proto.GeminiResponse.ContentPart + (*GeminiResponse_Content)(nil), // 33: apiservice_proto.GeminiResponse.Content + (*GeminiResponse_Candidate)(nil), // 34: apiservice_proto.GeminiResponse.Candidate + (*GeminiResponse_PromptFeedback)(nil), // 35: apiservice_proto.GeminiResponse.PromptFeedback +} +var file_communication_proto_depIdxs = []int32{ + 16, // 0: apiservice_proto.GeocodeResponse.results:type_name -> apiservice_proto.GeocodeResponse.Result + 17, // 1: apiservice_proto.Place.geometry_location:type_name -> apiservice_proto.Place.Location + 18, // 2: apiservice_proto.Place.opening_hours:type_name -> apiservice_proto.Place.OpeningHours + 19, // 3: apiservice_proto.Place.photos:type_name -> apiservice_proto.Place.Photo + 5, // 4: apiservice_proto.SearchPlacesResponse.results:type_name -> apiservice_proto.Place + 5, // 5: apiservice_proto.PlaceDetailsResponse.result:type_name -> apiservice_proto.Place + 25, // 6: apiservice_proto.DirectionsResponse.routes:type_name -> apiservice_proto.DirectionsResponse.Route + 26, // 7: apiservice_proto.DirectionsResponse.geocoded_waypoints:type_name -> apiservice_proto.DirectionsResponse.GeocodedWaypoint + 28, // 8: apiservice_proto.DistanceMatrixResponse.rows:type_name -> apiservice_proto.DistanceMatrixResponse.Row + 34, // 9: apiservice_proto.GeminiResponse.candidates:type_name -> apiservice_proto.GeminiResponse.Candidate + 35, // 10: apiservice_proto.GeminiResponse.prompt_feedback:type_name -> apiservice_proto.GeminiResponse.PromptFeedback + 15, // 11: apiservice_proto.GeocodeResponse.Result.location:type_name -> apiservice_proto.GeocodeResponse.Location + 20, // 12: apiservice_proto.DirectionsResponse.Step.distance:type_name -> apiservice_proto.DirectionsResponse.Distance + 21, // 13: apiservice_proto.DirectionsResponse.Step.duration:type_name -> apiservice_proto.DirectionsResponse.Duration + 22, // 14: apiservice_proto.DirectionsResponse.Step.polyline:type_name -> apiservice_proto.DirectionsResponse.Polyline + 20, // 15: apiservice_proto.DirectionsResponse.Leg.distance:type_name -> apiservice_proto.DirectionsResponse.Distance + 21, // 16: apiservice_proto.DirectionsResponse.Leg.duration:type_name -> apiservice_proto.DirectionsResponse.Duration + 23, // 17: apiservice_proto.DirectionsResponse.Leg.steps:type_name -> apiservice_proto.DirectionsResponse.Step + 24, // 18: apiservice_proto.DirectionsResponse.Route.legs:type_name -> apiservice_proto.DirectionsResponse.Leg + 22, // 19: apiservice_proto.DirectionsResponse.Route.overview_polyline:type_name -> apiservice_proto.DirectionsResponse.Polyline + 29, // 20: apiservice_proto.DistanceMatrixResponse.Element.duration:type_name -> apiservice_proto.DistanceMatrixResponse.Element.Duration + 30, // 21: apiservice_proto.DistanceMatrixResponse.Element.distance:type_name -> apiservice_proto.DistanceMatrixResponse.Element.Distance + 27, // 22: apiservice_proto.DistanceMatrixResponse.Row.elements:type_name -> apiservice_proto.DistanceMatrixResponse.Element + 32, // 23: apiservice_proto.GeminiResponse.Content.parts:type_name -> apiservice_proto.GeminiResponse.ContentPart + 33, // 24: apiservice_proto.GeminiResponse.Candidate.content:type_name -> apiservice_proto.GeminiResponse.Content + 31, // 25: apiservice_proto.GeminiResponse.Candidate.safety_ratings:type_name -> apiservice_proto.GeminiResponse.SafetyRating + 31, // 26: apiservice_proto.GeminiResponse.PromptFeedback.safety_ratings:type_name -> apiservice_proto.GeminiResponse.SafetyRating + 0, // 27: apiservice_proto.ExampleGreeter.SayHello:input_type -> apiservice_proto.HelloRequest + 2, // 28: apiservice_proto.Maps.Geocode:input_type -> apiservice_proto.GeocodeRequest + 4, // 29: apiservice_proto.Maps.SearchPlaces:input_type -> apiservice_proto.SearchPlacesRequest + 7, // 30: apiservice_proto.Maps.GetPlaceDetails:input_type -> apiservice_proto.PlaceDetailsRequest + 9, // 31: apiservice_proto.Maps.GetDirections:input_type -> apiservice_proto.DirectionsRequest + 11, // 32: apiservice_proto.Maps.GetDistanceMatrix:input_type -> apiservice_proto.DistanceMatrixRequest + 13, // 33: apiservice_proto.Gemini.GenerateContent:input_type -> apiservice_proto.GeminiRequest + 1, // 34: apiservice_proto.ExampleGreeter.SayHello:output_type -> apiservice_proto.HelloReply + 3, // 35: apiservice_proto.Maps.Geocode:output_type -> apiservice_proto.GeocodeResponse + 6, // 36: apiservice_proto.Maps.SearchPlaces:output_type -> apiservice_proto.SearchPlacesResponse + 8, // 37: apiservice_proto.Maps.GetPlaceDetails:output_type -> apiservice_proto.PlaceDetailsResponse + 10, // 38: apiservice_proto.Maps.GetDirections:output_type -> apiservice_proto.DirectionsResponse + 12, // 39: apiservice_proto.Maps.GetDistanceMatrix:output_type -> apiservice_proto.DistanceMatrixResponse + 14, // 40: apiservice_proto.Gemini.GenerateContent:output_type -> apiservice_proto.GeminiResponse + 34, // [34:41] is the sub-list for method output_type + 27, // [27:34] is the sub-list for method input_type + 27, // [27:27] is the sub-list for extension type_name + 27, // [27:27] is the sub-list for extension extendee + 0, // [0:27] is the sub-list for field type_name +} + +func init() { file_communication_proto_init() } +func file_communication_proto_init() { + if File_communication_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_communication_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HelloRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HelloReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchPlacesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchPlacesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlaceDetailsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlaceDetailsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeResponse_Location); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeResponse_Result); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place_Location); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place_OpeningHours); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place_Photo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Distance); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Duration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Polyline); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Step); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Leg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Route); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_GeocodedWaypoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Element); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Row); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Element_Duration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Element_Distance); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_SafetyRating); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_ContentPart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_Content); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_Candidate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_PromptFeedback); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_communication_proto_rawDesc, + NumEnums: 0, + NumMessages: 36, + NumExtensions: 0, + NumServices: 3, + }, + GoTypes: file_communication_proto_goTypes, + DependencyIndexes: file_communication_proto_depIdxs, + MessageInfos: file_communication_proto_msgTypes, + }.Build() + File_communication_proto = out.File + file_communication_proto_rawDesc = nil + file_communication_proto_goTypes = nil + file_communication_proto_depIdxs = nil +} diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..64b3343 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,289 @@ +#!/bin/bash + +set -e + +# Define Colors +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +spinner() { + local pid=$1 + local message="${2:-Building...}" # Default message if not provided + local delay=0.1 + local spinstr='|/-\' + echo -n -e "${YELLOW}${message} ${NC}" + while ps -p "$pid" > /dev/null; do + local temp_spinstr=${spinstr#?} + printf "[%c]" "$spinstr" + spinstr="$temp_spinstr${spinstr%"$temp_spinstr"}" # Rotate spinner + sleep $delay + printf "\b\b\b" # Erase the spinner + done + wait "$pid" # Wait for the process to finish and get its exit code + local exit_code=$? + if [ $exit_code -eq 0 ]; then + echo -e "\r${GREEN}${message} [OK]${NC} " # Success + else + echo -e "\r${RED}${message} [FAIL]${NC} " # Fail + fi + return $exit_code # Return the exit code of the command +} + +log_message() { + local message="$1" + local color="${2:-$NC}" # Default to No Color if not specified + echo -e "${color}[$(date '+%Y-%m-%d %H:%M:%S')] ${message}${NC}" +} + +SECTION_SEPARATOR="========================================================================" + +COMPOSE_FILE="deploy/docker-compose.yml" + +SERVICES=( + "auth-service" + "api-gateway" + "api-service" + "planning-service" + "social-media-service" +) + + +usage() { + echo -e "${BLUE}Usage: $0 [--build] [--run] [--up] [--down] [--logs] [--status] [--force-rebuild] [service1 service2 ...]${NC}" + echo " --help, -h Show this help message and exit" + echo " --up Build and then run services (equivalent to --build --run)" + echo " --build Build only" + echo " --run Run only" + echo " --down Stop and remove all services defined in the compose file" + echo " --logs [service...] View logs for specified services (or all if none specified)" + echo " --status Show the status of services" + echo " --force-rebuild Force rebuild of images without using cache" + echo " [service ...] Optional list of services to target" + echo + echo "Examples:" + echo " $0 # Build and run all" + echo " $0 --build # Build all" + echo " $0 --run # Run all" + echo " $0 --build api-gateway" + echo " $0 --run api-gateway department-service" + exit 1 +} + +BUILD=false +RUN=false +DOWN_CMD=false +LOGS_CMD=false +STATUS_CMD=false +FORCE_REBUILD=false + +# Parse flags +while [[ $# -gt 0 ]]; do + case "$1" in + --help|-h) + usage + exit 0 + ;; + --up) + BUILD=true + RUN=true + shift + ;; + --build) + BUILD=true + shift + ;; + --run) + RUN=true + shift + ;; + --down) + DOWN_CMD=true + shift + ;; + --logs) + LOGS_CMD=true + shift + ;; + --status) + STATUS_CMD=true + shift + ;; + --force-rebuild) + FORCE_REBUILD=true + shift + ;; + -*) + usage + ;; + *) + break + ;; + esac +done + +# If no operational flags specified and no services listed, default to build and run all. +if [ "$BUILD" = false ] && [ "$RUN" = false ] && [ "$DOWN_CMD" = false ] && [ "$LOGS_CMD" = false ] && [ "$STATUS_CMD" = false ] && [ $# -eq 0 ]; then + BUILD=true + RUN=true + TARGET_SERVICES=("${SERVICES[@]}") # Ensure TARGET_SERVICES is set for default all +elif [ $# -gt 0 ]; then # Services are listed (these are remaining arguments after flags) + TARGET_SERVICES=("$@") +else # Some flags were specified, but no services - applies to all services + TARGET_SERVICES=("${SERVICES[@]}") +fi + +# If no TARGET_SERVICES determined (e.g. only flags like --build passed, no specific services), set to all. +if [ ${#TARGET_SERVICES[@]} -eq 0 ]; then + TARGET_SERVICES=("${SERVICES[@]}") +fi + +# Down command block +if $DOWN_CMD; then + log_message "Starting Shutdown Process" "$BLUE" + echo "$SECTION_SEPARATOR" + log_message "๐Ÿ”ฝ Stopping and removing all services defined in $COMPOSE_FILE..." "$BLUE" + docker-compose -f "$COMPOSE_FILE" down + log_message "โœ… All services stopped and removed." "$GREEN" + echo "$SECTION_SEPARATOR" + log_message "Shutdown Process Completed" "$GREEN" + # If only --down was specified (and no other action flags), exit. + if ! $BUILD && ! $RUN ; then + exit 0 + fi +fi + +# Validate service names +for svc in "${TARGET_SERVICES[@]}"; do + if [[ ! " ${SERVICES[@]} " =~ " ${svc} " ]]; then + echo -e "${RED}โŒ Unknown service: $svc${NC}" + echo -e "${GREEN}โœ… Known services: ${SERVICES[*]}${NC}" + exit 1 + fi +done + +# Build block +if $BUILD; then + log_message "Starting Build Process" "$BLUE" + echo "$SECTION_SEPARATOR" + # echo -e "${BLUE}๐Ÿ”จ Building: ${TARGET_SERVICES[*]}${NC}" # Original overall message, now handled by log_message + for svc in "${TARGET_SERVICES[@]}"; do + if [ -f "$svc/pom.xml" ]; then + log_message "๐Ÿ“ฆ Running Maven build for $svc..." "$YELLOW" + (cd "$svc" && mvn clean package -DskipTests) + elif [ -f "$svc/build.gradle" ]; then + log_message "๐Ÿ“ฆ Running Gradle build for $svc..." "$YELLOW" + (cd "$svc" && ./gradlew bootJar --no-daemon) + else + log_message "โ„น๏ธ Skipping Maven/Gradle build for $svc (no pom.xml or build.gradle)" "$YELLOW" + fi + + build_cmd_array=() # Declare as a regular array + build_cmd_array+=("docker-compose" "-f" "$COMPOSE_FILE" "build") + if $FORCE_REBUILD; then + build_cmd_array+=("--no-cache") + log_message "โ„น๏ธ Force rebuild enabled for $svc (using --no-cache)." "$YELLOW" + fi + build_cmd_array+=("$svc") + + # Run the build command + ("${build_cmd_array[@]}") & + spinner $! "๐Ÿณ Building Docker image for $svc" + if [ $? -ne 0 ]; then + # Spinner already prints FAIL, this adds more context and exits + log_message "โŒ Docker build failed for $svc. Aborting." "$RED" + exit 1 # Exit if build fails, respecting set -e implicitly + fi + done + echo "$SECTION_SEPARATOR" + log_message "Build Process Completed" "$GREEN" +fi + +# Run block +if $RUN; then + log_message "Starting Services" "$BLUE" + echo "$SECTION_SEPARATOR" + log_message "๐Ÿš€ Starting: ${TARGET_SERVICES[*]}" "$BLUE" + docker-compose -f "$COMPOSE_FILE" up -d "${TARGET_SERVICES[@]}" + echo "$SECTION_SEPARATOR" + log_message "Services Startup Initiated" "$GREEN" + + log_message "Exposed Port Mappings:" "$BLUE" + echo "$SECTION_SEPARATOR" + + service_ports_info="" + # current_service="" # Removed as unused + in_service_block=false + in_ports_block=false + + for svc_name in "${TARGET_SERVICES[@]}"; do + service_ports_info="" + service_ports_info=$(awk -v service="$svc_name" ' + BEGIN { + in_service = 0; + in_ports = 0; + service_header_printed = 0; + } + $1 == service":" { + in_service = 1; + next; + } + in_service && /^[[:space:]]+ports:/ { + in_ports = 1; + next; + } + in_service && in_ports && /^[[:space:]]+-/ { + if (!service_header_printed) { + print " " service ":"; + service_header_printed = 1; + } + sub(/^[[:space:]]+- +/, " - "); + print; + next; + } + in_service && in_ports && (!/^[[:space:]]+/ || $1 ~ /^[a-zA-Z0-9_-]+:/) { + in_ports = 0; + in_service = 0; + } + in_service && !in_ports && $1 ~ /^[a-zA-Z0-9_-]+:/ && $1 != service":" { + in_service = 0; + } + ' "$COMPOSE_FILE") + + if [ -n "$service_ports_info" ]; then + log_message "$service_ports_info" "$GREEN" + else + log_message " $svc_name: No port mappings found or error in parsing." "$YELLOW" + fi + done + echo "$SECTION_SEPARATOR" +fi + +# Logs command block +if $LOGS_CMD; then + log_message "Fetching Logs" "$BLUE" + echo "$SECTION_SEPARATOR" + # TARGET_SERVICES should be already set by prior logic (either to specific services or all) + log_message "๐Ÿ“„ Fetching logs for: ${TARGET_SERVICES[*]}..." "$BLUE" + docker-compose -f "$COMPOSE_FILE" logs -f "${TARGET_SERVICES[@]}" + # If only --logs was specified (and no other action flags like build, run, down), then exit. + if ! $BUILD && ! $RUN && ! $DOWN_CMD; then + exit 0 + fi +fi + +# Status command block +if $STATUS_CMD; then + log_message "Checking Service Status" "$BLUE" + echo "$SECTION_SEPARATOR" + log_message "โ„น๏ธ Service Status for: ${TARGET_SERVICES[*]}..." "$BLUE" + docker-compose -f "$COMPOSE_FILE" ps "${TARGET_SERVICES[@]}" + echo "$SECTION_SEPARATOR" # Add this + log_message "Service Status Check Completed" "$GREEN" # Add this + # If only --status was specified, exit. + if ! $BUILD && ! $RUN && ! $DOWN_CMD && ! $LOGS_CMD; then + exit 0 + fi +fi \ No newline at end of file diff --git a/deploy/Dockerfile.springboot b/deploy/Dockerfile.springboot new file mode 100644 index 0000000..b795b1b --- /dev/null +++ b/deploy/Dockerfile.springboot @@ -0,0 +1,18 @@ +# Use an OpenJDK base image +FROM openjdk:17-jdk-slim + +# Install curl (required for wait-for-Keycloak logic) +RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* + + +# Add a volume for logs (optional) +VOLUME /tmp + +# Copy the built JAR file +COPY build/libs/*.jar app.jar + +# Expose the port on which the service runs +EXPOSE 8080 + +# Run the application +ENTRYPOINT ["java", "-jar", "/app.jar"] \ No newline at end of file diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000..c36015b --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,183 @@ +x-kong-env: &kong-env + KONG_DATABASE: postgres + KONG_PG_DATABASE: kong + KONG_PG_HOST: kong-database + KONG_PG_USER: kong + KONG_PG_PASSWORD: kong + +volumes: + kong_data: {} + kong_prefix_vol: + driver_opts: + type: tmpfs + device: tmpfs + kong_tmp_vol: + driver: local + driver_opts: + type: tmpfs + device: tmpfs + keycloak_data: {} + +networks: + kong-net: + ipam: + config: + - subnet: 172.30.0.0/16 + +services: + kong-database: + image: postgres:16-alpine + environment: + POSTGRES_DB: kong + POSTGRES_USER: kong + POSTGRES_PASSWORD: kong + volumes: + - kong_data:/var/lib/postgresql/data + networks: + - kong-net + healthcheck: + test: ["CMD", "pg_isready", "-d", "kong", "-U", "kong"] + interval: 30s + timeout: 10s + retries: 3 + restart: unless-stopped + + kong-migrations: + image: kong:3.5 + command: kong migrations bootstrap + environment: + <<: *kong-env + networks: + - kong-net + depends_on: + kong-database: + condition: service_healthy + restart: on-failure + + api-gateway: + image: kong:3.5 + user: kong + environment: + <<: *kong-env + KONG_ADMIN_ACCESS_LOG: /dev/stdout + KONG_ADMIN_ERROR_LOG: /dev/stderr + KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl + KONG_ADMIN_LISTEN: 0.0.0.0:8001 + KONG_PROXY_ACCESS_LOG: /dev/stdout + KONG_PROXY_ERROR_LOG: /dev/stderr + KONG_PREFIX: /var/run/kong + KONG_TRACING_INSTRUMENTATIONS: request + ports: + - "8000:8000" + - "8443:8443" + - "8001:8001" + - "8444:8444" + networks: + - kong-net + restart: on-failure + read_only: true + volumes: + - kong_prefix_vol:/var/run/kong + - kong_tmp_vol:/tmp + security_opt: + - no-new-privileges + depends_on: + kong-database: + condition: service_healthy + kong-migrations: + condition: service_completed_successfully + + auth-service: + build: + context: . + dockerfile: ../auth-service/Dockerfile.keycloak + command: + - start-dev + - --http-enabled=true + - --http-host=0.0.0.0 + - --hostname-strict=false + - --hostname-strict-https=false + # - --hostname=auth-service + # - --http-port=8080 + - --hostname=gotogetheruom.duckdns.org + - --http-port=8084 + - --https-port=8443 + environment: + KC_DB: postgres + KC_DB_URL: "jdbc:postgresql://aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres?sslmode=require&connectTimeout=10" + KC_DB_USERNAME: postgres.ucutsnncgapnsylikrxk + KC_DB_PASSWORD: Postgres@2025 + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + # KC_HOSTNAME_URL: http://localhost:8084 + # KC_HOSTNAME_URL: http://auth-service:8080 + KC_HTTPS_CERTIFICATE_FILE: /opt/keycloak/certs/fullchain.pem + KC_HTTPS_CERTIFICATE_KEY_FILE: /opt/keycloak/certs/privkey.pem + KC_HOSTNAME_URL: https://gotogetheruom.duckdns.org:8446 + KEYCLOAK_IMPORT: /opt/keycloak/data/import/kong-realm.json + volumes: + - ../auth-service/keycloak-import:/opt/keycloak/data/import + - keycloak_data:/opt/keycloak/data + - /etc/letsencrypt/archive/gotogetheruom.duckdns.org/fullchain1.pem:/opt/keycloak/certs/fullchain.pem:ro + - /etc/letsencrypt/archive/gotogetheruom.duckdns.org/privkey1.pem:/opt/keycloak/certs/privkey.pem:ro + networks: + - kong-net + ports: + - "8084:8080" + - "8446:8443" + + planning-service: + build: + context: ../planning-service + dockerfile: ../deploy/Dockerfile.springboot + ports: + - "8086:8081" + environment: + - SPRING_PROFILES_ACTIVE=docker + networks: + - kong-net + + social-media-service: + build: + context: ../social-media-service + # dockerfile: ../social-media-service/Dockerfile + ports: + - "8080:8080" + env_file: + - ../social-media-service/.env + environment: + - SPRING_PROFILES_ACTIVE=docker + networks: + - kong-net + depends_on: + - auth-service + # auth-service: + # condition: service_healthy + command: > + sh -c " + echo 'Waiting for Keycloak to be ready...' && + until curl -sSf http://auth-service:8080/realms/kong/.well-known/openid-configuration; do + echo 'Waiting for realm kong...'; + sleep 5; + done && + until curl -sSf -k https://gotogetheruom.duckdns.org:8446/realms/kong/.well-known/openid-configuration; do + echo 'Waiting for realm kong...'; + sleep 5; + done && + echo 'Keycloak realm is ready. Starting app...' && + java -jar /app/social-media-service.jar + " + + api-service: + build: + context: ../api-service + dockerfile: Dockerfile + ports: + - "8083:8000" + - "50051:50051" + env_file: + - ../api-service/.env + environment: + - GIN_MODE=release + networks: + - kong-net diff --git a/deploy/env.sh b/deploy/env.sh new file mode 100644 index 0000000..441d279 --- /dev/null +++ b/deploy/env.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e + +echo "๐Ÿ“ Creating .env for api-service..." +cat < ../api-service/.env +GOOGLE_MAPS_API_KEY=AIzaSyBqQhDKu98x-nZO85f-JVoUGgNUw2W_SWE +GOOGLE_GEMINI_API_KEY=AIzaSyAb08virZswAtMDNWXGGfBxM8ECwmFQS1w +PORT=8000 +EOT +echo "โœ… Created ../api-service/.env" + +echo "๐Ÿ“ Creating .env for social-media-service..." +cat < ../social-media-service/.env +CLIENT_ID=785994007278-lr2k84dv19513frlhkid2dvnf396mpa0.apps.googleusercontent.com +CLIENT_SECRET=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 +baseUrl=http://localhost:8080 +registrationId=keycloak +EOT +echo "โœ… Created ../social-media-service/.env" diff --git a/deploy/keycloak-setup.sh b/deploy/keycloak-setup.sh new file mode 100644 index 0000000..ae1ce2d --- /dev/null +++ b/deploy/keycloak-setup.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# Start Keycloak in background +/opt/keycloak/bin/kc.sh start-dev \ + --http-enabled=true \ + --hostname-strict=false \ + --hostname-strict-https=false & +KEYCLOAK_PID=$! + +# Wait for Keycloak to become ready +echo "โณ Waiting for Keycloak to start (checking kcadm connection)..." +until /opt/keycloak/bin/kcadm.sh config credentials \ + --server http://localhost:8080 \ + --realm master \ + --user ${KEYCLOAK_ADMIN:-admin} \ + --password ${KEYCLOAK_ADMIN_PASSWORD:-admin} \ + --config /tmp/kcadm.config >/dev/null 2>&1; do + sleep 2 +done +echo "โœ… Keycloak is up and authenticated." + +# Disable SSL requirement in master realm +/opt/keycloak/bin/kcadm.sh update realms/master \ + -s sslRequired=NONE \ + --config /tmp/kcadm.config + +# โœ… Import the realm file if it exists +if [ -f "/opt/keycloak/data/import/kong-realm.json" ]; then + echo "๐Ÿ“ฆ Importing realm from kong-realm.json..." + /opt/keycloak/bin/kcadm.sh create realms \ + -f /opt/keycloak/data/import/kong-realm.json \ + --config /tmp/kcadm.config || echo "โš ๏ธ Realm import may have failed or already exists." +else + echo "โŒ kong-realm.json not found at /opt/keycloak/data/import/" +fi + +# Keep Keycloak running +wait $KEYCLOAK_PID diff --git a/deploy/setup-nginx-ssl.sh b/deploy/setup-nginx-ssl.sh new file mode 100644 index 0000000..c287060 --- /dev/null +++ b/deploy/setup-nginx-ssl.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +set -e + +DOMAIN="gotogetheruom.duckdns.org" +NGINX_CONF="/etc/nginx/conf.d/backend.conf" + +echo "๐Ÿ”ง Installing NGINX..." +sudo dnf install -y nginx + +echo "๐Ÿ”ง Enabling and starting NGINX..." +sudo systemctl enable nginx +sudo systemctl start nginx + +echo "๐Ÿ“ Creating NGINX reverse proxy config..." +sudo tee $NGINX_CONF > /dev/null <<'EOF' +# Redirect HTTP to HTTPS +server { + listen 80; + server_name gotogetheruom.duckdns.org; + + location / { + return 301 https://$host$request_uri; + } +} + +# HTTPS reverse proxy +server { + listen 443 ssl; + server_name gotogetheruom.duckdns.org; + + ssl_certificate /etc/letsencrypt/live/gotogetheruom.duckdns.org/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/gotogetheruom.duckdns.org/privkey.pem; + + location /api/ { + proxy_pass http://127.0.0.1:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # location /auth/ { + # rewrite ^/auth/(.*)$ /$1 break; + + # proxy_pass http://127.0.0.1:8084/; + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $scheme; + + # proxy_http_version 1.1; + # proxy_set_header Upgrade $http_upgrade; + # proxy_set_header Connection "upgrade"; + + # # Rewriting internal paths in HTML responses to use /auth/ prefix + # sub_filter_once off; + # sub_filter_types text/html; + + # sub_filter 'href="/' 'href="/auth/'; + # sub_filter 'src="/' 'src="/auth/'; + # sub_filter 'action="/' 'action="/auth/'; + # } + + location / { + return 404; + } +} +EOF + +echo "๐Ÿ”“ Configuring firewall rules...." +sudo firewall-cmd --add-service=http --permanent +sudo firewall-cmd --add-service=https --permanent +sudo firewall-cmd --reload + +echo "๐Ÿ” Testing and restarting NGINX..." +sudo nginx -t && sudo systemctl restart nginx + +echo "๐ŸŽ‰ HTTPS reverse proxy is live at https://$DOMAIN" + +# sudo dnf install epel-release -y # Just in case +# sudo dnf install snapd -y +# sudo systemctl enable --now snapd.socket +# sudo ln -s /var/lib/snapd/snap /snap + +# # Restart shell to pick up `snap` +# exec "$SHELL" + +# # Install Certbot +# sudo snap install core +# sudo snap refresh core +# sudo snap install --classic certbot + +# # Link certbot +# sudo ln -s /snap/bin/certbot /usr/bin/certbot + +# # Now install nginx plugin (optional if you're using certbot directly with nginx) +# sudo snap set certbot trust-plugin-with-root=ok +# sudo snap install certbot-dns-cloudflare # optional, only if using Cloudflare + +# sudo dnf install python3-pip -y +# pip3 install certbot certbot-nginx --break-system-packages + + +# sudo certbot --nginx diff --git a/deploy/setup.sh b/deploy/setup.sh new file mode 100644 index 0000000..b1c9b8a --- /dev/null +++ b/deploy/setup.sh @@ -0,0 +1,34 @@ +# #!/bin/bash +# set -e + +# echo "๐ŸŸข Updating system..." +# sudo dnf update -y + +# echo "๐Ÿ“ฆ Installing Git..." +# sudo dnf install -y git + +# echo "โ˜• Installing Java 17 (OpenJDK)..." +# sudo dnf install -y java-17-openjdk-devel + +# echo "โœ… Setting JAVA_HOME..." +# JAVA_PATH=$(dirname $(dirname $(readlink -f $(which java)))) +# echo "export JAVA_HOME=$JAVA_PATH" | sudo tee -a /etc/profile.d/java.sh +# echo "export PATH=\$JAVA_HOME/bin:\$PATH" | sudo tee -a /etc/profile.d/java.sh +# source /etc/profile.d/java.sh + +# echo "๐Ÿงช Verifying Java..." +# java -version +# echo "JAVA_HOME=$JAVA_HOME" + +# echo "๐Ÿณ Installing Docker..." +# sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo +# sudo dnf install -y docker-ce docker-ce-cli containerd.io +# sudo systemctl enable --now docker + +# echo "๐Ÿณ Installing Docker Compose..." +# sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose +# sudo chmod +x /usr/local/bin/docker-compose + +# echo "โœ… All setup complete!" +sudo ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose +docker-compose version diff --git a/grpc/pb/communication.pb.go b/grpc/pb/communication.pb.go new file mode 100644 index 0000000..7edc974 --- /dev/null +++ b/grpc/pb/communication.pb.go @@ -0,0 +1,2972 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.12 +// source: communication.proto + +package pb + +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) +) + +// The request message containing the user's name. +type HelloRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *HelloRequest) Reset() { + *x = HelloRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloRequest) ProtoMessage() {} + +func (x *HelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. +func (*HelloRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{0} +} + +func (x *HelloRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// The response message containing the greetings +type HelloReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *HelloReply) Reset() { + *x = HelloReply{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HelloReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloReply) ProtoMessage() {} + +func (x *HelloReply) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. +func (*HelloReply) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{1} +} + +func (x *HelloReply) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type GeocodeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (x *GeocodeRequest) Reset() { + *x = GeocodeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeRequest) ProtoMessage() {} + +func (x *GeocodeRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeRequest.ProtoReflect.Descriptor instead. +func (*GeocodeRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{2} +} + +func (x *GeocodeRequest) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +type GeocodeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Results []*GeocodeResponse_Result `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "ZERO_RESULTS" +} + +func (x *GeocodeResponse) Reset() { + *x = GeocodeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse) ProtoMessage() {} + +func (x *GeocodeResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeResponse.ProtoReflect.Descriptor instead. +func (*GeocodeResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{3} +} + +func (x *GeocodeResponse) GetResults() []*GeocodeResponse_Result { + if x != nil { + return x.Results + } + return nil +} + +func (x *GeocodeResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type SearchPlacesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` // Text string to search for + Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` // Lat,Lng coordinates (e.g., "37.4224764,-122.0842499") +} + +func (x *SearchPlacesRequest) Reset() { + *x = SearchPlacesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[4] + 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_communication_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchPlacesRequest.ProtoReflect.Descriptor instead. +func (*SearchPlacesRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{4} +} + +func (x *SearchPlacesRequest) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *SearchPlacesRequest) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +type Place 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"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Vicinity string `protobuf:"bytes,3,opt,name=vicinity,proto3" json:"vicinity,omitempty"` // Or address + Rating float64 `protobuf:"fixed64,4,opt,name=rating,proto3" json:"rating,omitempty"` + UserRatingsTotal int32 `protobuf:"varint,5,opt,name=user_ratings_total,json=userRatingsTotal,proto3" json:"user_ratings_total,omitempty"` + GeometryLocation *Place_Location `protobuf:"bytes,6,opt,name=geometry_location,json=geometryLocation,proto3" json:"geometry_location,omitempty"` // Simplified, directly embedding Location + OpeningHours *Place_OpeningHours `protobuf:"bytes,7,opt,name=opening_hours,json=openingHours,proto3" json:"opening_hours,omitempty"` + Photos []*Place_Photo `protobuf:"bytes,8,rep,name=photos,proto3" json:"photos,omitempty"` + PhotoUrls []string `protobuf:"bytes,9,rep,name=photo_urls,json=photoUrls,proto3" json:"photo_urls,omitempty"` // New field from existing API + Types []string `protobuf:"bytes,10,rep,name=types,proto3" json:"types,omitempty"` +} + +func (x *Place) Reset() { + *x = Place{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place) ProtoMessage() {} + +func (x *Place) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place.ProtoReflect.Descriptor instead. +func (*Place) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5} +} + +func (x *Place) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *Place) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Place) GetVicinity() string { + if x != nil { + return x.Vicinity + } + return "" +} + +func (x *Place) GetRating() float64 { + if x != nil { + return x.Rating + } + return 0 +} + +func (x *Place) GetUserRatingsTotal() int32 { + if x != nil { + return x.UserRatingsTotal + } + return 0 +} + +func (x *Place) GetGeometryLocation() *Place_Location { + if x != nil { + return x.GeometryLocation + } + return nil +} + +func (x *Place) GetOpeningHours() *Place_OpeningHours { + if x != nil { + return x.OpeningHours + } + return nil +} + +func (x *Place) GetPhotos() []*Place_Photo { + if x != nil { + return x.Photos + } + return nil +} + +func (x *Place) GetPhotoUrls() []string { + if x != nil { + return x.PhotoUrls + } + return nil +} + +func (x *Place) GetTypes() []string { + if x != nil { + return x.Types + } + return nil +} + +type SearchPlacesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Results []*Place `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "ZERO_RESULTS" +} + +func (x *SearchPlacesResponse) Reset() { + *x = SearchPlacesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[6] + 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_communication_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchPlacesResponse.ProtoReflect.Descriptor instead. +func (*SearchPlacesResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{6} +} + +func (x *SearchPlacesResponse) GetResults() []*Place { + if x != nil { + return x.Results + } + return nil +} + +func (x *SearchPlacesResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type PlaceDetailsRequest 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 *PlaceDetailsRequest) Reset() { + *x = PlaceDetailsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlaceDetailsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlaceDetailsRequest) ProtoMessage() {} + +func (x *PlaceDetailsRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlaceDetailsRequest.ProtoReflect.Descriptor instead. +func (*PlaceDetailsRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{7} +} + +func (x *PlaceDetailsRequest) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +// Using the existing Place message for the main result, but we need a wrapper for the "result" field and status. +type PlaceDetailsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result *Place `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` // Contains most of the details + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "NOT_FOUND" +} + +func (x *PlaceDetailsResponse) Reset() { + *x = PlaceDetailsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlaceDetailsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlaceDetailsResponse) ProtoMessage() {} + +func (x *PlaceDetailsResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlaceDetailsResponse.ProtoReflect.Descriptor instead. +func (*PlaceDetailsResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{8} +} + +func (x *PlaceDetailsResponse) GetResult() *Place { + if x != nil { + return x.Result + } + return nil +} + +func (x *PlaceDetailsResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type DirectionsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Origin string `protobuf:"bytes,1,opt,name=origin,proto3" json:"origin,omitempty"` + Destination string `protobuf:"bytes,2,opt,name=destination,proto3" json:"destination,omitempty"` +} + +func (x *DirectionsRequest) Reset() { + *x = DirectionsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsRequest) ProtoMessage() {} + +func (x *DirectionsRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsRequest.ProtoReflect.Descriptor instead. +func (*DirectionsRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{9} +} + +func (x *DirectionsRequest) GetOrigin() string { + if x != nil { + return x.Origin + } + return "" +} + +func (x *DirectionsRequest) GetDestination() string { + if x != nil { + return x.Destination + } + return "" +} + +type DirectionsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Routes []*DirectionsResponse_Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + GeocodedWaypoints []*DirectionsResponse_GeocodedWaypoint `protobuf:"bytes,2,rep,name=geocoded_waypoints,json=geocodedWaypoints,proto3" json:"geocoded_waypoints,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "NOT_FOUND" +} + +func (x *DirectionsResponse) Reset() { + *x = DirectionsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse) ProtoMessage() {} + +func (x *DirectionsResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse.ProtoReflect.Descriptor instead. +func (*DirectionsResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10} +} + +func (x *DirectionsResponse) GetRoutes() []*DirectionsResponse_Route { + if x != nil { + return x.Routes + } + return nil +} + +func (x *DirectionsResponse) GetGeocodedWaypoints() []*DirectionsResponse_GeocodedWaypoint { + if x != nil { + return x.GeocodedWaypoints + } + return nil +} + +func (x *DirectionsResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type DistanceMatrixRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Origins string `protobuf:"bytes,1,opt,name=origins,proto3" json:"origins,omitempty"` // Pipe-separated + Destinations string `protobuf:"bytes,2,opt,name=destinations,proto3" json:"destinations,omitempty"` // Pipe-separated +} + +func (x *DistanceMatrixRequest) Reset() { + *x = DistanceMatrixRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixRequest) ProtoMessage() {} + +func (x *DistanceMatrixRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixRequest.ProtoReflect.Descriptor instead. +func (*DistanceMatrixRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{11} +} + +func (x *DistanceMatrixRequest) GetOrigins() string { + if x != nil { + return x.Origins + } + return "" +} + +func (x *DistanceMatrixRequest) GetDestinations() string { + if x != nil { + return x.Destinations + } + return "" +} + +type DistanceMatrixResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Based on Google's API: origin_addresses and destination_addresses are top-level + OriginAddresses []string `protobuf:"bytes,1,rep,name=origin_addresses,json=originAddresses,proto3" json:"origin_addresses,omitempty"` + DestinationAddresses []string `protobuf:"bytes,2,rep,name=destination_addresses,json=destinationAddresses,proto3" json:"destination_addresses,omitempty"` + Rows []*DistanceMatrixResponse_Row `protobuf:"bytes,3,rep,name=rows,proto3" json:"rows,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` // Overall status for the request, not explicitly in current Go model but good to have. +} + +func (x *DistanceMatrixResponse) Reset() { + *x = DistanceMatrixResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse) ProtoMessage() {} + +func (x *DistanceMatrixResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12} +} + +func (x *DistanceMatrixResponse) GetOriginAddresses() []string { + if x != nil { + return x.OriginAddresses + } + return nil +} + +func (x *DistanceMatrixResponse) GetDestinationAddresses() []string { + if x != nil { + return x.DestinationAddresses + } + return nil +} + +func (x *DistanceMatrixResponse) GetRows() []*DistanceMatrixResponse_Row { + if x != nil { + return x.Rows + } + return nil +} + +func (x *DistanceMatrixResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +type GeminiRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Prompt string `protobuf:"bytes,1,opt,name=prompt,proto3" json:"prompt,omitempty"` +} + +func (x *GeminiRequest) Reset() { + *x = GeminiRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiRequest) ProtoMessage() {} + +func (x *GeminiRequest) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiRequest.ProtoReflect.Descriptor instead. +func (*GeminiRequest) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{13} +} + +func (x *GeminiRequest) GetPrompt() string { + if x != nil { + return x.Prompt + } + return "" +} + +type GeminiResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Candidates []*GeminiResponse_Candidate `protobuf:"bytes,1,rep,name=candidates,proto3" json:"candidates,omitempty"` + PromptFeedback *GeminiResponse_PromptFeedback `protobuf:"bytes,2,opt,name=prompt_feedback,json=promptFeedback,proto3" json:"prompt_feedback,omitempty"` // UsageMetadata usage_metadata = 3; // If token count, etc., is needed +} + +func (x *GeminiResponse) Reset() { + *x = GeminiResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse) ProtoMessage() {} + +func (x *GeminiResponse) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse.ProtoReflect.Descriptor instead. +func (*GeminiResponse) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14} +} + +func (x *GeminiResponse) GetCandidates() []*GeminiResponse_Candidate { + if x != nil { + return x.Candidates + } + return nil +} + +func (x *GeminiResponse) GetPromptFeedback() *GeminiResponse_PromptFeedback { + if x != nil { + return x.PromptFeedback + } + return nil +} + +type GeocodeResponse_Location struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Lat float64 `protobuf:"fixed64,1,opt,name=lat,proto3" json:"lat,omitempty"` + Lng float64 `protobuf:"fixed64,2,opt,name=lng,proto3" json:"lng,omitempty"` +} + +func (x *GeocodeResponse_Location) Reset() { + *x = GeocodeResponse_Location{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeResponse_Location) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse_Location) ProtoMessage() {} + +func (x *GeocodeResponse_Location) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeResponse_Location.ProtoReflect.Descriptor instead. +func (*GeocodeResponse_Location) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *GeocodeResponse_Location) GetLat() float64 { + if x != nil { + return x.Lat + } + return 0 +} + +func (x *GeocodeResponse_Location) GetLng() float64 { + if x != nil { + return x.Lng + } + return 0 +} + +type GeocodeResponse_Result struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FormattedAddress string `protobuf:"bytes,1,opt,name=formatted_address,json=formattedAddress,proto3" json:"formatted_address,omitempty"` + Location *GeocodeResponse_Location `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` // Add other relevant fields from Geocoding API if needed +} + +func (x *GeocodeResponse_Result) Reset() { + *x = GeocodeResponse_Result{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeocodeResponse_Result) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeocodeResponse_Result) ProtoMessage() {} + +func (x *GeocodeResponse_Result) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeocodeResponse_Result.ProtoReflect.Descriptor instead. +func (*GeocodeResponse_Result) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{3, 1} +} + +func (x *GeocodeResponse_Result) GetFormattedAddress() string { + if x != nil { + return x.FormattedAddress + } + return "" +} + +func (x *GeocodeResponse_Result) GetLocation() *GeocodeResponse_Location { + if x != nil { + return x.Location + } + return nil +} + +type Place_Location struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Lat float64 `protobuf:"fixed64,1,opt,name=lat,proto3" json:"lat,omitempty"` + Lng float64 `protobuf:"fixed64,2,opt,name=lng,proto3" json:"lng,omitempty"` +} + +func (x *Place_Location) Reset() { + *x = Place_Location{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place_Location) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_Location) ProtoMessage() {} + +func (x *Place_Location) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place_Location.ProtoReflect.Descriptor instead. +func (*Place_Location) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *Place_Location) GetLat() float64 { + if x != nil { + return x.Lat + } + return 0 +} + +func (x *Place_Location) GetLng() float64 { + if x != nil { + return x.Lng + } + return 0 +} + +type Place_OpeningHours struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpenNow bool `protobuf:"varint,1,opt,name=open_now,json=openNow,proto3" json:"open_now,omitempty"` +} + +func (x *Place_OpeningHours) Reset() { + *x = Place_OpeningHours{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place_OpeningHours) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_OpeningHours) ProtoMessage() {} + +func (x *Place_OpeningHours) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place_OpeningHours.ProtoReflect.Descriptor instead. +func (*Place_OpeningHours) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5, 1} +} + +func (x *Place_OpeningHours) GetOpenNow() bool { + if x != nil { + return x.OpenNow + } + return false +} + +type Place_Photo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PhotoReference string `protobuf:"bytes,1,opt,name=photo_reference,json=photoReference,proto3" json:"photo_reference,omitempty"` + Height int32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + Width int32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` // repeated string html_attributions = 4; // Usually not needed for direct display +} + +func (x *Place_Photo) Reset() { + *x = Place_Photo{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Place_Photo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Place_Photo) ProtoMessage() {} + +func (x *Place_Photo) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Place_Photo.ProtoReflect.Descriptor instead. +func (*Place_Photo) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{5, 2} +} + +func (x *Place_Photo) GetPhotoReference() string { + if x != nil { + return x.PhotoReference + } + return "" +} + +func (x *Place_Photo) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +func (x *Place_Photo) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +type DirectionsResponse_Distance struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // meters +} + +func (x *DirectionsResponse_Distance) Reset() { + *x = DirectionsResponse_Distance{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Distance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Distance) ProtoMessage() {} + +func (x *DirectionsResponse_Distance) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Distance.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Distance) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 0} +} + +func (x *DirectionsResponse_Distance) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DirectionsResponse_Distance) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DirectionsResponse_Duration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // seconds +} + +func (x *DirectionsResponse_Duration) Reset() { + *x = DirectionsResponse_Duration{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Duration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Duration) ProtoMessage() {} + +func (x *DirectionsResponse_Duration) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Duration.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Duration) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 1} +} + +func (x *DirectionsResponse_Duration) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DirectionsResponse_Duration) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DirectionsResponse_Polyline struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Points string `protobuf:"bytes,1,opt,name=points,proto3" json:"points,omitempty"` +} + +func (x *DirectionsResponse_Polyline) Reset() { + *x = DirectionsResponse_Polyline{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Polyline) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Polyline) ProtoMessage() {} + +func (x *DirectionsResponse_Polyline) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Polyline.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Polyline) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 2} +} + +func (x *DirectionsResponse_Polyline) GetPoints() string { + if x != nil { + return x.Points + } + return "" +} + +type DirectionsResponse_Step struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HtmlInstructions string `protobuf:"bytes,1,opt,name=html_instructions,json=htmlInstructions,proto3" json:"html_instructions,omitempty"` + Distance *DirectionsResponse_Distance `protobuf:"bytes,2,opt,name=distance,proto3" json:"distance,omitempty"` + Duration *DirectionsResponse_Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + Polyline *DirectionsResponse_Polyline `protobuf:"bytes,4,opt,name=polyline,proto3" json:"polyline,omitempty"` // Add start_location, end_location if needed +} + +func (x *DirectionsResponse_Step) Reset() { + *x = DirectionsResponse_Step{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Step) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Step) ProtoMessage() {} + +func (x *DirectionsResponse_Step) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Step.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Step) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 3} +} + +func (x *DirectionsResponse_Step) GetHtmlInstructions() string { + if x != nil { + return x.HtmlInstructions + } + return "" +} + +func (x *DirectionsResponse_Step) GetDistance() *DirectionsResponse_Distance { + if x != nil { + return x.Distance + } + return nil +} + +func (x *DirectionsResponse_Step) GetDuration() *DirectionsResponse_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DirectionsResponse_Step) GetPolyline() *DirectionsResponse_Polyline { + if x != nil { + return x.Polyline + } + return nil +} + +type DirectionsResponse_Leg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Distance *DirectionsResponse_Distance `protobuf:"bytes,1,opt,name=distance,proto3" json:"distance,omitempty"` + Duration *DirectionsResponse_Duration `protobuf:"bytes,2,opt,name=duration,proto3" json:"duration,omitempty"` + StartAddress string `protobuf:"bytes,3,opt,name=start_address,json=startAddress,proto3" json:"start_address,omitempty"` + EndAddress string `protobuf:"bytes,4,opt,name=end_address,json=endAddress,proto3" json:"end_address,omitempty"` + Steps []*DirectionsResponse_Step `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"` // Add start_location, end_location if needed +} + +func (x *DirectionsResponse_Leg) Reset() { + *x = DirectionsResponse_Leg{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Leg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Leg) ProtoMessage() {} + +func (x *DirectionsResponse_Leg) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Leg.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Leg) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 4} +} + +func (x *DirectionsResponse_Leg) GetDistance() *DirectionsResponse_Distance { + if x != nil { + return x.Distance + } + return nil +} + +func (x *DirectionsResponse_Leg) GetDuration() *DirectionsResponse_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DirectionsResponse_Leg) GetStartAddress() string { + if x != nil { + return x.StartAddress + } + return "" +} + +func (x *DirectionsResponse_Leg) GetEndAddress() string { + if x != nil { + return x.EndAddress + } + return "" +} + +func (x *DirectionsResponse_Leg) GetSteps() []*DirectionsResponse_Step { + if x != nil { + return x.Steps + } + return nil +} + +type DirectionsResponse_Route struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Summary string `protobuf:"bytes,1,opt,name=summary,proto3" json:"summary,omitempty"` + Legs []*DirectionsResponse_Leg `protobuf:"bytes,2,rep,name=legs,proto3" json:"legs,omitempty"` + OverviewPolyline *DirectionsResponse_Polyline `protobuf:"bytes,3,opt,name=overview_polyline,json=overviewPolyline,proto3" json:"overview_polyline,omitempty"` // Add warnings, bounds if needed +} + +func (x *DirectionsResponse_Route) Reset() { + *x = DirectionsResponse_Route{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_Route) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_Route) ProtoMessage() {} + +func (x *DirectionsResponse_Route) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_Route.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_Route) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 5} +} + +func (x *DirectionsResponse_Route) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *DirectionsResponse_Route) GetLegs() []*DirectionsResponse_Leg { + if x != nil { + return x.Legs + } + return nil +} + +func (x *DirectionsResponse_Route) GetOverviewPolyline() *DirectionsResponse_Polyline { + if x != nil { + return x.OverviewPolyline + } + return nil +} + +type DirectionsResponse_GeocodedWaypoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GeocoderStatus string `protobuf:"bytes,1,opt,name=geocoder_status,json=geocoderStatus,proto3" json:"geocoder_status,omitempty"` + PlaceId string `protobuf:"bytes,2,opt,name=place_id,json=placeId,proto3" json:"place_id,omitempty"` + Types []string `protobuf:"bytes,3,rep,name=types,proto3" json:"types,omitempty"` +} + +func (x *DirectionsResponse_GeocodedWaypoint) Reset() { + *x = DirectionsResponse_GeocodedWaypoint{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DirectionsResponse_GeocodedWaypoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectionsResponse_GeocodedWaypoint) ProtoMessage() {} + +func (x *DirectionsResponse_GeocodedWaypoint) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DirectionsResponse_GeocodedWaypoint.ProtoReflect.Descriptor instead. +func (*DirectionsResponse_GeocodedWaypoint) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{10, 6} +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetGeocoderStatus() string { + if x != nil { + return x.GeocoderStatus + } + return "" +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetPlaceId() string { + if x != nil { + return x.PlaceId + } + return "" +} + +func (x *DirectionsResponse_GeocodedWaypoint) GetTypes() []string { + if x != nil { + return x.Types + } + return nil +} + +type DistanceMatrixResponse_Element struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` // e.g., "OK", "NOT_FOUND", "ZERO_RESULTS" + Duration *DistanceMatrixResponse_Element_Duration `protobuf:"bytes,2,opt,name=duration,proto3" json:"duration,omitempty"` + Distance *DistanceMatrixResponse_Element_Distance `protobuf:"bytes,3,opt,name=distance,proto3" json:"distance,omitempty"` +} + +func (x *DistanceMatrixResponse_Element) Reset() { + *x = DistanceMatrixResponse_Element{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Element) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Element.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 0} +} + +func (x *DistanceMatrixResponse_Element) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *DistanceMatrixResponse_Element) GetDuration() *DistanceMatrixResponse_Element_Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DistanceMatrixResponse_Element) GetDistance() *DistanceMatrixResponse_Element_Distance { + if x != nil { + return x.Distance + } + return nil +} + +type DistanceMatrixResponse_Row struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Elements []*DistanceMatrixResponse_Element `protobuf:"bytes,1,rep,name=elements,proto3" json:"elements,omitempty"` +} + +func (x *DistanceMatrixResponse_Row) Reset() { + *x = DistanceMatrixResponse_Row{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Row) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Row) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Row) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Row.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Row) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 1} +} + +func (x *DistanceMatrixResponse_Row) GetElements() []*DistanceMatrixResponse_Element { + if x != nil { + return x.Elements + } + return nil +} + +type DistanceMatrixResponse_Element_Duration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // seconds +} + +func (x *DistanceMatrixResponse_Element_Duration) Reset() { + *x = DistanceMatrixResponse_Element_Duration{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Element_Duration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element_Duration) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element_Duration) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Element_Duration.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element_Duration) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 0, 0} +} + +func (x *DistanceMatrixResponse_Element_Duration) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DistanceMatrixResponse_Element_Duration) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type DistanceMatrixResponse_Element_Distance struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // meters +} + +func (x *DistanceMatrixResponse_Element_Distance) Reset() { + *x = DistanceMatrixResponse_Element_Distance{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DistanceMatrixResponse_Element_Distance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistanceMatrixResponse_Element_Distance) ProtoMessage() {} + +func (x *DistanceMatrixResponse_Element_Distance) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistanceMatrixResponse_Element_Distance.ProtoReflect.Descriptor instead. +func (*DistanceMatrixResponse_Element_Distance) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{12, 0, 1} +} + +func (x *DistanceMatrixResponse_Element_Distance) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *DistanceMatrixResponse_Element_Distance) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +type GeminiResponse_SafetyRating struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Category string `protobuf:"bytes,1,opt,name=category,proto3" json:"category,omitempty"` // e.g., "HARM_CATEGORY_SEXUALLY_EXPLICIT" + Probability string `protobuf:"bytes,2,opt,name=probability,proto3" json:"probability,omitempty"` // e.g., "NEGLIGIBLE", "LOW", "MEDIUM", "HIGH" +} + +func (x *GeminiResponse_SafetyRating) Reset() { + *x = GeminiResponse_SafetyRating{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_SafetyRating) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_SafetyRating) ProtoMessage() {} + +func (x *GeminiResponse_SafetyRating) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_SafetyRating.ProtoReflect.Descriptor instead. +func (*GeminiResponse_SafetyRating) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 0} +} + +func (x *GeminiResponse_SafetyRating) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *GeminiResponse_SafetyRating) GetProbability() string { + if x != nil { + return x.Probability + } + return "" +} + +type GeminiResponse_ContentPart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` // Potentially add other part types like 'inline_data' if needed in the future +} + +func (x *GeminiResponse_ContentPart) Reset() { + *x = GeminiResponse_ContentPart{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_ContentPart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_ContentPart) ProtoMessage() {} + +func (x *GeminiResponse_ContentPart) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_ContentPart.ProtoReflect.Descriptor instead. +func (*GeminiResponse_ContentPart) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 1} +} + +func (x *GeminiResponse_ContentPart) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +type GeminiResponse_Content struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Parts []*GeminiResponse_ContentPart `protobuf:"bytes,1,rep,name=parts,proto3" json:"parts,omitempty"` + Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` // e.g., "user", "model" +} + +func (x *GeminiResponse_Content) Reset() { + *x = GeminiResponse_Content{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_Content) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_Content) ProtoMessage() {} + +func (x *GeminiResponse_Content) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_Content.ProtoReflect.Descriptor instead. +func (*GeminiResponse_Content) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 2} +} + +func (x *GeminiResponse_Content) GetParts() []*GeminiResponse_ContentPart { + if x != nil { + return x.Parts + } + return nil +} + +func (x *GeminiResponse_Content) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +type GeminiResponse_Candidate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Content *GeminiResponse_Content `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + FinishReason string `protobuf:"bytes,2,opt,name=finish_reason,json=finishReason,proto3" json:"finish_reason,omitempty"` // e.g., "STOP", "MAX_TOKENS", "SAFETY" + Index int32 `protobuf:"varint,3,opt,name=index,proto3" json:"index,omitempty"` + SafetyRatings []*GeminiResponse_SafetyRating `protobuf:"bytes,4,rep,name=safety_ratings,json=safetyRatings,proto3" json:"safety_ratings,omitempty"` // Potentially add 'citation_metadata' if needed +} + +func (x *GeminiResponse_Candidate) Reset() { + *x = GeminiResponse_Candidate{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_Candidate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_Candidate) ProtoMessage() {} + +func (x *GeminiResponse_Candidate) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_Candidate.ProtoReflect.Descriptor instead. +func (*GeminiResponse_Candidate) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 3} +} + +func (x *GeminiResponse_Candidate) GetContent() *GeminiResponse_Content { + if x != nil { + return x.Content + } + return nil +} + +func (x *GeminiResponse_Candidate) GetFinishReason() string { + if x != nil { + return x.FinishReason + } + return "" +} + +func (x *GeminiResponse_Candidate) GetIndex() int32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *GeminiResponse_Candidate) GetSafetyRatings() []*GeminiResponse_SafetyRating { + if x != nil { + return x.SafetyRatings + } + return nil +} + +type GeminiResponse_PromptFeedback struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // string block_reason = 1; // If prompt was blocked + SafetyRatings []*GeminiResponse_SafetyRating `protobuf:"bytes,2,rep,name=safety_ratings,json=safetyRatings,proto3" json:"safety_ratings,omitempty"` +} + +func (x *GeminiResponse_PromptFeedback) Reset() { + *x = GeminiResponse_PromptFeedback{} + if protoimpl.UnsafeEnabled { + mi := &file_communication_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeminiResponse_PromptFeedback) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeminiResponse_PromptFeedback) ProtoMessage() {} + +func (x *GeminiResponse_PromptFeedback) ProtoReflect() protoreflect.Message { + mi := &file_communication_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeminiResponse_PromptFeedback.ProtoReflect.Descriptor instead. +func (*GeminiResponse_PromptFeedback) Descriptor() ([]byte, []int) { + return file_communication_proto_rawDescGZIP(), []int{14, 4} +} + +func (x *GeminiResponse_PromptFeedback) GetSafetyRatings() []*GeminiResponse_SafetyRating { + if x != nil { + return x.SafetyRatings + } + return nil +} + +var File_communication_proto protoreflect.FileDescriptor + +var file_communication_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0c, 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, 0x26, 0x0a, 0x0a, 0x48, + 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 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, 0x2a, 0x0a, 0x0e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0x9c, 0x02, 0x0a, 0x0f, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, + 0x2e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6c, + 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x61, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x6c, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6e, 0x67, 0x1a, + 0x7d, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x64, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x46, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x63, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x47, + 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, 0x1a, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xd9, 0x04, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x63, + 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, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x69, 0x63, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x76, 0x69, 0x63, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x72, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x72, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x10, 0x75, 0x73, 0x65, 0x72, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x54, 0x6f, 0x74, + 0x61, 0x6c, 0x12, 0x4d, 0x0a, 0x11, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x10, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x49, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x6f, 0x75, + 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, 0x63, + 0x65, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x52, 0x0c, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x12, 0x35, 0x0a, 0x06, + 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, + 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x50, 0x6c, 0x61, 0x63, 0x65, 0x2e, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x52, 0x06, 0x70, 0x68, 0x6f, + 0x74, 0x6f, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x5f, 0x75, 0x72, 0x6c, + 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x55, 0x72, + 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x1a, 0x2e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x03, 0x6c, 0x61, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6e, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6e, 0x67, 0x1a, 0x29, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x6e, + 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x6e, + 0x5f, 0x6e, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6f, 0x70, 0x65, 0x6e, + 0x4e, 0x6f, 0x77, 0x1a, 0x5e, 0x0a, 0x05, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x12, 0x27, 0x0a, 0x0f, + 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x22, 0x61, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, + 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x50, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x30, 0x0a, 0x13, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 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, 0x5f, 0x0a, 0x14, 0x50, 0x6c, 0x61, 0x63, + 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xce, 0x09, 0x0a, 0x12, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x42, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x12, 0x64, 0x0a, 0x12, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, + 0x77, 0x61, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x57, 0x61, + 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x11, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, + 0x57, 0x61, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x1a, 0x34, 0x0a, 0x08, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x34, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x22, 0x0a, + 0x08, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x1a, 0x94, 0x02, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x2b, 0x0a, 0x11, 0x68, 0x74, + 0x6d, 0x6c, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x68, 0x74, 0x6d, 0x6c, 0x49, 0x6e, 0x73, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x49, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, + 0x08, 0x70, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x52, 0x08, + 0x70, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0xa2, 0x02, 0x0a, 0x03, 0x4c, 0x65, 0x67, + 0x12, 0x49, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, + 0x6e, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x65, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x05, + 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a, 0xbb, 0x01, + 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x12, 0x3c, 0x0a, 0x04, 0x6c, 0x65, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, 0x65, 0x67, 0x52, 0x04, 0x6c, 0x65, 0x67, 0x73, 0x12, + 0x5a, 0x0a, 0x11, 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x6f, 0x6c, 0x79, + 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x52, 0x10, 0x6f, 0x76, 0x65, 0x72, 0x76, + 0x69, 0x65, 0x77, 0x50, 0x6f, 0x6c, 0x79, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0x6c, 0x0a, 0x10, 0x47, + 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x57, 0x61, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x27, 0x0a, 0x0f, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x67, 0x65, 0x6f, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x55, 0x0a, 0x15, 0x44, 0x69, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0c, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0xe5, 0x04, 0x0a, 0x16, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, + 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x33, 0x0a, 0x15, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x04, 0x72, + 0x6f, 0x77, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0xbb, 0x02, 0x0a, 0x07, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x55, 0x0a, 0x08, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x55, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, + 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x64, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x1a, 0x34, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x34, 0x0a, + 0x08, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x1a, 0x53, 0x0a, 0x03, 0x52, 0x6f, 0x77, 0x12, 0x4c, 0x0a, 0x08, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x61, + 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x27, 0x0a, 0x0d, 0x47, 0x65, 0x6d, 0x69, + 0x6e, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, + 0x74, 0x22, 0xd5, 0x05, 0x0a, 0x0e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, + 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, + 0x12, 0x58, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, + 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x1a, 0x4c, 0x0a, 0x0c, 0x53, 0x61, + 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, + 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x1a, 0x21, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x1a, 0x61, 0x0a, 0x07, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x50, + 0x61, 0x72, 0x74, 0x52, 0x05, 0x70, 0x61, 0x72, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x1a, 0xe0, + 0x01, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x42, 0x0a, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x52, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x54, 0x0a, 0x0e, 0x73, + 0x61, 0x66, 0x65, 0x74, 0x79, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x61, 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x52, 0x0d, 0x73, 0x61, 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x1a, 0x66, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x12, 0x54, 0x0a, 0x0e, 0x73, 0x61, 0x66, 0x65, 0x74, 0x79, 0x5f, 0x72, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, + 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x61, + 0x66, 0x65, 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0d, 0x73, 0x61, 0x66, 0x65, + 0x74, 0x79, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x32, 0x5c, 0x0a, 0x0e, 0x45, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x08, 0x53, + 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0xdb, 0x03, 0x0a, 0x04, 0x4d, 0x61, 0x70, 0x73, + 0x12, 0x4e, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, + 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5d, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, + 0x12, 0x25, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x60, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x12, 0x25, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x70, 0x69, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6c, 0x61, + 0x63, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, + 0x11, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, + 0x69, 0x78, 0x12, 0x27, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, + 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x61, 0x70, + 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x5e, 0x0a, 0x06, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x12, + 0x54, 0x0a, 0x0f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d, 0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x01, 0x5a, + 0x13, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x67, 0x72, 0x70, + 0x63, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_communication_proto_rawDescOnce sync.Once + file_communication_proto_rawDescData = file_communication_proto_rawDesc +) + +func file_communication_proto_rawDescGZIP() []byte { + file_communication_proto_rawDescOnce.Do(func() { + file_communication_proto_rawDescData = protoimpl.X.CompressGZIP(file_communication_proto_rawDescData) + }) + return file_communication_proto_rawDescData +} + +var file_communication_proto_msgTypes = make([]protoimpl.MessageInfo, 36) +var file_communication_proto_goTypes = []interface{}{ + (*HelloRequest)(nil), // 0: apiservice_proto.HelloRequest + (*HelloReply)(nil), // 1: apiservice_proto.HelloReply + (*GeocodeRequest)(nil), // 2: apiservice_proto.GeocodeRequest + (*GeocodeResponse)(nil), // 3: apiservice_proto.GeocodeResponse + (*SearchPlacesRequest)(nil), // 4: apiservice_proto.SearchPlacesRequest + (*Place)(nil), // 5: apiservice_proto.Place + (*SearchPlacesResponse)(nil), // 6: apiservice_proto.SearchPlacesResponse + (*PlaceDetailsRequest)(nil), // 7: apiservice_proto.PlaceDetailsRequest + (*PlaceDetailsResponse)(nil), // 8: apiservice_proto.PlaceDetailsResponse + (*DirectionsRequest)(nil), // 9: apiservice_proto.DirectionsRequest + (*DirectionsResponse)(nil), // 10: apiservice_proto.DirectionsResponse + (*DistanceMatrixRequest)(nil), // 11: apiservice_proto.DistanceMatrixRequest + (*DistanceMatrixResponse)(nil), // 12: apiservice_proto.DistanceMatrixResponse + (*GeminiRequest)(nil), // 13: apiservice_proto.GeminiRequest + (*GeminiResponse)(nil), // 14: apiservice_proto.GeminiResponse + (*GeocodeResponse_Location)(nil), // 15: apiservice_proto.GeocodeResponse.Location + (*GeocodeResponse_Result)(nil), // 16: apiservice_proto.GeocodeResponse.Result + (*Place_Location)(nil), // 17: apiservice_proto.Place.Location + (*Place_OpeningHours)(nil), // 18: apiservice_proto.Place.OpeningHours + (*Place_Photo)(nil), // 19: apiservice_proto.Place.Photo + (*DirectionsResponse_Distance)(nil), // 20: apiservice_proto.DirectionsResponse.Distance + (*DirectionsResponse_Duration)(nil), // 21: apiservice_proto.DirectionsResponse.Duration + (*DirectionsResponse_Polyline)(nil), // 22: apiservice_proto.DirectionsResponse.Polyline + (*DirectionsResponse_Step)(nil), // 23: apiservice_proto.DirectionsResponse.Step + (*DirectionsResponse_Leg)(nil), // 24: apiservice_proto.DirectionsResponse.Leg + (*DirectionsResponse_Route)(nil), // 25: apiservice_proto.DirectionsResponse.Route + (*DirectionsResponse_GeocodedWaypoint)(nil), // 26: apiservice_proto.DirectionsResponse.GeocodedWaypoint + (*DistanceMatrixResponse_Element)(nil), // 27: apiservice_proto.DistanceMatrixResponse.Element + (*DistanceMatrixResponse_Row)(nil), // 28: apiservice_proto.DistanceMatrixResponse.Row + (*DistanceMatrixResponse_Element_Duration)(nil), // 29: apiservice_proto.DistanceMatrixResponse.Element.Duration + (*DistanceMatrixResponse_Element_Distance)(nil), // 30: apiservice_proto.DistanceMatrixResponse.Element.Distance + (*GeminiResponse_SafetyRating)(nil), // 31: apiservice_proto.GeminiResponse.SafetyRating + (*GeminiResponse_ContentPart)(nil), // 32: apiservice_proto.GeminiResponse.ContentPart + (*GeminiResponse_Content)(nil), // 33: apiservice_proto.GeminiResponse.Content + (*GeminiResponse_Candidate)(nil), // 34: apiservice_proto.GeminiResponse.Candidate + (*GeminiResponse_PromptFeedback)(nil), // 35: apiservice_proto.GeminiResponse.PromptFeedback +} +var file_communication_proto_depIdxs = []int32{ + 16, // 0: apiservice_proto.GeocodeResponse.results:type_name -> apiservice_proto.GeocodeResponse.Result + 17, // 1: apiservice_proto.Place.geometry_location:type_name -> apiservice_proto.Place.Location + 18, // 2: apiservice_proto.Place.opening_hours:type_name -> apiservice_proto.Place.OpeningHours + 19, // 3: apiservice_proto.Place.photos:type_name -> apiservice_proto.Place.Photo + 5, // 4: apiservice_proto.SearchPlacesResponse.results:type_name -> apiservice_proto.Place + 5, // 5: apiservice_proto.PlaceDetailsResponse.result:type_name -> apiservice_proto.Place + 25, // 6: apiservice_proto.DirectionsResponse.routes:type_name -> apiservice_proto.DirectionsResponse.Route + 26, // 7: apiservice_proto.DirectionsResponse.geocoded_waypoints:type_name -> apiservice_proto.DirectionsResponse.GeocodedWaypoint + 28, // 8: apiservice_proto.DistanceMatrixResponse.rows:type_name -> apiservice_proto.DistanceMatrixResponse.Row + 34, // 9: apiservice_proto.GeminiResponse.candidates:type_name -> apiservice_proto.GeminiResponse.Candidate + 35, // 10: apiservice_proto.GeminiResponse.prompt_feedback:type_name -> apiservice_proto.GeminiResponse.PromptFeedback + 15, // 11: apiservice_proto.GeocodeResponse.Result.location:type_name -> apiservice_proto.GeocodeResponse.Location + 20, // 12: apiservice_proto.DirectionsResponse.Step.distance:type_name -> apiservice_proto.DirectionsResponse.Distance + 21, // 13: apiservice_proto.DirectionsResponse.Step.duration:type_name -> apiservice_proto.DirectionsResponse.Duration + 22, // 14: apiservice_proto.DirectionsResponse.Step.polyline:type_name -> apiservice_proto.DirectionsResponse.Polyline + 20, // 15: apiservice_proto.DirectionsResponse.Leg.distance:type_name -> apiservice_proto.DirectionsResponse.Distance + 21, // 16: apiservice_proto.DirectionsResponse.Leg.duration:type_name -> apiservice_proto.DirectionsResponse.Duration + 23, // 17: apiservice_proto.DirectionsResponse.Leg.steps:type_name -> apiservice_proto.DirectionsResponse.Step + 24, // 18: apiservice_proto.DirectionsResponse.Route.legs:type_name -> apiservice_proto.DirectionsResponse.Leg + 22, // 19: apiservice_proto.DirectionsResponse.Route.overview_polyline:type_name -> apiservice_proto.DirectionsResponse.Polyline + 29, // 20: apiservice_proto.DistanceMatrixResponse.Element.duration:type_name -> apiservice_proto.DistanceMatrixResponse.Element.Duration + 30, // 21: apiservice_proto.DistanceMatrixResponse.Element.distance:type_name -> apiservice_proto.DistanceMatrixResponse.Element.Distance + 27, // 22: apiservice_proto.DistanceMatrixResponse.Row.elements:type_name -> apiservice_proto.DistanceMatrixResponse.Element + 32, // 23: apiservice_proto.GeminiResponse.Content.parts:type_name -> apiservice_proto.GeminiResponse.ContentPart + 33, // 24: apiservice_proto.GeminiResponse.Candidate.content:type_name -> apiservice_proto.GeminiResponse.Content + 31, // 25: apiservice_proto.GeminiResponse.Candidate.safety_ratings:type_name -> apiservice_proto.GeminiResponse.SafetyRating + 31, // 26: apiservice_proto.GeminiResponse.PromptFeedback.safety_ratings:type_name -> apiservice_proto.GeminiResponse.SafetyRating + 0, // 27: apiservice_proto.ExampleGreeter.SayHello:input_type -> apiservice_proto.HelloRequest + 2, // 28: apiservice_proto.Maps.Geocode:input_type -> apiservice_proto.GeocodeRequest + 4, // 29: apiservice_proto.Maps.SearchPlaces:input_type -> apiservice_proto.SearchPlacesRequest + 7, // 30: apiservice_proto.Maps.GetPlaceDetails:input_type -> apiservice_proto.PlaceDetailsRequest + 9, // 31: apiservice_proto.Maps.GetDirections:input_type -> apiservice_proto.DirectionsRequest + 11, // 32: apiservice_proto.Maps.GetDistanceMatrix:input_type -> apiservice_proto.DistanceMatrixRequest + 13, // 33: apiservice_proto.Gemini.GenerateContent:input_type -> apiservice_proto.GeminiRequest + 1, // 34: apiservice_proto.ExampleGreeter.SayHello:output_type -> apiservice_proto.HelloReply + 3, // 35: apiservice_proto.Maps.Geocode:output_type -> apiservice_proto.GeocodeResponse + 6, // 36: apiservice_proto.Maps.SearchPlaces:output_type -> apiservice_proto.SearchPlacesResponse + 8, // 37: apiservice_proto.Maps.GetPlaceDetails:output_type -> apiservice_proto.PlaceDetailsResponse + 10, // 38: apiservice_proto.Maps.GetDirections:output_type -> apiservice_proto.DirectionsResponse + 12, // 39: apiservice_proto.Maps.GetDistanceMatrix:output_type -> apiservice_proto.DistanceMatrixResponse + 14, // 40: apiservice_proto.Gemini.GenerateContent:output_type -> apiservice_proto.GeminiResponse + 34, // [34:41] is the sub-list for method output_type + 27, // [27:34] is the sub-list for method input_type + 27, // [27:27] is the sub-list for extension type_name + 27, // [27:27] is the sub-list for extension extendee + 0, // [0:27] is the sub-list for field type_name +} + +func init() { file_communication_proto_init() } +func file_communication_proto_init() { + if File_communication_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_communication_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HelloRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HelloReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchPlacesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchPlacesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlaceDetailsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlaceDetailsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeResponse_Location); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeocodeResponse_Result); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place_Location); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place_OpeningHours); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Place_Photo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Distance); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Duration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Polyline); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Step); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Leg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_Route); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DirectionsResponse_GeocodedWaypoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Element); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Row); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Element_Duration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DistanceMatrixResponse_Element_Distance); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_SafetyRating); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_ContentPart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_Content); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_Candidate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communication_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeminiResponse_PromptFeedback); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_communication_proto_rawDesc, + NumEnums: 0, + NumMessages: 36, + NumExtensions: 0, + NumServices: 3, + }, + GoTypes: file_communication_proto_goTypes, + DependencyIndexes: file_communication_proto_depIdxs, + MessageInfos: file_communication_proto_msgTypes, + }.Build() + File_communication_proto = out.File + file_communication_proto_rawDesc = nil + file_communication_proto_goTypes = nil + file_communication_proto_depIdxs = nil +} diff --git a/grpc/pb/communication_grpc.pb.go b/grpc/pb/communication_grpc.pb.go new file mode 100644 index 0000000..ab3e30c --- /dev/null +++ b/grpc/pb/communication_grpc.pb.go @@ -0,0 +1,423 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.21.12 +// source: communication.proto + +package pb + +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.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ExampleGreeterClient is the client API for ExampleGreeter 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 ExampleGreeterClient interface { + // Sends a greeting + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type exampleGreeterClient struct { + cc grpc.ClientConnInterface +} + +func NewExampleGreeterClient(cc grpc.ClientConnInterface) ExampleGreeterClient { + return &exampleGreeterClient{cc} +} + +func (c *exampleGreeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := c.cc.Invoke(ctx, "/apiservice_proto.ExampleGreeter/SayHello", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ExampleGreeterServer is the server API for ExampleGreeter service. +// All implementations must embed UnimplementedExampleGreeterServer +// for forward compatibility +type ExampleGreeterServer interface { + // Sends a greeting + SayHello(context.Context, *HelloRequest) (*HelloReply, error) + mustEmbedUnimplementedExampleGreeterServer() +} + +// UnimplementedExampleGreeterServer must be embedded to have forward compatible implementations. +type UnimplementedExampleGreeterServer struct { +} + +func (UnimplementedExampleGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") +} +func (UnimplementedExampleGreeterServer) mustEmbedUnimplementedExampleGreeterServer() {} + +// UnsafeExampleGreeterServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ExampleGreeterServer will +// result in compilation errors. +type UnsafeExampleGreeterServer interface { + mustEmbedUnimplementedExampleGreeterServer() +} + +func RegisterExampleGreeterServer(s grpc.ServiceRegistrar, srv ExampleGreeterServer) { + s.RegisterService(&ExampleGreeter_ServiceDesc, srv) +} + +func _ExampleGreeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ExampleGreeterServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apiservice_proto.ExampleGreeter/SayHello", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ExampleGreeterServer).SayHello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ExampleGreeter_ServiceDesc is the grpc.ServiceDesc for ExampleGreeter service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ExampleGreeter_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "apiservice_proto.ExampleGreeter", + HandlerType: (*ExampleGreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _ExampleGreeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "communication.proto", +} + +// MapsClient is the client API for Maps 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 MapsClient interface { + Geocode(ctx context.Context, in *GeocodeRequest, opts ...grpc.CallOption) (*GeocodeResponse, error) + SearchPlaces(ctx context.Context, in *SearchPlacesRequest, opts ...grpc.CallOption) (*SearchPlacesResponse, error) + GetPlaceDetails(ctx context.Context, in *PlaceDetailsRequest, opts ...grpc.CallOption) (*PlaceDetailsResponse, error) + GetDirections(ctx context.Context, in *DirectionsRequest, opts ...grpc.CallOption) (*DirectionsResponse, error) + GetDistanceMatrix(ctx context.Context, in *DistanceMatrixRequest, opts ...grpc.CallOption) (*DistanceMatrixResponse, error) +} + +type mapsClient struct { + cc grpc.ClientConnInterface +} + +func NewMapsClient(cc grpc.ClientConnInterface) MapsClient { + return &mapsClient{cc} +} + +func (c *mapsClient) Geocode(ctx context.Context, in *GeocodeRequest, opts ...grpc.CallOption) (*GeocodeResponse, error) { + out := new(GeocodeResponse) + err := c.cc.Invoke(ctx, "/apiservice_proto.Maps/Geocode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) SearchPlaces(ctx context.Context, in *SearchPlacesRequest, opts ...grpc.CallOption) (*SearchPlacesResponse, error) { + out := new(SearchPlacesResponse) + err := c.cc.Invoke(ctx, "/apiservice_proto.Maps/SearchPlaces", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) GetPlaceDetails(ctx context.Context, in *PlaceDetailsRequest, opts ...grpc.CallOption) (*PlaceDetailsResponse, error) { + out := new(PlaceDetailsResponse) + err := c.cc.Invoke(ctx, "/apiservice_proto.Maps/GetPlaceDetails", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) GetDirections(ctx context.Context, in *DirectionsRequest, opts ...grpc.CallOption) (*DirectionsResponse, error) { + out := new(DirectionsResponse) + err := c.cc.Invoke(ctx, "/apiservice_proto.Maps/GetDirections", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mapsClient) GetDistanceMatrix(ctx context.Context, in *DistanceMatrixRequest, opts ...grpc.CallOption) (*DistanceMatrixResponse, error) { + out := new(DistanceMatrixResponse) + err := c.cc.Invoke(ctx, "/apiservice_proto.Maps/GetDistanceMatrix", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MapsServer is the server API for Maps service. +// All implementations must embed UnimplementedMapsServer +// for forward compatibility +type MapsServer interface { + Geocode(context.Context, *GeocodeRequest) (*GeocodeResponse, error) + SearchPlaces(context.Context, *SearchPlacesRequest) (*SearchPlacesResponse, error) + GetPlaceDetails(context.Context, *PlaceDetailsRequest) (*PlaceDetailsResponse, error) + GetDirections(context.Context, *DirectionsRequest) (*DirectionsResponse, error) + GetDistanceMatrix(context.Context, *DistanceMatrixRequest) (*DistanceMatrixResponse, error) + mustEmbedUnimplementedMapsServer() +} + +// UnimplementedMapsServer must be embedded to have forward compatible implementations. +type UnimplementedMapsServer struct { +} + +func (UnimplementedMapsServer) Geocode(context.Context, *GeocodeRequest) (*GeocodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Geocode not implemented") +} +func (UnimplementedMapsServer) SearchPlaces(context.Context, *SearchPlacesRequest) (*SearchPlacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchPlaces not implemented") +} +func (UnimplementedMapsServer) GetPlaceDetails(context.Context, *PlaceDetailsRequest) (*PlaceDetailsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPlaceDetails not implemented") +} +func (UnimplementedMapsServer) GetDirections(context.Context, *DirectionsRequest) (*DirectionsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDirections not implemented") +} +func (UnimplementedMapsServer) GetDistanceMatrix(context.Context, *DistanceMatrixRequest) (*DistanceMatrixResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDistanceMatrix not implemented") +} +func (UnimplementedMapsServer) mustEmbedUnimplementedMapsServer() {} + +// UnsafeMapsServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MapsServer will +// result in compilation errors. +type UnsafeMapsServer interface { + mustEmbedUnimplementedMapsServer() +} + +func RegisterMapsServer(s grpc.ServiceRegistrar, srv MapsServer) { + s.RegisterService(&Maps_ServiceDesc, srv) +} + +func _Maps_Geocode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeocodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).Geocode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apiservice_proto.Maps/Geocode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).Geocode(ctx, req.(*GeocodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_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.(MapsServer).SearchPlaces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apiservice_proto.Maps/SearchPlaces", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).SearchPlaces(ctx, req.(*SearchPlacesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_GetPlaceDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PlaceDetailsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).GetPlaceDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apiservice_proto.Maps/GetPlaceDetails", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).GetPlaceDetails(ctx, req.(*PlaceDetailsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_GetDirections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DirectionsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).GetDirections(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apiservice_proto.Maps/GetDirections", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).GetDirections(ctx, req.(*DirectionsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Maps_GetDistanceMatrix_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DistanceMatrixRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MapsServer).GetDistanceMatrix(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apiservice_proto.Maps/GetDistanceMatrix", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MapsServer).GetDistanceMatrix(ctx, req.(*DistanceMatrixRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Maps_ServiceDesc is the grpc.ServiceDesc for Maps service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Maps_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "apiservice_proto.Maps", + HandlerType: (*MapsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Geocode", + Handler: _Maps_Geocode_Handler, + }, + { + MethodName: "SearchPlaces", + Handler: _Maps_SearchPlaces_Handler, + }, + { + MethodName: "GetPlaceDetails", + Handler: _Maps_GetPlaceDetails_Handler, + }, + { + MethodName: "GetDirections", + Handler: _Maps_GetDirections_Handler, + }, + { + MethodName: "GetDistanceMatrix", + Handler: _Maps_GetDistanceMatrix_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "communication.proto", +} + +// GeminiClient is the client API for Gemini 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 GeminiClient interface { + GenerateContent(ctx context.Context, in *GeminiRequest, opts ...grpc.CallOption) (*GeminiResponse, error) +} + +type geminiClient struct { + cc grpc.ClientConnInterface +} + +func NewGeminiClient(cc grpc.ClientConnInterface) GeminiClient { + return &geminiClient{cc} +} + +func (c *geminiClient) GenerateContent(ctx context.Context, in *GeminiRequest, opts ...grpc.CallOption) (*GeminiResponse, error) { + out := new(GeminiResponse) + err := c.cc.Invoke(ctx, "/apiservice_proto.Gemini/GenerateContent", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GeminiServer is the server API for Gemini service. +// All implementations must embed UnimplementedGeminiServer +// for forward compatibility +type GeminiServer interface { + GenerateContent(context.Context, *GeminiRequest) (*GeminiResponse, error) + mustEmbedUnimplementedGeminiServer() +} + +// UnimplementedGeminiServer must be embedded to have forward compatible implementations. +type UnimplementedGeminiServer struct { +} + +func (UnimplementedGeminiServer) GenerateContent(context.Context, *GeminiRequest) (*GeminiResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateContent not implemented") +} +func (UnimplementedGeminiServer) mustEmbedUnimplementedGeminiServer() {} + +// UnsafeGeminiServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GeminiServer will +// result in compilation errors. +type UnsafeGeminiServer interface { + mustEmbedUnimplementedGeminiServer() +} + +func RegisterGeminiServer(s grpc.ServiceRegistrar, srv GeminiServer) { + s.RegisterService(&Gemini_ServiceDesc, srv) +} + +func _Gemini_GenerateContent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeminiRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GeminiServer).GenerateContent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apiservice_proto.Gemini/GenerateContent", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GeminiServer).GenerateContent(ctx, req.(*GeminiRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Gemini_ServiceDesc is the grpc.ServiceDesc for Gemini service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Gemini_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "apiservice_proto.Gemini", + HandlerType: (*GeminiServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GenerateContent", + Handler: _Gemini_GenerateContent_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "communication.proto", +} diff --git a/planning-service/.gitattributes b/planning-service/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/planning-service/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/planning-service/build.gradle b/planning-service/build.gradle new file mode 100644 index 0000000..c3ceb99 --- /dev/null +++ b/planning-service/build.gradle @@ -0,0 +1,75 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.1' + id 'io.spring.dependency-management' version '1.1.7' + id 'com.google.protobuf' version '0.9.2' +} + +group = 'org.example' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.kafka:spring-kafka' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.kafka:spring-kafka-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + implementation 'com.fasterxml:classmate:1.5.1' + + implementation 'io.grpc:grpc-netty-shaded:1.57.2' + implementation 'io.grpc:grpc-protobuf:1.57.2' + implementation 'io.grpc:grpc-stub:1.57.2' + implementation 'com.google.protobuf:protobuf-java:3.24.4' + + // Removed Vertex AI client library - using local protobuf definitions + // implementation 'com.google.cloud:google-cloud-vertexai:2.43.0' + + compileOnly 'org.apache.tomcat:annotations-api:6.0.53' +} + +tasks.named('test') { + useJUnitPlatform() +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.24.4" + } + plugins { + grpc { + artifact = "io.grpc:protoc-gen-grpc-java:1.57.2" + } + } + generateProtoTasks { + all().each { task -> + task.plugins { + grpc {} + } + } + } +} + +sourceSets { + main { + proto { + // Points to ../proto relative to planning-service/ + srcDirs = ['../proto'] + } + } +} diff --git a/planning-service/gradle/wrapper/gradle-wrapper.jar b/planning-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..a4b76b9 Binary files /dev/null and b/planning-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/planning-service/gradle/wrapper/gradle-wrapper.properties b/planning-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e18bc25 --- /dev/null +++ b/planning-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/planning-service/gradlew b/planning-service/gradlew new file mode 100755 index 0000000..f5feea6 --- /dev/null +++ b/planning-service/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright ยฉ 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป, +# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป; +# * compound commands having a testable exit status, especially ยซcaseยป; +# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/planning-service/gradlew.bat b/planning-service/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/planning-service/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/planning-service/settings.gradle b/planning-service/settings.gradle new file mode 100644 index 0000000..505df99 --- /dev/null +++ b/planning-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'planning-service' diff --git a/planning-service/src/main/java/org/example/planningservice/PlanningServiceApplication.java b/planning-service/src/main/java/org/example/planningservice/PlanningServiceApplication.java new file mode 100644 index 0000000..d2a4739 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/PlanningServiceApplication.java @@ -0,0 +1,13 @@ +package org.example.planningservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PlanningServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(PlanningServiceApplication.class, args); + } + +} diff --git a/planning-service/src/main/java/org/example/planningservice/controller/GrpcTestController.java b/planning-service/src/main/java/org/example/planningservice/controller/GrpcTestController.java new file mode 100644 index 0000000..889bf71 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/controller/GrpcTestController.java @@ -0,0 +1,105 @@ +package org.example.planningservice.controller; + + +import org.example.planningservice.dto.request.*; +import org.example.planningservice.dto.response.*; +import org.example.planningservice.service.grpc.GeminiService; +import org.example.planningservice.service.grpc.GreeterService; // Added +import org.example.planningservice.service.grpc.MapService; +import org.springframework.web.bind.annotation.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +// import org.example.planningservice.grpc.client.GreeterClient; // Removed +// import org.example.planningservice.grpc.client.GeminiClient; // Removed +// import org.example.planningservice.grpc.apiservice.common.HelloReply; // Removed +// import org.example.planningservice.grpc.apiservice.gemini.GeminiResponse; // Removed + + +@RestController +@RequestMapping("/test/grpc") +public class GrpcTestController { + + // private final GreeterClient greeterClient; // Removed + private final GreeterService greeterService; // Added + private final GeminiService geminiService; + private final MapService mapService; + + @Autowired + public GrpcTestController(GreeterService greeterService, GeminiService geminiService, MapService mapService) { // Updated constructor + this.greeterService = greeterService; // Updated + this.geminiService = geminiService; + this.mapService = mapService; + } + + @GetMapping("/hello") + public ResponseEntity sayHello(@RequestParam(defaultValue = "World") String name) { + try { + GreeterRequestDTO requestDTO = new GreeterRequestDTO(name); + GreeterResponseDTO responseDTO = greeterService.sayHello(requestDTO); + return ResponseEntity.ok(responseDTO.getMessage()); + } catch (Exception e) { + return ResponseEntity.internalServerError().body("Error calling Greeter service: " + e.getMessage()); + } + } + + @GetMapping("/gemini/generate") + public ResponseEntity generateContent(@RequestParam String prompt) { + try { + GeminiRequestDTO requestDTO = new GeminiRequestDTO(prompt); + GeminiResponseDTO responseDTO = geminiService.generateContent(requestDTO); + return ResponseEntity.ok(responseDTO); + } catch (Exception e) { + return ResponseEntity.internalServerError().body("Error calling Gemini service: " + e.getMessage()); + } + } + + @GetMapping("/maps/geocode") + public ResponseEntity geocode(@RequestParam String address) { + try { + GeocodeResponseDTO response = mapService.geocode(new GeocodeRequestDTO(address)); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.internalServerError().body("Error calling Maps Geocode: " + e.getMessage()); + } + } + + @GetMapping("/maps/search") + public ResponseEntity searchPlaces(@RequestParam String query, @RequestParam String location) { + try { + SearchPlacesResponseDTO response = mapService.searchPlaces(new SearchPlacesRequestDTO(query, location)); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.internalServerError().body("Error calling Maps SearchPlaces: " + e.getMessage()); + } + } + + @GetMapping("/maps/details/{placeId}") + public ResponseEntity getPlaceDetails(@PathVariable String placeId) { + try { + PlaceDetailsResponseDTO response = mapService.getPlaceDetails(placeId); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.internalServerError().body("Error calling Maps GetPlaceDetails: " + e.getMessage()); + } + } + + @GetMapping("/maps/directions") + public ResponseEntity getDirections(@RequestParam String origin, @RequestParam String destination) { + try { + DirectionsResponseDTO response = mapService.getDirections(new DirectionsRequestDTO(origin, destination)); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.internalServerError().body("Error calling Maps GetDirections: " + e.getMessage()); + } + } + + @GetMapping("/maps/distancematrix") + public ResponseEntity getDistanceMatrix(@RequestParam String origins, @RequestParam String destinations) { + try { + DistanceMatrixResponseDTO response = mapService.getDistanceMatrix(new DistanceMatrixRequestDTO(origins, destinations)); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.internalServerError().body("Error calling Maps GetDistanceMatrix: " + e.getMessage()); + } + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/controller/PathController.java b/planning-service/src/main/java/org/example/planningservice/controller/PathController.java new file mode 100644 index 0000000..0e09a36 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/controller/PathController.java @@ -0,0 +1,37 @@ +package org.example.planningservice.controller; + +import lombok.extern.slf4j.Slf4j; +import org.example.planningservice.dto.request.DirectionsRequestDTO; +import org.example.planningservice.dto.response.DirectionsResponseDTO; +import org.example.planningservice.exception.DirectionsServiceException; +import org.example.planningservice.pipeline.path.PathFindingPipe; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/pipeline") +public class PathController { + + @Autowired + private PathFindingPipe pathFindingPipe; + + @PostMapping("/path") + public ResponseEntity executePipeline(@RequestBody DirectionsRequestDTO routeRequest) { + + try { + DirectionsResponseDTO response = pathFindingPipe.execute(routeRequest); + return ResponseEntity.ok(response); + } catch (DirectionsServiceException e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); + } catch (IllegalArgumentException e) { + return ResponseEntity.badRequest().body(e.getMessage()); + } + + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/dto/request/DirectionsRequestDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/request/DirectionsRequestDTO.java new file mode 100644 index 0000000..b6d6be9 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/request/DirectionsRequestDTO.java @@ -0,0 +1,18 @@ +package org.example.planningservice.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DirectionsRequestDTO { + private String origin; + private String destination; + + public boolean isBlank() { + return origin == null || origin.isBlank() + || destination == null || destination.isBlank(); + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/dto/request/DistanceMatrixRequestDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/request/DistanceMatrixRequestDTO.java new file mode 100644 index 0000000..1af33ed --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/request/DistanceMatrixRequestDTO.java @@ -0,0 +1,13 @@ +package org.example.planningservice.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DistanceMatrixRequestDTO { + private String origins; + private String destinations; +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/dto/request/GeminiRequestDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/request/GeminiRequestDTO.java new file mode 100644 index 0000000..2c92175 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/request/GeminiRequestDTO.java @@ -0,0 +1,20 @@ +package org.example.planningservice.dto.request; + +public class GeminiRequestDTO { + private String prompt; + + public GeminiRequestDTO() { + } + + public GeminiRequestDTO(String prompt) { + this.prompt = prompt; + } + + public String getPrompt() { + return prompt; + } + + public void setPrompt(String prompt) { + this.prompt = prompt; + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/dto/request/GeocodeRequestDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/request/GeocodeRequestDTO.java new file mode 100644 index 0000000..ff8c589 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/request/GeocodeRequestDTO.java @@ -0,0 +1,13 @@ +package org.example.planningservice.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GeocodeRequestDTO { + private String address; +} + diff --git a/planning-service/src/main/java/org/example/planningservice/dto/request/GreeterRequestDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/request/GreeterRequestDTO.java new file mode 100644 index 0000000..a43618b --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/request/GreeterRequestDTO.java @@ -0,0 +1,20 @@ +package org.example.planningservice.dto.request; + +public class GreeterRequestDTO { + private String name; + + public GreeterRequestDTO() { + } + + public GreeterRequestDTO(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/dto/request/SearchPlacesRequestDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/request/SearchPlacesRequestDTO.java new file mode 100644 index 0000000..7824da3 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/request/SearchPlacesRequestDTO.java @@ -0,0 +1,13 @@ +package org.example.planningservice.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SearchPlacesRequestDTO { + private String query; + private String location; +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/dto/response/DirectionsResponseDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/response/DirectionsResponseDTO.java new file mode 100644 index 0000000..88fbf0f --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/response/DirectionsResponseDTO.java @@ -0,0 +1,93 @@ +package org.example.planningservice.dto.response; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DirectionsResponseDTO { + private List routes; + private List geocodedWaypoints; + private String status; + + @JsonIgnore + public boolean isBlank() { + if (!"OK".equalsIgnoreCase(status)) return true; + if (routes == null || routes.isEmpty()) return true; + + RouteDTO firstRoute = routes.get(0); + if (firstRoute.getLegs() == null || firstRoute.getLegs().isEmpty()) return true; + if (firstRoute.getOverviewPolyline() == null || + firstRoute.getOverviewPolyline().getPoints() == null || + firstRoute.getOverviewPolyline().getPoints().isBlank()) return true; + + return false; // Not blank โ€” has valid content + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class RouteDTO { + private String summary; + private List legs; + private PolylineDTO overviewPolyline; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class LegDTO { + private DistanceDTO distance; + private DurationDTO duration; + private String startAddress; + private String endAddress; + private List steps; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class StepDTO { + private String htmlInstructions; + private DistanceDTO distance; + private DurationDTO duration; + private PolylineDTO polyline; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class PolylineDTO { + private String points; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class DistanceDTO { + private String text; + private int value; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class DurationDTO { + private String text; + private int value; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class GeocodedWaypointDTO { + private String geocoderStatus; + private String placeId; + private List types; + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/dto/response/DistanceMatrixResponseDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/response/DistanceMatrixResponseDTO.java new file mode 100644 index 0000000..6db872e --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/response/DistanceMatrixResponseDTO.java @@ -0,0 +1,33 @@ +package org.example.planningservice.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DistanceMatrixResponseDTO { + private List originAddresses; + private List destinationAddresses; + private List rows; + private String status; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class RowDTO { + private List elements; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ElementDTO { + private String status; + private DirectionsResponseDTO.DurationDTO duration; + private DirectionsResponseDTO.DistanceDTO distance; + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/dto/response/GeminiResponseDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/response/GeminiResponseDTO.java new file mode 100644 index 0000000..768acd1 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/response/GeminiResponseDTO.java @@ -0,0 +1,20 @@ +package org.example.planningservice.dto.response; + +public class GeminiResponseDTO { + private String generatedContent; + + public GeminiResponseDTO() { + } + + public GeminiResponseDTO(String generatedContent) { + this.generatedContent = generatedContent; + } + + public String getGeneratedContent() { + return generatedContent; + } + + public void setGeneratedContent(String generatedContent) { + this.generatedContent = generatedContent; + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/dto/response/GeocodeResponseDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/response/GeocodeResponseDTO.java new file mode 100644 index 0000000..93eb70f --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/response/GeocodeResponseDTO.java @@ -0,0 +1,31 @@ +package org.example.planningservice.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GeocodeResponseDTO { + private List results; + private String status; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ResultDTO { + private String formattedAddress; + private LocationDTO location; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class LocationDTO { + private double lat; + private double lng; + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/dto/response/GreeterResponseDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/response/GreeterResponseDTO.java new file mode 100644 index 0000000..bc40e0c --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/response/GreeterResponseDTO.java @@ -0,0 +1,20 @@ +package org.example.planningservice.dto.response; + +public class GreeterResponseDTO { + private String message; + + public GreeterResponseDTO() { + } + + public GreeterResponseDTO(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/dto/response/PlaceDetailsResponseDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/response/PlaceDetailsResponseDTO.java new file mode 100644 index 0000000..4f066e8 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/response/PlaceDetailsResponseDTO.java @@ -0,0 +1,13 @@ +package org.example.planningservice.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PlaceDetailsResponseDTO { + private SearchPlacesResponseDTO.PlaceDTO result; + private String status; +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/dto/response/SearchPlacesResponseDTO.java b/planning-service/src/main/java/org/example/planningservice/dto/response/SearchPlacesResponseDTO.java new file mode 100644 index 0000000..4090767 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/dto/response/SearchPlacesResponseDTO.java @@ -0,0 +1,55 @@ +package org.example.planningservice.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SearchPlacesResponseDTO { + private List results; + private String status; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class PlaceDTO { + private String placeId; + private String name; + private String vicinity; + private double rating; + private int userRatingsTotal; + private LocationDTO geometryLocation; + private OpeningHoursDTO openingHours; + private List photos; + private List photoUrls; + private List types; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class PhotoDTO { + private String photoReference; + private int height; + private int width; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class OpeningHoursDTO { + private boolean openNow; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class LocationDTO { + private double lat; + private double lng; + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/exception/DirectionsServiceException.java b/planning-service/src/main/java/org/example/planningservice/exception/DirectionsServiceException.java new file mode 100644 index 0000000..a1b90a1 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/exception/DirectionsServiceException.java @@ -0,0 +1,7 @@ +package org.example.planningservice.exception; + +public class DirectionsServiceException extends RuntimeException { + public DirectionsServiceException(String message) { + super(message); + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/framework/pipeline/Block.java b/planning-service/src/main/java/org/example/planningservice/framework/pipeline/Block.java new file mode 100644 index 0000000..ff767bc --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/framework/pipeline/Block.java @@ -0,0 +1,11 @@ +package org.example.planningservice.framework.pipeline; + +/** + * Represents a processing block in a pipeline. + * + * @param the input type + * @param the output type + */ +public interface Block { + O process(I input); +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/framework/pipeline/Pipe.java b/planning-service/src/main/java/org/example/planningservice/framework/pipeline/Pipe.java new file mode 100644 index 0000000..1f076a9 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/framework/pipeline/Pipe.java @@ -0,0 +1,24 @@ +package org.example.planningservice.framework.pipeline; + +/** + * Represents a pipeline. + * + * @param the input type + * @param the output type + */ +public class Pipe { + + public final Block current; + + public Pipe(Block current) { + this.current = current; + } + + public Pipe connect(Block next) { + return new Pipe<>(input -> next.process(current.process(input))); + } + + public O execute(I input) { + return current.process(input); + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/grpc/client/GeminiClient.java b/planning-service/src/main/java/org/example/planningservice/grpc/client/GeminiClient.java new file mode 100644 index 0000000..bdc2e81 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/grpc/client/GeminiClient.java @@ -0,0 +1,45 @@ +package org.example.planningservice.grpc.client; + +import org.example.planningservice.grpc.apiservice.gemini.GeminiGrpc; +import org.example.planningservice.grpc.apiservice.gemini.GeminiRequest; +import org.example.planningservice.grpc.apiservice.gemini.GeminiResponse; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import java.util.concurrent.TimeUnit; + +@Service +public class GeminiClient { + + private ManagedChannel channel; + private GeminiGrpc.GeminiBlockingStub blockingStub; + + @Value("${api.service.host:localhost}") + private String apiServiceHost; + + @Value("${api.service.port:8001}") + private int apiServicePort; + + @PostConstruct + private void init() { + channel = ManagedChannelBuilder.forAddress(apiServiceHost, apiServicePort) + .usePlaintext() + .build(); + blockingStub = GeminiGrpc.newBlockingStub(channel); + } + + public GeminiResponse generateContent(String prompt) { + GeminiRequest request = GeminiRequest.newBuilder().setPrompt(prompt).build(); + return blockingStub.generateContent(request); + } + + @PreDestroy + public void shutdown() throws InterruptedException { + if (channel != null) { + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/grpc/client/GreeterClient.java b/planning-service/src/main/java/org/example/planningservice/grpc/client/GreeterClient.java new file mode 100644 index 0000000..4811ff4 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/grpc/client/GreeterClient.java @@ -0,0 +1,66 @@ +package org.example.planningservice.grpc.client; + +import org.example.planningservice.grpc.apiservice.common.ExampleGreeterGrpc; +import org.example.planningservice.grpc.apiservice.common.HelloRequest; +import org.example.planningservice.grpc.apiservice.common.HelloReply; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +@Service +public class GreeterClient { + private static final Logger logger = Logger.getLogger(GreeterClient.class.getName()); + + private ManagedChannel channel; + private ExampleGreeterGrpc.ExampleGreeterBlockingStub blockingStub; + + @Value("${api.service.host:localhost}") + private String apiServiceHost; + + @Value("${api.service.port:8001}") // Matches the updated port in application.properties + private int apiServicePort; + + @PostConstruct + private void init() { + logger.info("Initializing GreeterClient for " + apiServiceHost + ":" + apiServicePort); + channel = ManagedChannelBuilder.forAddress(apiServiceHost, apiServicePort) + .usePlaintext() // For simplicity in dev; use SSL/TLS in production + .build(); + blockingStub = ExampleGreeterGrpc.newBlockingStub(channel); + } + + @PreDestroy + public void shutdown() throws InterruptedException { + if (channel != null) { + logger.info("Shutting down GreeterClient channel"); + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + + /** Say hello to server. */ + public HelloReply sayHello(String name) { + logger.info("Attempting to greet " + name + " via gRPC..."); + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + // The try-catch block can be here for logging, or removed if errors are to be handled by the caller (controller) + try { + HelloReply response = blockingStub.sayHello(request); + logger.info("Successfully greeted " + name + ". Response: " + response.getMessage()); + return response; + } catch (Exception e) { + logger.log(Level.SEVERE, "gRPC call to Greeter service failed for name: " + name, e); + throw e; // Re-throw the exception to be handled by the controller + } + } + + /** + * Greet server. If provided, the first element of {@code args} is the name to use in the + * greeting. + */ + // Main method removed as this class is now a Spring managed bean +} diff --git a/planning-service/src/main/java/org/example/planningservice/grpc/client/MapsClient.java b/planning-service/src/main/java/org/example/planningservice/grpc/client/MapsClient.java new file mode 100644 index 0000000..7b35ecd --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/grpc/client/MapsClient.java @@ -0,0 +1,72 @@ +package org.example.planningservice.grpc.client; + +import org.example.planningservice.grpc.apiservice.maps.*; // Import all maps grpc classes +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import java.util.concurrent.TimeUnit; + +@Service +public class MapsClient { + + private ManagedChannel channel; + private MapsGrpc.MapsBlockingStub blockingStub; + + @Value("${api.service.host:localhost}") + private String apiServiceHost; + + @Value("${api.service.port:8001}") + private int apiServicePort; + + @PostConstruct + private void init() { + channel = ManagedChannelBuilder.forAddress(apiServiceHost, apiServicePort) + .usePlaintext() + .build(); + blockingStub = MapsGrpc.newBlockingStub(channel); + } + + public GeocodeResponse geocode(String address) { + GeocodeRequest request = GeocodeRequest.newBuilder().setAddress(address).build(); + return blockingStub.geocode(request); + } + + public SearchPlacesResponse searchPlaces(String query, String location) { + SearchPlacesRequest request = SearchPlacesRequest.newBuilder() + .setQuery(query) + .setLocation(location) + .build(); + return blockingStub.searchPlaces(request); + } + + public PlaceDetailsResponse getPlaceDetails(String placeId) { + PlaceDetailsRequest request = PlaceDetailsRequest.newBuilder().setPlaceId(placeId).build(); + return blockingStub.getPlaceDetails(request); + } + + public DirectionsResponse getDirections(String origin, String destination) { + DirectionsRequest request = DirectionsRequest.newBuilder() + .setOrigin(origin) + .setDestination(destination) + .build(); + return blockingStub.getDirections(request); + } + + public DistanceMatrixResponse getDistanceMatrix(String origins, String destinations) { + DistanceMatrixRequest request = DistanceMatrixRequest.newBuilder() + .setOrigins(origins) + .setDestinations(destinations) + .build(); + return blockingStub.getDistanceMatrix(request); + } + + @PreDestroy + public void shutdown() throws InterruptedException { + if (channel != null) { + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/pipeline/path/PathFindingPipe.java b/planning-service/src/main/java/org/example/planningservice/pipeline/path/PathFindingPipe.java new file mode 100644 index 0000000..042d137 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/pipeline/path/PathFindingPipe.java @@ -0,0 +1,39 @@ +package org.example.planningservice.pipeline.path; + +import lombok.extern.slf4j.Slf4j; +import org.example.planningservice.dto.request.DirectionsRequestDTO; +import org.example.planningservice.dto.response.DirectionsResponseDTO; +import org.example.planningservice.framework.pipeline.Pipe; +import org.example.planningservice.pipeline.path.blocks.DataTransformationBlock; +import org.example.planningservice.pipeline.path.blocks.StorageBlock; +import org.example.planningservice.pipeline.path.blocks.ValidationBlock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class PathFindingPipe { + + @Autowired + private DataTransformationBlock dataTransformationBlock; + + @Autowired + private StorageBlock storageBlock; + + @Autowired + private ValidationBlock validationBlock; + + public DirectionsResponseDTO execute(DirectionsRequestDTO routeRequest) { + Pipe pathFindingPipe = createPathFindingPipe(); + log.info("=== created the pipeline (not executed yet) ==="); + + // Execute the pipeline + return pathFindingPipe.execute(routeRequest); + } + + private Pipe createPathFindingPipe() { + return new Pipe<>(validationBlock) + .connect(dataTransformationBlock) + .connect(storageBlock); + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/DataTransformationBlock.java b/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/DataTransformationBlock.java new file mode 100644 index 0000000..0193358 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/DataTransformationBlock.java @@ -0,0 +1,39 @@ +package org.example.planningservice.pipeline.path.blocks; + +import lombok.extern.slf4j.Slf4j; +import org.example.planningservice.dto.request.DirectionsRequestDTO; +import org.example.planningservice.dto.response.DirectionsResponseDTO; +import org.example.planningservice.exception.DirectionsServiceException; +import org.example.planningservice.framework.pipeline.Block; +import org.example.planningservice.service.grpc.MapService; +import org.springframework.stereotype.Component; + + +@Slf4j +@Component +public class DataTransformationBlock implements Block { + + private final MapService mapService; + + public DataTransformationBlock(MapService mapService) { + this.mapService = mapService; + } + + @Override + public DirectionsResponseDTO process(DirectionsRequestDTO routeRequest) { + try { + DirectionsResponseDTO response = mapService.getDirections(routeRequest); + + if (response == null || response.isBlank()) { + throw new IllegalArgumentException("Invalid retrieved data!"); + } + + log.info("๐ŸšŒ Data Transformation Completed: {}", response); + + return response; + + } catch (Exception e) { + throw new DirectionsServiceException("Error calling Maps GetDirections: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/StorageBlock.java b/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/StorageBlock.java new file mode 100644 index 0000000..a791056 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/StorageBlock.java @@ -0,0 +1,19 @@ +package org.example.planningservice.pipeline.path.blocks; + +import lombok.extern.slf4j.Slf4j; +import org.example.planningservice.dto.response.DirectionsResponseDTO; +import org.example.planningservice.framework.pipeline.Block; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class StorageBlock implements Block { + + @Override + public DirectionsResponseDTO process(DirectionsResponseDTO path) { + + log.info("\uD83D\uDCBE Data Stored: {}", path); + + return path; + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/ValidationBlock.java b/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/ValidationBlock.java new file mode 100644 index 0000000..7589f69 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/pipeline/path/blocks/ValidationBlock.java @@ -0,0 +1,21 @@ +package org.example.planningservice.pipeline.path.blocks; + +import lombok.extern.slf4j.Slf4j; +import org.example.planningservice.dto.request.DirectionsRequestDTO; +import org.example.planningservice.framework.pipeline.Block; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class ValidationBlock implements Block { + + @Override + public DirectionsRequestDTO process(DirectionsRequestDTO routeRequest) { + if (routeRequest == null || routeRequest.isBlank()) { + throw new IllegalArgumentException("Invalid input data!"); + } + + log.info("โœ… Validation Passed: {}", routeRequest); + return routeRequest; + } +} \ No newline at end of file diff --git a/planning-service/src/main/java/org/example/planningservice/service/grpc/GeminiService.java b/planning-service/src/main/java/org/example/planningservice/service/grpc/GeminiService.java new file mode 100644 index 0000000..9997e6a --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/service/grpc/GeminiService.java @@ -0,0 +1,8 @@ +package org.example.planningservice.service.grpc; + +import org.example.planningservice.dto.request.GeminiRequestDTO; +import org.example.planningservice.dto.response.GeminiResponseDTO; + +public interface GeminiService { + GeminiResponseDTO generateContent(GeminiRequestDTO request); +} diff --git a/planning-service/src/main/java/org/example/planningservice/service/grpc/GreeterService.java b/planning-service/src/main/java/org/example/planningservice/service/grpc/GreeterService.java new file mode 100644 index 0000000..e910d7b --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/service/grpc/GreeterService.java @@ -0,0 +1,8 @@ +package org.example.planningservice.service.grpc; + +import org.example.planningservice.dto.request.GreeterRequestDTO; +import org.example.planningservice.dto.response.GreeterResponseDTO; + +public interface GreeterService { + GreeterResponseDTO sayHello(GreeterRequestDTO request); +} diff --git a/planning-service/src/main/java/org/example/planningservice/service/grpc/MapService.java b/planning-service/src/main/java/org/example/planningservice/service/grpc/MapService.java new file mode 100644 index 0000000..bfd0596 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/service/grpc/MapService.java @@ -0,0 +1,12 @@ +package org.example.planningservice.service.grpc; + +import org.example.planningservice.dto.request.*; +import org.example.planningservice.dto.response.*; + +public interface MapService { + GeocodeResponseDTO geocode(GeocodeRequestDTO request); + SearchPlacesResponseDTO searchPlaces(SearchPlacesRequestDTO request); + PlaceDetailsResponseDTO getPlaceDetails(String placeId); + DirectionsResponseDTO getDirections(DirectionsRequestDTO request); + DistanceMatrixResponseDTO getDistanceMatrix(DistanceMatrixRequestDTO request); +} diff --git a/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/GeminiServiceImpl.java b/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/GeminiServiceImpl.java new file mode 100644 index 0000000..fa10ddc --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/GeminiServiceImpl.java @@ -0,0 +1,33 @@ +package org.example.planningservice.service.grpc.impl; + +import org.example.planningservice.grpc.apiservice.gemini.GeminiResponse; // Corrected import from proto +import org.example.planningservice.grpc.client.GeminiClient; +import org.example.planningservice.dto.request.GeminiRequestDTO; +import org.example.planningservice.dto.response.GeminiResponseDTO; +import org.example.planningservice.service.grpc.GeminiService; +import org.springframework.stereotype.Service; + +@Service +public class GeminiServiceImpl implements GeminiService { + + private final GeminiClient geminiClient; + + public GeminiServiceImpl(GeminiClient geminiClient) { + this.geminiClient = geminiClient; + } + + @Override + public GeminiResponseDTO generateContent(GeminiRequestDTO request) { + GeminiResponse response = geminiClient.generateContent(request.getPrompt()); // Corrected type + // The existing mapping logic seems compatible with the proto structure. + // For now, let's assume a simple getText() or similar method. + // If the actual response is more complex, this mapping will need to be more sophisticated. + String generatedText = ""; + if (response != null && response.getCandidatesCount() > 0 && + response.getCandidates(0).hasContent() && // Check if content exists + response.getCandidates(0).getContent().getPartsCount() > 0) { + generatedText = response.getCandidates(0).getContent().getParts(0).getText(); + } + return new GeminiResponseDTO(generatedText); + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/GreeterServiceImpl.java b/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/GreeterServiceImpl.java new file mode 100644 index 0000000..9890945 --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/GreeterServiceImpl.java @@ -0,0 +1,24 @@ +package org.example.planningservice.service.grpc.impl; + +import org.example.planningservice.grpc.client.GreeterClient; // Corrected import +import org.example.planningservice.dto.request.GreeterRequestDTO; +import org.example.planningservice.dto.response.GreeterResponseDTO; +import org.example.planningservice.grpc.apiservice.common.HelloReply; +import org.example.planningservice.service.grpc.GreeterService; +import org.springframework.stereotype.Service; + +@Service +public class GreeterServiceImpl implements GreeterService { + + private final GreeterClient greeterClient; + + public GreeterServiceImpl(GreeterClient greeterClient) { + this.greeterClient = greeterClient; + } + + @Override + public GreeterResponseDTO sayHello(GreeterRequestDTO request) { + HelloReply reply = greeterClient.sayHello(request.getName()); + return new GreeterResponseDTO(reply.getMessage()); + } +} diff --git a/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/MapServiceImpl.java b/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/MapServiceImpl.java new file mode 100644 index 0000000..d17e55b --- /dev/null +++ b/planning-service/src/main/java/org/example/planningservice/service/grpc/impl/MapServiceImpl.java @@ -0,0 +1,149 @@ +package org.example.planningservice.service.grpc.impl; + +import org.example.planningservice.dto.request.*; +import org.example.planningservice.dto.response.*; +import org.example.planningservice.grpc.apiservice.maps.*; +import org.example.planningservice.grpc.client.MapsClient; +import org.example.planningservice.service.grpc.MapService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class MapServiceImpl implements MapService { + + private final MapsClient mapsClient; + + public MapServiceImpl(MapsClient mapsClient) { + this.mapsClient = mapsClient; + } + + @Override + public GeocodeResponseDTO geocode(GeocodeRequestDTO request) { + GeocodeResponse response = mapsClient.geocode(request.getAddress()); + List results = response.getResultsList().stream() + .map(r -> new GeocodeResponseDTO.ResultDTO( + r.getFormattedAddress(), + new GeocodeResponseDTO.LocationDTO( + r.getLocation().getLat(), + r.getLocation().getLng() + ) + )).collect(Collectors.toList()); + return new GeocodeResponseDTO(results, response.getStatus()); + } + + @Override + public SearchPlacesResponseDTO searchPlaces(SearchPlacesRequestDTO request) { + SearchPlacesResponse response = mapsClient.searchPlaces(request.getQuery(), request.getLocation()); + List places = response.getResultsList().stream().map(place -> { + SearchPlacesResponseDTO.LocationDTO loc = new SearchPlacesResponseDTO.LocationDTO( + place.getGeometryLocation().getLat(), + place.getGeometryLocation().getLng() + ); + List photos = place.getPhotosList().stream().map(photo -> + new SearchPlacesResponseDTO.PhotoDTO( + photo.getPhotoReference(), + photo.getHeight(), + photo.getWidth() + )).collect(Collectors.toList()); + SearchPlacesResponseDTO.OpeningHoursDTO openingHours = new SearchPlacesResponseDTO.OpeningHoursDTO( + place.getOpeningHours().getOpenNow() + ); + return new SearchPlacesResponseDTO.PlaceDTO( + place.getPlaceId(), + place.getName(), + place.getVicinity(), + place.getRating(), + place.getUserRatingsTotal(), + loc, + openingHours, + photos, + place.getPhotoUrlsList(), + place.getTypesList() + ); + }).collect(Collectors.toList()); + return new SearchPlacesResponseDTO(places, response.getStatus()); + } + + @Override + public PlaceDetailsResponseDTO getPlaceDetails(String placeId) { + PlaceDetailsResponse response = mapsClient.getPlaceDetails(placeId); + Place place = response.getResult(); + SearchPlacesResponseDTO.PlaceDTO placeDTO = new SearchPlacesResponseDTO.PlaceDTO( + place.getPlaceId(), + place.getName(), + place.getVicinity(), + place.getRating(), + place.getUserRatingsTotal(), + new SearchPlacesResponseDTO.LocationDTO( + place.getGeometryLocation().getLat(), + place.getGeometryLocation().getLng() + ), + new SearchPlacesResponseDTO.OpeningHoursDTO( + place.getOpeningHours().getOpenNow() + ), + place.getPhotosList().stream().map(photo -> + new SearchPlacesResponseDTO.PhotoDTO( + photo.getPhotoReference(), + photo.getHeight(), + photo.getWidth() + )).collect(Collectors.toList()), + place.getPhotoUrlsList(), + place.getTypesList() + ); + return new PlaceDetailsResponseDTO(placeDTO, response.getStatus()); + } + + @Override + public DirectionsResponseDTO getDirections(DirectionsRequestDTO request) { + DirectionsResponse response = mapsClient.getDirections(request.getOrigin(), request.getDestination()); + + List routes = response.getRoutesList().stream().map(route -> { + DirectionsResponseDTO.PolylineDTO overview = new DirectionsResponseDTO.PolylineDTO(route.getOverviewPolyline().getPoints()); + List legs = route.getLegsList().stream().map(leg -> { + List steps = leg.getStepsList().stream().map(step -> + new DirectionsResponseDTO.StepDTO( + step.getHtmlInstructions(), + new DirectionsResponseDTO.DistanceDTO(step.getDistance().getText(), step.getDistance().getValue()), + new DirectionsResponseDTO.DurationDTO(step.getDuration().getText(), step.getDuration().getValue()), + new DirectionsResponseDTO.PolylineDTO(step.getPolyline().getPoints()) + )).collect(Collectors.toList()); + return new DirectionsResponseDTO.LegDTO( + new DirectionsResponseDTO.DistanceDTO(leg.getDistance().getText(), leg.getDistance().getValue()), + new DirectionsResponseDTO.DurationDTO(leg.getDuration().getText(), leg.getDuration().getValue()), + leg.getStartAddress(), + leg.getEndAddress(), + steps + ); + }).collect(Collectors.toList()); + return new DirectionsResponseDTO.RouteDTO(route.getSummary(), legs, overview); + }).collect(Collectors.toList()); + + List waypoints = response.getGeocodedWaypointsList().stream() + .map(wp -> new DirectionsResponseDTO.GeocodedWaypointDTO(wp.getGeocoderStatus(), wp.getPlaceId(), wp.getTypesList())) + .collect(Collectors.toList()); + + return new DirectionsResponseDTO(routes, waypoints, response.getStatus()); + } + + @Override + public DistanceMatrixResponseDTO getDistanceMatrix(DistanceMatrixRequestDTO request) { + DistanceMatrixResponse response = mapsClient.getDistanceMatrix(request.getOrigins(), request.getDestinations()); + List rows = response.getRowsList().stream().map(row -> { + List elements = row.getElementsList().stream().map(el -> + new DistanceMatrixResponseDTO.ElementDTO( + el.getStatus(), + new DirectionsResponseDTO.DurationDTO(el.getDuration().getText(), el.getDuration().getValue()), + new DirectionsResponseDTO.DistanceDTO(el.getDistance().getText(), el.getDistance().getValue()) + )).collect(Collectors.toList()); + return new DistanceMatrixResponseDTO.RowDTO(elements); + }).collect(Collectors.toList()); + return new DistanceMatrixResponseDTO( + response.getOriginAddressesList(), + response.getDestinationAddressesList(), + rows, + response.getStatus() + ); + } +} \ No newline at end of file diff --git a/planning-service/src/main/proto/common.proto b/planning-service/src/main/proto/common.proto new file mode 100644 index 0000000..c643289 --- /dev/null +++ b/planning-service/src/main/proto/common.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package common_proto; + +option go_package = "api-service/grpc/pb/common"; +option java_package = "com.example.planning.grpc"; +option java_multiple_files = true; + +service Greeter { + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +message HelloRequest { + string name = 1; +} +message HelloReply { + string message = 1; +} diff --git a/planning-service/src/main/resources/application.properties b/planning-service/src/main/resources/application.properties new file mode 100644 index 0000000..b97f1d8 --- /dev/null +++ b/planning-service/src/main/resources/application.properties @@ -0,0 +1,6 @@ +spring.application.name=planning-service +server.port=8081 + +# API Service gRPC Endpoint +api.service.host=localhost +api.service.port=50051 diff --git a/planning-service/src/test/java/org/example/planningservice/PlanningServiceApplicationTests.java b/planning-service/src/test/java/org/example/planningservice/PlanningServiceApplicationTests.java new file mode 100644 index 0000000..73172b0 --- /dev/null +++ b/planning-service/src/test/java/org/example/planningservice/PlanningServiceApplicationTests.java @@ -0,0 +1,13 @@ +package org.example.planningservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PlanningServiceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/planning-service/src/test/java/org/example/planningservice/grpc/client/GeminiClientTest.java b/planning-service/src/test/java/org/example/planningservice/grpc/client/GeminiClientTest.java new file mode 100644 index 0000000..e5df505 --- /dev/null +++ b/planning-service/src/test/java/org/example/planningservice/grpc/client/GeminiClientTest.java @@ -0,0 +1,32 @@ +package org.example.planningservice.grpc.client; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.example.planningservice.PlanningServiceApplication; +import org.example.planningservice.grpc.client.GeminiClient; // Updated import + +@SpringBootTest(classes = PlanningServiceApplication.class) +public class GeminiClientTest { + + @Autowired + private GeminiClient geminiClient; + + @Test + void contextLoads() { + assertNotNull(geminiClient, "GeminiClient should be loaded from Spring context"); + } + + @Test + void testGenerateContent_Placeholder() { + // This is a placeholder test. + // In a real scenario, you would mock the gRPC service or use a test server. + // For now, we just check if the client is available. + assertNotNull(geminiClient, "GeminiClient is available"); + // Example of how you might call it (would require a running/mocked server): + // String prompt = "Test prompt"; + // org.example.planningservice.grpc.apiservice.gemini.GeminiResponse response = geminiClient.generateContent(prompt); + // assertNotNull(response); + } +} diff --git a/planning-service/src/test/java/org/example/planningservice/grpc/client/MapsClientTest.java b/planning-service/src/test/java/org/example/planningservice/grpc/client/MapsClientTest.java new file mode 100644 index 0000000..e694a26 --- /dev/null +++ b/planning-service/src/test/java/org/example/planningservice/grpc/client/MapsClientTest.java @@ -0,0 +1,34 @@ +package org.example.planningservice.grpc.client; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.example.planningservice.PlanningServiceApplication; +import org.example.planningservice.grpc.client.MapsClient; // Updated import + +@SpringBootTest(classes = PlanningServiceApplication.class) +public class MapsClientTest { + + @Autowired + private MapsClient mapsClient; + + @Test + void contextLoads() { + assertNotNull(mapsClient, "MapsClient should be loaded from Spring context"); + } + + @Test + void testGeocode_Placeholder() { + assertNotNull(mapsClient, "MapsClient is available"); + // Example: mapsClient.geocode("1600 Amphitheatre Parkway, Mountain View, CA"); + } + + @Test + void testSearchPlaces_Placeholder() { + assertNotNull(mapsClient, "MapsClient is available"); + // Example: mapsClient.searchPlaces("restaurants", "Mountain View, CA"); + } + + // Add more placeholder tests for other MapsClient methods if desired +} diff --git a/planning-service/src/test/java/org/example/planningservice/service/grpc/impl/GeminiServiceImplTest.java b/planning-service/src/test/java/org/example/planningservice/service/grpc/impl/GeminiServiceImplTest.java new file mode 100644 index 0000000..66452d9 --- /dev/null +++ b/planning-service/src/test/java/org/example/planningservice/service/grpc/impl/GeminiServiceImplTest.java @@ -0,0 +1,134 @@ +package org.example.planningservice.service.grpc.impl; + +import org.example.planningservice.grpc.apiservice.gemini.GeminiResponse; // Corrected import +import org.example.planningservice.grpc.apiservice.gemini.GeminiResponse.Candidate; // Corrected import +import org.example.planningservice.grpc.apiservice.gemini.GeminiResponse.Content; // Corrected import +import org.example.planningservice.grpc.apiservice.gemini.GeminiResponse.ContentPart; // Corrected import +import org.example.planningservice.grpc.client.GeminiClient; // Corrected import +import org.example.planningservice.dto.request.GeminiRequestDTO; +import org.example.planningservice.dto.response.GeminiResponseDTO; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class GeminiServiceImplTest { + + @Mock + private GeminiClient geminiClient; + + @InjectMocks + private GeminiServiceImpl geminiService; + + private GeminiRequestDTO requestDTO; + private GeminiResponse grpcResponse; // Corrected type + private String prompt; + private String expectedResponseText; + + @BeforeEach + void setUp() { + prompt = "Test prompt"; + requestDTO = new GeminiRequestDTO(prompt); + + expectedResponseText = "Generated content text"; + // Corrected builder according to local proto definition + ContentPart part = ContentPart.newBuilder().setText(expectedResponseText).build(); + Content content = Content.newBuilder().addParts(part).build(); + Candidate candidate = Candidate.newBuilder().setContent(content).build(); + grpcResponse = GeminiResponse.newBuilder().addCandidates(candidate).build(); + } + + @Test + void generateContent_shouldReturnMappedDTO_whenClientReturnsResponse() { + // Arrange + when(geminiClient.generateContent(prompt)).thenReturn(grpcResponse); + + // Act + GeminiResponseDTO actualResponseDTO = geminiService.generateContent(requestDTO); + + // Assert + assertEquals(expectedResponseText, actualResponseDTO.getGeneratedContent()); + verify(geminiClient).generateContent(prompt); + } + + @Test + void generateContent_shouldReturnEmptyDTO_whenClientReturnsEmptyResponse() { + // Arrange + GeminiResponse emptyGrpcResponse = GeminiResponse.newBuilder().build(); // Corrected type + when(geminiClient.generateContent(prompt)).thenReturn(emptyGrpcResponse); + + // Act + GeminiResponseDTO actualResponseDTO = geminiService.generateContent(requestDTO); + + // Assert + assertEquals("", actualResponseDTO.getGeneratedContent()); + verify(geminiClient).generateContent(prompt); + } + + @Test + void generateContent_shouldReturnEmptyDTO_whenClientReturnsNullResponse() { + // Arrange + when(geminiClient.generateContent(prompt)).thenReturn(null); + + // Act + GeminiResponseDTO actualResponseDTO = geminiService.generateContent(requestDTO); + + // Assert + assertEquals("", actualResponseDTO.getGeneratedContent()); + verify(geminiClient).generateContent(prompt); + } + + @Test + void generateContent_shouldHandleNoCandidatesInResponse() { + // Arrange + GeminiResponse responseWithNoCandidates = GeminiResponse.newBuilder().clearCandidates().build(); // Corrected type + when(geminiClient.generateContent(prompt)).thenReturn(responseWithNoCandidates); + + // Act + GeminiResponseDTO actualResponseDTO = geminiService.generateContent(requestDTO); + + // Assert + assertEquals("", actualResponseDTO.getGeneratedContent()); + verify(geminiClient).generateContent(prompt); + } + + @Test + void generateContent_shouldHandleNoPartsInCandidateContent() { + // Arrange + // Corrected builder according to local proto definition + Content contentWithNoParts = Content.newBuilder().clearParts().build(); + Candidate candidateWithNoParts = Candidate.newBuilder().setContent(contentWithNoParts).build(); + GeminiResponse responseWithNoParts = GeminiResponse.newBuilder().addCandidates(candidateWithNoParts).build(); // Corrected type + when(geminiClient.generateContent(prompt)).thenReturn(responseWithNoParts); + + // Act + GeminiResponseDTO actualResponseDTO = geminiService.generateContent(requestDTO); + + // Assert + assertEquals("", actualResponseDTO.getGeneratedContent()); + verify(geminiClient).generateContent(prompt); + } + + @Test + void generateContent_shouldHandleNoContentInCandidate() { + // Arrange + Candidate candidateWithNoContent = Candidate.newBuilder().clearContent().build(); + GeminiResponse responseWithNoContent = GeminiResponse.newBuilder().addCandidates(candidateWithNoContent).build(); + when(geminiClient.generateContent(prompt)).thenReturn(responseWithNoContent); + + // Act + GeminiResponseDTO actualResponseDTO = geminiService.generateContent(requestDTO); + + // Assert + assertEquals("", actualResponseDTO.getGeneratedContent()); + verify(geminiClient).generateContent(prompt); + } +} diff --git a/planning-service/src/test/java/org/example/planningservice/service/grpc/impl/GreeterServiceImplTest.java b/planning-service/src/test/java/org/example/planningservice/service/grpc/impl/GreeterServiceImplTest.java new file mode 100644 index 0000000..cd0816f --- /dev/null +++ b/planning-service/src/test/java/org/example/planningservice/service/grpc/impl/GreeterServiceImplTest.java @@ -0,0 +1,74 @@ +package org.example.planningservice.service.grpc.impl; + +import org.example.planningservice.grpc.client.GreeterClient; // Corrected import +import org.example.planningservice.dto.request.GreeterRequestDTO; +import org.example.planningservice.dto.response.GreeterResponseDTO; +import org.example.planningservice.grpc.apiservice.common.HelloReply; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class GreeterServiceImplTest { + + @Mock + private GreeterClient greeterClient; + + @InjectMocks + private GreeterServiceImpl greeterService; + + private GreeterRequestDTO requestDTO; + private HelloReply grpcReply; + private String name; + private String expectedMessage; + + @BeforeEach + void setUp() { + name = "Test User"; + requestDTO = new GreeterRequestDTO(name); + + expectedMessage = "Hello " + name; + grpcReply = HelloReply.newBuilder().setMessage(expectedMessage).build(); + } + + @Test + void sayHello_shouldReturnMappedDTO_whenClientReturnsReply() { + // Arrange + when(greeterClient.sayHello(name)).thenReturn(grpcReply); + + // Act + GreeterResponseDTO actualResponseDTO = greeterService.sayHello(requestDTO); + + // Assert + assertEquals(expectedMessage, actualResponseDTO.getMessage()); + verify(greeterClient).sayHello(name); + } + + @Test + void sayHello_shouldHandleNullClientResponse() { + // Arrange + when(greeterClient.sayHello(name)).thenReturn(null); + + // Act & Assert + // This scenario depends on how GreeterClient and underlying gRPC call behave. + // If greeterClient.sayHello(name) returning null causes a NullPointerException + // when .getMessage() is called, the test should assert that. + // For this example, let's assume it would throw NullPointerException if not handled. + // However, the current implementation of GreeterServiceImpl would indeed throw NPE. + // A more robust implementation might check for null and throw a custom exception or return a default DTO. + // For now, we test the current behavior. + try { + greeterService.sayHello(requestDTO); + } catch (NullPointerException e) { + // Expected if client returns null and service does not handle it before calling getMessage() + } + verify(greeterClient).sayHello(name); + } +} diff --git a/proto/common.proto b/proto/common.proto new file mode 100644 index 0000000..f932aea --- /dev/null +++ b/proto/common.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package common_proto; + +option go_package = "api-service/grpc/pb/common"; +option java_package = "org.example.planningservice.grpc.apiservice.common"; +option java_multiple_files = true; + +service ExampleGreeter { + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +message HelloRequest { + string name = 1; +} +message HelloReply { + string message = 1; +} diff --git a/proto/gemini.proto b/proto/gemini.proto new file mode 100644 index 0000000..028d380 --- /dev/null +++ b/proto/gemini.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package gemini_proto; + +option go_package = "api-service/grpc/pb/gemini"; +option java_package = "org.example.planningservice.grpc.apiservice.gemini"; +option java_multiple_files = true; + +// Gemini Service +service Gemini { + rpc GenerateContent(GeminiRequest) returns (GeminiResponse); +} + +message GeminiRequest { + string prompt = 1; +} +message GeminiResponse { + message SafetyRating { + string category = 1; + string probability = 2; + } + message ContentPart { + string text = 1; + } + message Content { + repeated ContentPart parts = 1; + string role = 2; + } + message Candidate { + Content content = 1; + string finish_reason = 2; + int32 index = 3; + repeated SafetyRating safety_ratings = 4; + } + message PromptFeedback { + repeated SafetyRating safety_ratings = 2; + } + repeated Candidate candidates = 1; + PromptFeedback prompt_feedback = 2; +} diff --git a/proto/maps.proto b/proto/maps.proto new file mode 100644 index 0000000..d2bf055 --- /dev/null +++ b/proto/maps.proto @@ -0,0 +1,149 @@ +syntax = "proto3"; + +package maps_proto; + +option go_package = "api-service/grpc/pb/maps"; +option java_package = "org.example.planningservice.grpc.apiservice.maps"; +option java_multiple_files = true; + +// Maps Service +service Maps { + rpc Geocode(GeocodeRequest) returns (GeocodeResponse); + rpc SearchPlaces(SearchPlacesRequest) returns (SearchPlacesResponse); + rpc GetPlaceDetails(PlaceDetailsRequest) returns (PlaceDetailsResponse); + rpc GetDirections(DirectionsRequest) returns (DirectionsResponse); + rpc GetDistanceMatrix(DistanceMatrixRequest) returns (DistanceMatrixResponse); +} + +// --- Geocoding --- +message GeocodeRequest { + string address = 1; +} +message GeocodeResponse { + message Location { + double lat = 1; + double lng = 2; + } + message Result { + string formatted_address = 1; + Location location = 2; + } + repeated Result results = 1; + string status = 2; +} + +// --- Places Search --- +message SearchPlacesRequest { + string query = 1; + string location = 2; +} +message Place { + message Location { + double lat = 1; + double lng = 2; + } + message OpeningHours { + bool open_now = 1; + } + message Photo { + string photo_reference = 1; + int32 height = 2; + int32 width = 3; + } + string place_id = 1; + string name = 2; + string vicinity = 3; + double rating = 4; + int32 user_ratings_total = 5; + Location geometry_location = 6; + OpeningHours opening_hours = 7; + repeated Photo photos = 8; + repeated string photo_urls = 9; + repeated string types = 10; +} +message SearchPlacesResponse { + repeated Place results = 1; + string status = 2; +} + +// --- Place Details --- +message PlaceDetailsRequest { + string place_id = 1; +} +message PlaceDetailsResponse { + Place result = 1; + string status = 2; +} + +// --- Directions --- +message DirectionsRequest { + string origin = 1; + string destination = 2; +} +message DirectionsResponse { + message Distance { + string text = 1; + int32 value = 2; // meters + } + message Duration { + string text = 1; + int32 value = 2; // seconds + } + message Polyline { + string points = 1; + } + message Step { + string html_instructions = 1; + Distance distance = 2; + Duration duration = 3; + Polyline polyline = 4; + } + message Leg { + Distance distance = 1; + Duration duration = 2; + string start_address = 3; + string end_address = 4; + repeated Step steps = 5; + } + message Route { + string summary = 1; + repeated Leg legs = 2; + Polyline overview_polyline = 3; + } + message GeocodedWaypoint { + string geocoder_status = 1; + string place_id = 2; + repeated string types = 3; + } + repeated Route routes = 1; + repeated GeocodedWaypoint geocoded_waypoints = 2; + string status = 3; +} + +// --- Distance Matrix --- +message DistanceMatrixRequest { + string origins = 1; + string destinations = 2; +} +message DistanceMatrixResponse { + repeated string origin_addresses = 1; + repeated string destination_addresses = 2; + message Element { + message Duration { + string text = 1; + int32 value = 2; // seconds + } + message Distance { + string text = 1; + int32 value = 2; // meters + } + string status = 1; + Duration duration = 2; + Distance distance = 3; + } + message Row { + repeated Element elements = 1; + } + repeated Row rows = 3; + string status = 4; +} diff --git a/social-media-service/.env b/social-media-service/.env new file mode 100644 index 0000000..e07e9fb --- /dev/null +++ b/social-media-service/.env @@ -0,0 +1,4 @@ +CLIENT_ID=785994007278-lr2k84dv19513frlhkid2dvnf396mpa0.apps.googleusercontent.com +CLIENT_SECRET=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 +baseUrl=https://gotogetheruom.duckdns.org +registrationId=keycloak \ No newline at end of file diff --git a/social-media-service/.env.Example b/social-media-service/.env.Example new file mode 100644 index 0000000..5f4951c --- /dev/null +++ b/social-media-service/.env.Example @@ -0,0 +1,4 @@ +CLIENT_ID=xxxxx +CLIENT_SECRET=xxxxxxxx +baseUrl= +registrationId= \ No newline at end of file diff --git a/social-media-service/.gradle/8.12/checksums/checksums.lock b/social-media-service/.gradle/8.12/checksums/checksums.lock new file mode 100644 index 0000000..de999e7 Binary files /dev/null and b/social-media-service/.gradle/8.12/checksums/checksums.lock differ diff --git a/social-media-service/.gradle/8.12/checksums/md5-checksums.bin b/social-media-service/.gradle/8.12/checksums/md5-checksums.bin new file mode 100644 index 0000000..9f21960 Binary files /dev/null and b/social-media-service/.gradle/8.12/checksums/md5-checksums.bin differ diff --git a/social-media-service/.gradle/8.12/checksums/sha1-checksums.bin b/social-media-service/.gradle/8.12/checksums/sha1-checksums.bin new file mode 100644 index 0000000..49bbe79 Binary files /dev/null and b/social-media-service/.gradle/8.12/checksums/sha1-checksums.bin differ diff --git a/social-media-service/.gradle/8.12/executionHistory/executionHistory.bin b/social-media-service/.gradle/8.12/executionHistory/executionHistory.bin new file mode 100644 index 0000000..5ec7765 Binary files /dev/null and b/social-media-service/.gradle/8.12/executionHistory/executionHistory.bin differ diff --git a/social-media-service/.gradle/8.12/executionHistory/executionHistory.lock b/social-media-service/.gradle/8.12/executionHistory/executionHistory.lock new file mode 100644 index 0000000..60c2e4c Binary files /dev/null and b/social-media-service/.gradle/8.12/executionHistory/executionHistory.lock differ diff --git a/social-media-service/.gradle/8.12/expanded/expanded.lock b/social-media-service/.gradle/8.12/expanded/expanded.lock new file mode 100644 index 0000000..61155f2 Binary files /dev/null and b/social-media-service/.gradle/8.12/expanded/expanded.lock differ diff --git a/social-media-service/.gradle/8.12/fileChanges/last-build.bin b/social-media-service/.gradle/8.12/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/social-media-service/.gradle/8.12/fileChanges/last-build.bin differ diff --git a/social-media-service/.gradle/8.12/fileHashes/fileHashes.bin b/social-media-service/.gradle/8.12/fileHashes/fileHashes.bin new file mode 100644 index 0000000..200e9c1 Binary files /dev/null and b/social-media-service/.gradle/8.12/fileHashes/fileHashes.bin differ diff --git a/social-media-service/.gradle/8.12/fileHashes/fileHashes.lock b/social-media-service/.gradle/8.12/fileHashes/fileHashes.lock new file mode 100644 index 0000000..09d8263 Binary files /dev/null and b/social-media-service/.gradle/8.12/fileHashes/fileHashes.lock differ diff --git a/social-media-service/.gradle/8.12/fileHashes/resourceHashesCache.bin b/social-media-service/.gradle/8.12/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..835a169 Binary files /dev/null and b/social-media-service/.gradle/8.12/fileHashes/resourceHashesCache.bin differ diff --git a/social-media-service/.gradle/8.12/gc.properties b/social-media-service/.gradle/8.12/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/social-media-service/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/social-media-service/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..278a0fb Binary files /dev/null and b/social-media-service/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/social-media-service/.gradle/buildOutputCleanup/cache.properties b/social-media-service/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..01c76da --- /dev/null +++ b/social-media-service/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Sun Apr 27 11:22:39 IST 2025 +gradle.version=8.12 diff --git a/social-media-service/.gradle/buildOutputCleanup/outputFiles.bin b/social-media-service/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..f1e884d Binary files /dev/null and b/social-media-service/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/social-media-service/.gradle/file-system.probe b/social-media-service/.gradle/file-system.probe new file mode 100644 index 0000000..8a83618 Binary files /dev/null and b/social-media-service/.gradle/file-system.probe differ diff --git a/social-media-service/.gradle/vcs-1/gc.properties b/social-media-service/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/social-media-service/.idea/compiler.xml b/social-media-service/.idea/compiler.xml new file mode 100644 index 0000000..1da3651 --- /dev/null +++ b/social-media-service/.idea/compiler.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/social-media-service/.idea/gradle.xml b/social-media-service/.idea/gradle.xml new file mode 100644 index 0000000..ce1c62c --- /dev/null +++ b/social-media-service/.idea/gradle.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/social-media-service/.idea/misc.xml b/social-media-service/.idea/misc.xml new file mode 100644 index 0000000..de0c428 --- /dev/null +++ b/social-media-service/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/social-media-service/.idea/modules.xml b/social-media-service/.idea/modules.xml new file mode 100644 index 0000000..58a388e --- /dev/null +++ b/social-media-service/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/social-media-service/.idea/vcs.xml b/social-media-service/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/social-media-service/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/social-media-service/Dockerfile b/social-media-service/Dockerfile new file mode 100644 index 0000000..ea0b674 --- /dev/null +++ b/social-media-service/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:17-jdk-slim +RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +COPY build/libs/*.jar /app.jar +EXPOSE 8080 +ENTRYPOINT ["/entrypoint.sh"] diff --git a/social-media-service/bin/main/application.properties b/social-media-service/bin/main/application.properties new file mode 100644 index 0000000..194b36f --- /dev/null +++ b/social-media-service/bin/main/application.properties @@ -0,0 +1,47 @@ +spring.application.name=social-media-service + +# Database configuration +#spring.datasource.url=${SPRING_DATASOURCE_URL} +spring.datasource.username=postgres.odffpjvuptssxaaggnsn +spring.datasource.password=Postgres + +#spring.datasource.username=${SPRING_DATASOURCE_USERNAME} +#spring.datasource.password=${SPRING_DATASOURCE_PASSWORD} + +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres?user=postgres.odffpjvuptssxaaggnsn&password=Postgres +#spring.jpa.hibernate.ddl-auto=none + +# JPA & Hibernate Configuration +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.show-sql=true + +logging.level.org.springframework.web.cors=DEBUG + +# Spring Security OAuth2 Client Configuration +# Assuming 'keycloak' is the registration ID for your Keycloak provider +# and Google is an identity provider within that Keycloak realm. + +# Provider details for Keycloak itself (acting as the OIDC provider to your app) +spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8081/realms/kong +# spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username # Adjust if needed based on Keycloak token claims + +# Client registration details for your application registered in Keycloak +spring.security.oauth2.client.registration.google.provider=keycloak +spring.security.oauth2.client.registration.google.client-id=${CLIENT_ID} +spring.security.oauth2.client.registration.google.client-secret=${CLIENT_SECRET} +spring.security.oauth2.client.registration.google.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.google.redirect-uri=${baseUrl}/login/oauth2/code/${registrationId} +# spring.security.oauth2.client.registration.google.redirect-uri=http://localhost:8080/login/oauth2/code/google # Or be explicit if {baseUrl} is not set up +spring.security.oauth2.client.registration.google.scope=openid,profile,email +# The client-name is what might appear on a default login page if Spring generates one. +spring.security.oauth2.client.registration.google.client-name=Google + +# Note: The 'client-id' and 'client-secret' here are for the 'social-media-service' client registration within Keycloak, +# NOT the Google client ID/secret directly, unless you are bypassing Keycloak for direct Google OAuth, +# which is not the current plan (plan is Keycloak federating Google). +# The Keycloak instance itself is configured with the Google client ID/secret. +# The `registration.google` here tells Spring how to initiate the login flow via Keycloak, +# which then redirects to Google. The `provider=keycloak` links this registration to use Keycloak's OIDC config. +# The name 'google' for the registrationId is conventional for triggering Google login via Keycloak. diff --git a/social-media-service/bin/main/com/example/socialmediaservice/SocialMediaServiceApplication.class b/social-media-service/bin/main/com/example/socialmediaservice/SocialMediaServiceApplication.class new file mode 100644 index 0000000..5cfe241 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/SocialMediaServiceApplication.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/controller/MediaController.class b/social-media-service/bin/main/com/example/socialmediaservice/controller/MediaController.class new file mode 100644 index 0000000..d8bc928 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/controller/MediaController.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/controller/PostController.class b/social-media-service/bin/main/com/example/socialmediaservice/controller/PostController.class new file mode 100644 index 0000000..df8ef97 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/controller/PostController.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/controller/PostInteractionController.class b/social-media-service/bin/main/com/example/socialmediaservice/controller/PostInteractionController.class new file mode 100644 index 0000000..aee295c Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/controller/PostInteractionController.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController$AvatarUpdateRequest.class b/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController$AvatarUpdateRequest.class new file mode 100644 index 0000000..aa95efc Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController$AvatarUpdateRequest.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController$RegisterRequest.class b/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController$RegisterRequest.class new file mode 100644 index 0000000..65fd1ed Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController$RegisterRequest.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController.class b/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController.class new file mode 100644 index 0000000..88778a6 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/controller/UserController.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/CommentDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/CommentDTO.class new file mode 100644 index 0000000..9c2a6d8 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/CommentDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/CreatePostRequestDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/CreatePostRequestDTO.class new file mode 100644 index 0000000..c5c8473 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/CreatePostRequestDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/CreatePostResponseDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/CreatePostResponseDTO.class new file mode 100644 index 0000000..2de6260 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/CreatePostResponseDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/FollowerInfo.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/FollowerInfo.class new file mode 100644 index 0000000..ffa927a Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/FollowerInfo.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/MediaCreateRequestDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/MediaCreateRequestDTO.class new file mode 100644 index 0000000..4589576 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/MediaCreateRequestDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/MediaDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/MediaDTO.class new file mode 100644 index 0000000..342d432 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/MediaDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO$CountDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO$CountDTO.class new file mode 100644 index 0000000..7ad1aba Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO$CountDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO$UserIdDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO$UserIdDTO.class new file mode 100644 index 0000000..fdf4749 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO$UserIdDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO.class new file mode 100644 index 0000000..20cf3b8 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/PostsPageDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostsPageDTO.class new file mode 100644 index 0000000..f04a45b Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/PostsPageDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/ReactionDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/ReactionDTO.class new file mode 100644 index 0000000..b0c0d63 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/ReactionDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.class new file mode 100644 index 0000000..e2fee94 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/RequestCommentDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/RequestCommentDTO.class new file mode 100644 index 0000000..c7c4e8b Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/RequestCommentDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdatePostRequestDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdatePostRequestDTO.class new file mode 100644 index 0000000..625d892 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdatePostRequestDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdateProfileRequest.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdateProfileRequest.class new file mode 100644 index 0000000..1c8e710 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdateProfileRequest.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdateProfileResponse.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdateProfileResponse.class new file mode 100644 index 0000000..28c1c73 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/UpdateProfileResponse.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/UserDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/UserDTO.class new file mode 100644 index 0000000..3e9d424 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/UserDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/dto/UserProfileDTO.class b/social-media-service/bin/main/com/example/socialmediaservice/dto/UserProfileDTO.class new file mode 100644 index 0000000..05e0e4e Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/dto/UserProfileDTO.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/entity/Bookmark.class b/social-media-service/bin/main/com/example/socialmediaservice/entity/Bookmark.class new file mode 100644 index 0000000..c74d02a Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/entity/Bookmark.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/entity/Comment.class b/social-media-service/bin/main/com/example/socialmediaservice/entity/Comment.class new file mode 100644 index 0000000..165b778 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/entity/Comment.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/entity/Media.class b/social-media-service/bin/main/com/example/socialmediaservice/entity/Media.class new file mode 100644 index 0000000..fcc4fa5 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/entity/Media.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/entity/Post.class b/social-media-service/bin/main/com/example/socialmediaservice/entity/Post.class new file mode 100644 index 0000000..8699888 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/entity/Post.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/entity/Reaction.class b/social-media-service/bin/main/com/example/socialmediaservice/entity/Reaction.class new file mode 100644 index 0000000..e826ccb Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/entity/Reaction.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/entity/User.class b/social-media-service/bin/main/com/example/socialmediaservice/entity/User.class new file mode 100644 index 0000000..d29385e Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/entity/User.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/enums/MediaType.class b/social-media-service/bin/main/com/example/socialmediaservice/enums/MediaType.class new file mode 100644 index 0000000..608cbe1 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/enums/MediaType.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/enums/ReactionType.class b/social-media-service/bin/main/com/example/socialmediaservice/enums/ReactionType.class new file mode 100644 index 0000000..9b6b7a6 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/enums/ReactionType.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/mapper/CommentMapper.class b/social-media-service/bin/main/com/example/socialmediaservice/mapper/CommentMapper.class new file mode 100644 index 0000000..1c8cdfa Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/mapper/CommentMapper.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/mapper/PostMapper.class b/social-media-service/bin/main/com/example/socialmediaservice/mapper/PostMapper.class new file mode 100644 index 0000000..df65401 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/mapper/PostMapper.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/repository/BookmarkRepository.class b/social-media-service/bin/main/com/example/socialmediaservice/repository/BookmarkRepository.class new file mode 100644 index 0000000..4fae317 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/repository/BookmarkRepository.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/repository/CommentRepo.class b/social-media-service/bin/main/com/example/socialmediaservice/repository/CommentRepo.class new file mode 100644 index 0000000..17c838f Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/repository/CommentRepo.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/repository/MediaRepo.class b/social-media-service/bin/main/com/example/socialmediaservice/repository/MediaRepo.class new file mode 100644 index 0000000..063f69b Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/repository/MediaRepo.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/repository/PostRepo.class b/social-media-service/bin/main/com/example/socialmediaservice/repository/PostRepo.class new file mode 100644 index 0000000..647234d Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/repository/PostRepo.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/repository/ReactionRepo.class b/social-media-service/bin/main/com/example/socialmediaservice/repository/ReactionRepo.class new file mode 100644 index 0000000..225b9ae Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/repository/ReactionRepo.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/repository/UserRepo.class b/social-media-service/bin/main/com/example/socialmediaservice/repository/UserRepo.class new file mode 100644 index 0000000..31854c4 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/repository/UserRepo.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/BookmarkService.class b/social-media-service/bin/main/com/example/socialmediaservice/service/BookmarkService.class new file mode 100644 index 0000000..200235b Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/BookmarkService.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/CommentService.class b/social-media-service/bin/main/com/example/socialmediaservice/service/CommentService.class new file mode 100644 index 0000000..22aef23 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/CommentService.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/MediaService.class b/social-media-service/bin/main/com/example/socialmediaservice/service/MediaService.class new file mode 100644 index 0000000..a1ee93e Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/MediaService.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/PostService.class b/social-media-service/bin/main/com/example/socialmediaservice/service/PostService.class new file mode 100644 index 0000000..dc2581c Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/PostService.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/ReactionService.class b/social-media-service/bin/main/com/example/socialmediaservice/service/ReactionService.class new file mode 100644 index 0000000..4bbb851 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/ReactionService.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest$Credential.class b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest$Credential.class new file mode 100644 index 0000000..6ef0167 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest$Credential.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest.class b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest.class new file mode 100644 index 0000000..f39359e Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$TokenResponse.class b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$TokenResponse.class new file mode 100644 index 0000000..daa442b Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService$TokenResponse.class differ diff --git a/social-media-service/bin/main/com/example/socialmediaservice/service/UserService.class b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService.class new file mode 100644 index 0000000..d727c48 Binary files /dev/null and b/social-media-service/bin/main/com/example/socialmediaservice/service/UserService.class differ diff --git a/social-media-service/bin/test/com/example/socialmediaservice/SocialMediaServiceApplicationTests.class b/social-media-service/bin/test/com/example/socialmediaservice/SocialMediaServiceApplicationTests.class new file mode 100644 index 0000000..4e3dd0f Binary files /dev/null and b/social-media-service/bin/test/com/example/socialmediaservice/SocialMediaServiceApplicationTests.class differ diff --git a/social-media-service/build.gradle b/social-media-service/build.gradle new file mode 100644 index 0000000..1e32b81 --- /dev/null +++ b/social-media-service/build.gradle @@ -0,0 +1,83 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.0' + id 'io.spring.dependency-management' version '1.1.6' + id 'com.google.protobuf' version '0.9.2' +} + +group = 'com.example' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-mail' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-starter-validation' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'org.postgresql:postgresql' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + + runtimeOnly 'io.grpc:grpc-netty-shaded:1.52.1' + implementation 'io.grpc:grpc-protobuf:1.52.1' + implementation 'io.grpc:grpc-stub:1.52.1' + compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' + + // grpc denendencies + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'org.springframework.boot:spring-boot-starter-webflux' + + +} + + + +test { + useJUnitPlatform() +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.21.7" + } + plugins { + grpc { + artifact = 'io.grpc:protoc-gen-grpc-java:1.52.1' + } + } + generateProtoTasks { + all()*.plugins { + grpc {} + } + } +} + + + +tasks.named('test') { + useJUnitPlatform() +} \ No newline at end of file diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/SocialMediaServiceApplication.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/SocialMediaServiceApplication.class new file mode 100644 index 0000000..7ab3a00 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/SocialMediaServiceApplication.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/MediaController.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/MediaController.class new file mode 100644 index 0000000..c1f404f Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/MediaController.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/PostController.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/PostController.class new file mode 100644 index 0000000..46855a8 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/PostController.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/PostInteractionController.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/PostInteractionController.class new file mode 100644 index 0000000..da82aee Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/PostInteractionController.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController$AvatarUpdateRequest.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController$AvatarUpdateRequest.class new file mode 100644 index 0000000..6c4310e Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController$AvatarUpdateRequest.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController$RegisterRequest.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController$RegisterRequest.class new file mode 100644 index 0000000..d5f2576 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController$RegisterRequest.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController.class new file mode 100644 index 0000000..769a15d Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/controller/UserController.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CommentDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CommentDTO.class new file mode 100644 index 0000000..6331f30 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CommentDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CreatePostRequestDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CreatePostRequestDTO.class new file mode 100644 index 0000000..0617fdf Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CreatePostRequestDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CreatePostResponseDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CreatePostResponseDTO.class new file mode 100644 index 0000000..071f991 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/CreatePostResponseDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/FollowerInfo.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/FollowerInfo.class new file mode 100644 index 0000000..bac9361 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/FollowerInfo.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/MediaCreateRequestDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/MediaCreateRequestDTO.class new file mode 100644 index 0000000..81a2e18 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/MediaCreateRequestDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/MediaDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/MediaDTO.class new file mode 100644 index 0000000..9593d6e Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/MediaDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO$CountDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO$CountDTO.class new file mode 100644 index 0000000..29d2c00 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO$CountDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO$UserIdDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO$UserIdDTO.class new file mode 100644 index 0000000..45cd95a Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO$UserIdDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO.class new file mode 100644 index 0000000..eed5f32 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostsPageDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostsPageDTO.class new file mode 100644 index 0000000..efbfdb1 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/PostsPageDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/ReactionDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/ReactionDTO.class new file mode 100644 index 0000000..4d3324b Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/ReactionDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.class new file mode 100644 index 0000000..3990242 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/RequestCommentDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/RequestCommentDTO.class new file mode 100644 index 0000000..740af81 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/RequestCommentDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdatePostRequestDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdatePostRequestDTO.class new file mode 100644 index 0000000..75dc837 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdatePostRequestDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdateProfileRequest.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdateProfileRequest.class new file mode 100644 index 0000000..fea6c94 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdateProfileRequest.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdateProfileResponse.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdateProfileResponse.class new file mode 100644 index 0000000..f22347f Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UpdateProfileResponse.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UserDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UserDTO.class new file mode 100644 index 0000000..e06bc04 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UserDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UserProfileDTO.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UserProfileDTO.class new file mode 100644 index 0000000..b2aba90 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/dto/UserProfileDTO.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Bookmark.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Bookmark.class new file mode 100644 index 0000000..1031c3a Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Bookmark.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Comment.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Comment.class new file mode 100644 index 0000000..b4732c4 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Comment.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Media.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Media.class new file mode 100644 index 0000000..4cb829e Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Media.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Post.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Post.class new file mode 100644 index 0000000..0b6ba71 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Post.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Reaction.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Reaction.class new file mode 100644 index 0000000..284d240 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/Reaction.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/User.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/User.class new file mode 100644 index 0000000..c1e6e80 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/entity/User.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/enums/MediaType.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/enums/MediaType.class new file mode 100644 index 0000000..8e02ae7 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/enums/MediaType.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/enums/ReactionType.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/enums/ReactionType.class new file mode 100644 index 0000000..3f9e797 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/enums/ReactionType.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/mapper/CommentMapper.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/mapper/CommentMapper.class new file mode 100644 index 0000000..ca13bd2 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/mapper/CommentMapper.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/mapper/PostMapper.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/mapper/PostMapper.class new file mode 100644 index 0000000..092aa05 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/mapper/PostMapper.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/BookmarkRepository.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/BookmarkRepository.class new file mode 100644 index 0000000..d85b323 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/BookmarkRepository.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/CommentRepo.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/CommentRepo.class new file mode 100644 index 0000000..10919ef Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/CommentRepo.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/MediaRepo.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/MediaRepo.class new file mode 100644 index 0000000..23f8b7b Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/MediaRepo.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/PostRepo.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/PostRepo.class new file mode 100644 index 0000000..fbdae24 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/PostRepo.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/ReactionRepo.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/ReactionRepo.class new file mode 100644 index 0000000..deac36c Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/ReactionRepo.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/UserRepo.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/UserRepo.class new file mode 100644 index 0000000..4f91ee1 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/repository/UserRepo.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/BookmarkService.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/BookmarkService.class new file mode 100644 index 0000000..ebd73fb Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/BookmarkService.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/CommentService.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/CommentService.class new file mode 100644 index 0000000..67a57d5 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/CommentService.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/MediaService.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/MediaService.class new file mode 100644 index 0000000..4f87682 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/MediaService.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/PostService.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/PostService.class new file mode 100644 index 0000000..9ae16b4 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/PostService.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/ReactionService.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/ReactionService.class new file mode 100644 index 0000000..8289eff Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/ReactionService.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest$Credential.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest$Credential.class new file mode 100644 index 0000000..c914bd3 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest$Credential.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest.class new file mode 100644 index 0000000..8993f22 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$KeycloakUserRequest.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$TokenResponse.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$TokenResponse.class new file mode 100644 index 0000000..500ce64 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService$TokenResponse.class differ diff --git a/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService.class b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService.class new file mode 100644 index 0000000..f537143 Binary files /dev/null and b/social-media-service/build/classes/java/main/com/example/socialmediaservice/service/UserService.class differ diff --git a/social-media-service/build/extracted-include-protos/main/google/api/annotations.proto b/social-media-service/build/extracted-include-protos/main/google/api/annotations.proto new file mode 100644 index 0000000..efdab3d --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/auth.proto b/social-media-service/build/extracted-include-protos/main/google/api/auth.proto new file mode 100644 index 0000000..54026e1 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/auth.proto @@ -0,0 +1,232 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "AuthProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// `Authentication` defines the authentication configuration for API methods +// provided by an API service. +// +// Example: +// +// name: calendar.googleapis.com +// authentication: +// providers: +// - id: google_calendar_auth +// jwks_uri: https://www.googleapis.com/oauth2/v1/certs +// issuer: https://securetoken.google.com +// rules: +// - selector: "*" +// requirements: +// provider_id: google_calendar_auth +// - selector: google.calendar.Delegate +// oauth: +// canonical_scopes: https://www.googleapis.com/auth/calendar.read +message Authentication { + // A list of authentication rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated AuthenticationRule rules = 3; + + // Defines a set of authentication providers that a service supports. + repeated AuthProvider providers = 4; +} + +// Authentication rules for the service. +// +// By default, if a method has any authentication requirements, every request +// must include a valid credential matching one of the requirements. +// It's an error to include more than one kind of credential in a single +// request. +// +// If a method doesn't have any auth requirements, request credentials will be +// ignored. +message AuthenticationRule { + // Selects the methods to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // The requirements for OAuth credentials. + OAuthRequirements oauth = 2; + + // If true, the service accepts API keys without any other credential. + // This flag only applies to HTTP and gRPC requests. + bool allow_without_credential = 5; + + // Requirements for additional authentication providers. + repeated AuthRequirement requirements = 7; +} + +// Specifies a location to extract JWT from an API request. +message JwtLocation { + oneof in { + // Specifies HTTP header name to extract JWT token. + string header = 1; + + // Specifies URL query parameter name to extract JWT token. + string query = 2; + } + + // The value prefix. The value format is "value_prefix{token}" + // Only applies to "in" header type. Must be empty for "in" query type. + // If not empty, the header value has to match (case sensitive) this prefix. + // If not matched, JWT will not be extracted. If matched, JWT will be + // extracted after the prefix is removed. + // + // For example, for "Authorization: Bearer {JWT}", + // value_prefix="Bearer " with a space at the end. + string value_prefix = 3; +} + +// Configuration for an authentication provider, including support for +// [JSON Web Token +// (JWT)](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32). +message AuthProvider { + // The unique identifier of the auth provider. It will be referred to by + // `AuthRequirement.provider_id`. + // + // Example: "bookstore_auth". + string id = 1; + + // Identifies the principal that issued the JWT. See + // https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.1 + // Usually a URL or an email address. + // + // Example: https://securetoken.google.com + // Example: 1234567-compute@developer.gserviceaccount.com + string issuer = 2; + + // URL of the provider's public key set to validate signature of the JWT. See + // [OpenID + // Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata). + // Optional if the key set document: + // - can be retrieved from + // [OpenID + // Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) + // of the issuer. + // - can be inferred from the email domain of the issuer (e.g. a Google + // service account). + // + // Example: https://www.googleapis.com/oauth2/v1/certs + string jwks_uri = 3; + + // The list of JWT + // [audiences](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.3). + // that are allowed to access. A JWT containing any of these audiences will + // be accepted. When this setting is absent, JWTs with audiences: + // - "https://[service.name]/[google.protobuf.Api.name]" + // - "https://[service.name]/" + // will be accepted. + // For example, if no audiences are in the setting, LibraryService API will + // accept JWTs with the following audiences: + // - + // https://library-example.googleapis.com/google.example.library.v1.LibraryService + // - https://library-example.googleapis.com/ + // + // Example: + // + // audiences: bookstore_android.apps.googleusercontent.com, + // bookstore_web.apps.googleusercontent.com + string audiences = 4; + + // Redirect URL if JWT token is required but not present or is expired. + // Implement authorizationUrl of securityDefinitions in OpenAPI spec. + string authorization_url = 5; + + // Defines the locations to extract the JWT. + // + // JWT locations can be either from HTTP headers or URL query parameters. + // The rule is that the first match wins. The checking order is: checking + // all headers first, then URL query parameters. + // + // If not specified, default to use following 3 locations: + // 1) Authorization: Bearer + // 2) x-goog-iap-jwt-assertion + // 3) access_token query parameter + // + // Default locations can be specified as followings: + // jwt_locations: + // - header: Authorization + // value_prefix: "Bearer " + // - header: x-goog-iap-jwt-assertion + // - query: access_token + repeated JwtLocation jwt_locations = 6; +} + +// OAuth scopes are a way to define data and permissions on data. For example, +// there are scopes defined for "Read-only access to Google Calendar" and +// "Access to Cloud Platform". Users can consent to a scope for an application, +// giving it permission to access that data on their behalf. +// +// OAuth scope specifications should be fairly coarse grained; a user will need +// to see and understand the text description of what your scope means. +// +// In most cases: use one or at most two OAuth scopes for an entire family of +// products. If your product has multiple APIs, you should probably be sharing +// the OAuth scope across all of those APIs. +// +// When you need finer grained OAuth consent screens: talk with your product +// management about how developers will use them in practice. +// +// Please note that even though each of the canonical scopes is enough for a +// request to be accepted and passed to the backend, a request can still fail +// due to the backend requiring additional scopes or permissions. +message OAuthRequirements { + // The list of publicly documented OAuth scopes that are allowed access. An + // OAuth token containing any of these scopes will be accepted. + // + // Example: + // + // canonical_scopes: https://www.googleapis.com/auth/calendar, + // https://www.googleapis.com/auth/calendar.read + string canonical_scopes = 1; +} + +// User-defined authentication requirements, including support for +// [JSON Web Token +// (JWT)](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32). +message AuthRequirement { + // [id][google.api.AuthProvider.id] from authentication provider. + // + // Example: + // + // provider_id: bookstore_auth + string provider_id = 1; + + // NOTE: This will be deprecated soon, once AuthProvider.audiences is + // implemented and accepted in all the runtime components. + // + // The list of JWT + // [audiences](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.3). + // that are allowed to access. A JWT containing any of these audiences will + // be accepted. When this setting is absent, only JWTs with audience + // "https://[Service_name][google.api.Service.name]/[API_name][google.protobuf.Api.name]" + // will be accepted. For example, if no audiences are in the setting, + // LibraryService API will only accept JWTs with the following audience + // "https://library-example.googleapis.com/google.example.library.v1.LibraryService". + // + // Example: + // + // audiences: bookstore_android.apps.googleusercontent.com, + // bookstore_web.apps.googleusercontent.com + string audiences = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/backend.proto b/social-media-service/build/extracted-include-protos/main/google/api/backend.proto new file mode 100644 index 0000000..da38786 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/backend.proto @@ -0,0 +1,182 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "BackendProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// `Backend` defines the backend configuration for a service. +message Backend { + // A list of API backend rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated BackendRule rules = 1; +} + +// A backend rule provides configuration for an individual API element. +message BackendRule { + // Path Translation specifies how to combine the backend address with the + // request path in order to produce the appropriate forwarding URL for the + // request. + // + // Path Translation is applicable only to HTTP-based backends. Backends which + // do not accept requests over HTTP/HTTPS should leave `path_translation` + // unspecified. + enum PathTranslation { + PATH_TRANSLATION_UNSPECIFIED = 0; + + // Use the backend address as-is, with no modification to the path. If the + // URL pattern contains variables, the variable names and values will be + // appended to the query string. If a query string parameter and a URL + // pattern variable have the same name, this may result in duplicate keys in + // the query string. + // + // # Examples + // + // Given the following operation config: + // + // Method path: /api/company/{cid}/user/{uid} + // Backend address: https://example.cloudfunctions.net/getUser + // + // Requests to the following request paths will call the backend at the + // translated path: + // + // Request path: /api/company/widgetworks/user/johndoe + // Translated: + // https://example.cloudfunctions.net/getUser?cid=widgetworks&uid=johndoe + // + // Request path: /api/company/widgetworks/user/johndoe?timezone=EST + // Translated: + // https://example.cloudfunctions.net/getUser?timezone=EST&cid=widgetworks&uid=johndoe + CONSTANT_ADDRESS = 1; + + // The request path will be appended to the backend address. + // + // # Examples + // + // Given the following operation config: + // + // Method path: /api/company/{cid}/user/{uid} + // Backend address: https://example.appspot.com + // + // Requests to the following request paths will call the backend at the + // translated path: + // + // Request path: /api/company/widgetworks/user/johndoe + // Translated: + // https://example.appspot.com/api/company/widgetworks/user/johndoe + // + // Request path: /api/company/widgetworks/user/johndoe?timezone=EST + // Translated: + // https://example.appspot.com/api/company/widgetworks/user/johndoe?timezone=EST + APPEND_PATH_TO_ADDRESS = 2; + } + + // Selects the methods to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // The address of the API backend. + // + // The scheme is used to determine the backend protocol and security. + // The following schemes are accepted: + // + // SCHEME PROTOCOL SECURITY + // http:// HTTP None + // https:// HTTP TLS + // grpc:// gRPC None + // grpcs:// gRPC TLS + // + // It is recommended to explicitly include a scheme. Leaving out the scheme + // may cause constrasting behaviors across platforms. + // + // If the port is unspecified, the default is: + // - 80 for schemes without TLS + // - 443 for schemes with TLS + // + // For HTTP backends, use [protocol][google.api.BackendRule.protocol] + // to specify the protocol version. + string address = 2; + + // The number of seconds to wait for a response from a request. The default + // varies based on the request protocol and deployment environment. + double deadline = 3; + + // Minimum deadline in seconds needed for this method. Calls having deadline + // value lower than this will be rejected. + double min_deadline = 4; + + // The number of seconds to wait for the completion of a long running + // operation. The default is no deadline. + double operation_deadline = 5; + + PathTranslation path_translation = 6; + + // Authentication settings used by the backend. + // + // These are typically used to provide service management functionality to + // a backend served on a publicly-routable URL. The `authentication` + // details should match the authentication behavior used by the backend. + // + // For example, specifying `jwt_audience` implies that the backend expects + // authentication via a JWT. + // + // When authentication is unspecified, the resulting behavior is the same + // as `disable_auth` set to `true`. + // + // Refer to https://developers.google.com/identity/protocols/OpenIDConnect for + // JWT ID token. + oneof authentication { + // The JWT audience is used when generating a JWT ID token for the backend. + // This ID token will be added in the HTTP "authorization" header, and sent + // to the backend. + string jwt_audience = 7; + + // When disable_auth is true, a JWT ID token won't be generated and the + // original "Authorization" HTTP header will be preserved. If the header is + // used to carry the original token and is expected by the backend, this + // field must be set to true to preserve the header. + bool disable_auth = 8; + } + + // The protocol used for sending a request to the backend. + // The supported values are "http/1.1" and "h2". + // + // The default value is inferred from the scheme in the + // [address][google.api.BackendRule.address] field: + // + // SCHEME PROTOCOL + // http:// http/1.1 + // https:// http/1.1 + // grpc:// h2 + // grpcs:// h2 + // + // For secure HTTP backends (https://) that support HTTP/2, set this field + // to "h2" for improved performance. + // + // Configuring this field to non-default values is only supported for secure + // HTTP backends. This field will be ignored for all other backends. + // + // See + // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids + // for more details on the supported values. + string protocol = 9; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/billing.proto b/social-media-service/build/extracted-include-protos/main/google/api/billing.proto new file mode 100644 index 0000000..cf48179 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/billing.proto @@ -0,0 +1,77 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/metric.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "BillingProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Billing related configuration of the service. +// +// The following example shows how to configure monitored resources and metrics +// for billing, `consumer_destinations` is the only supported destination and +// the monitored resources need at least one label key +// `cloud.googleapis.com/location` to indicate the location of the billing +// usage, using different monitored resources between monitoring and billing is +// recommended so they can be evolved independently: +// +// +// monitored_resources: +// - type: library.googleapis.com/billing_branch +// labels: +// - key: cloud.googleapis.com/location +// description: | +// Predefined label to support billing location restriction. +// - key: city +// description: | +// Custom label to define the city where the library branch is located +// in. +// - key: name +// description: Custom label to define the name of the library branch. +// metrics: +// - name: library.googleapis.com/book/borrowed_count +// metric_kind: DELTA +// value_type: INT64 +// unit: "1" +// billing: +// consumer_destinations: +// - monitored_resource: library.googleapis.com/billing_branch +// metrics: +// - library.googleapis.com/book/borrowed_count +message Billing { + // Configuration of a specific billing destination (Currently only support + // bill against consumer project). + message BillingDestination { + // The monitored resource type. The type must be defined in + // [Service.monitored_resources][google.api.Service.monitored_resources] section. + string monitored_resource = 1; + + // Names of the metrics to report to this billing destination. + // Each name must be defined in [Service.metrics][google.api.Service.metrics] section. + repeated string metrics = 2; + } + + // Billing configurations for sending metrics to the consumer project. + // There can be multiple consumer destinations per service, each one must have + // a different monitored resource type. A metric can be used in at most + // one consumer destination. + repeated BillingDestination consumer_destinations = 8; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/client.proto b/social-media-service/build/extracted-include-protos/main/google/api/client.proto new file mode 100644 index 0000000..3b3fd0c --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/client.proto @@ -0,0 +1,99 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "ClientProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // A definition of a client library method signature. + // + // In client libraries, each proto RPC corresponds to one or more methods + // which the end user is able to call, and calls the underlying RPC. + // Normally, this method receives a single argument (a struct or instance + // corresponding to the RPC request object). Defining this field will + // add one or more overloads providing flattened or simpler method signatures + // in some languages. + // + // The fields on the method signature are provided as a comma-separated + // string. + // + // For example, the proto RPC and annotation: + // + // rpc CreateSubscription(CreateSubscriptionRequest) + // returns (Subscription) { + // option (google.api.method_signature) = "name,topic"; + // } + // + // Would add the following Java overload (in addition to the method accepting + // the request object): + // + // public final Subscription createSubscription(String name, String topic) + // + // The following backwards-compatibility guidelines apply: + // + // * Adding this annotation to an unannotated method is backwards + // compatible. + // * Adding this annotation to a method which already has existing + // method signature annotations is backwards compatible if and only if + // the new method signature annotation is last in the sequence. + // * Modifying or removing an existing method signature annotation is + // a breaking change. + // * Re-ordering existing method signature annotations is a breaking + // change. + repeated string method_signature = 1051; +} + +extend google.protobuf.ServiceOptions { + // The hostname for this service. + // This should be specified with no prefix or protocol. + // + // Example: + // + // service Foo { + // option (google.api.default_host) = "foo.googleapi.com"; + // ... + // } + string default_host = 1049; + + // OAuth scopes needed for the client. + // + // Example: + // + // service Foo { + // option (google.api.oauth_scopes) = \ + // "https://www.googleapis.com/auth/cloud-platform"; + // ... + // } + // + // If there is more than one scope, use a comma-separated string: + // + // Example: + // + // service Foo { + // option (google.api.oauth_scopes) = \ + // "https://www.googleapis.com/auth/cloud-platform," + // "https://www.googleapis.com/auth/monitoring"; + // ... + // } + string oauth_scopes = 1050; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/config_change.proto b/social-media-service/build/extracted-include-protos/main/google/api/config_change.proto new file mode 100644 index 0000000..f1fcde4 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/config_change.proto @@ -0,0 +1,84 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/configchange;configchange"; +option java_multiple_files = true; +option java_outer_classname = "ConfigChangeProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Output generated from semantically comparing two versions of a service +// configuration. +// +// Includes detailed information about a field that have changed with +// applicable advice about potential consequences for the change, such as +// backwards-incompatibility. +message ConfigChange { + // Object hierarchy path to the change, with levels separated by a '.' + // character. For repeated fields, an applicable unique identifier field is + // used for the index (usually selector, name, or id). For maps, the term + // 'key' is used. If the field has no unique identifier, the numeric index + // is used. + // Examples: + // - visibility.rules[selector=="google.LibraryService.ListBooks"].restriction + // - quota.metric_rules[selector=="google"].metric_costs[key=="reads"].value + // - logging.producer_destinations[0] + string element = 1; + + // Value of the changed object in the old Service configuration, + // in JSON format. This field will not be populated if ChangeType == ADDED. + string old_value = 2; + + // Value of the changed object in the new Service configuration, + // in JSON format. This field will not be populated if ChangeType == REMOVED. + string new_value = 3; + + // The type for this change, either ADDED, REMOVED, or MODIFIED. + ChangeType change_type = 4; + + // Collection of advice provided for this change, useful for determining the + // possible impact of this change. + repeated Advice advices = 5; +} + +// Generated advice about this change, used for providing more +// information about how a change will affect the existing service. +message Advice { + // Useful description for why this advice was applied and what actions should + // be taken to mitigate any implied risks. + string description = 2; +} + +// Classifies set of possible modifications to an object in the service +// configuration. +enum ChangeType { + // No value was provided. + CHANGE_TYPE_UNSPECIFIED = 0; + + // The changed object exists in the 'new' service configuration, but not + // in the 'old' service configuration. + ADDED = 1; + + // The changed object exists in the 'old' service configuration, but not + // in the 'new' service configuration. + REMOVED = 2; + + // The changed object exists in both service configurations, but its value + // is different. + MODIFIED = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/consumer.proto b/social-media-service/build/extracted-include-protos/main/google/api/consumer.proto new file mode 100644 index 0000000..b7e5df1 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/consumer.proto @@ -0,0 +1,82 @@ +// Copyright 2016 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "ConsumerProto"; +option java_package = "com.google.api"; + +// A descriptor for defining project properties for a service. One service may +// have many consumer projects, and the service may want to behave differently +// depending on some properties on the project. For example, a project may be +// associated with a school, or a business, or a government agency, a business +// type property on the project may affect how a service responds to the client. +// This descriptor defines which properties are allowed to be set on a project. +// +// Example: +// +// project_properties: +// properties: +// - name: NO_WATERMARK +// type: BOOL +// description: Allows usage of the API without watermarks. +// - name: EXTENDED_TILE_CACHE_PERIOD +// type: INT64 +message ProjectProperties { + // List of per consumer project-specific properties. + repeated Property properties = 1; +} + +// Defines project properties. +// +// API services can define properties that can be assigned to consumer projects +// so that backends can perform response customization without having to make +// additional calls or maintain additional storage. For example, Maps API +// defines properties that controls map tile cache period, or whether to embed a +// watermark in a result. +// +// These values can be set via API producer console. Only API providers can +// define and set these properties. +message Property { + // Supported data type of the property values + enum PropertyType { + // The type is unspecified, and will result in an error. + UNSPECIFIED = 0; + + // The type is `int64`. + INT64 = 1; + + // The type is `bool`. + BOOL = 2; + + // The type is `string`. + STRING = 3; + + // The type is 'double'. + DOUBLE = 4; + } + + // The name of the property (a.k.a key). + string name = 1; + + // The type of this property. + PropertyType type = 2; + + // The description of the property + string description = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/context.proto b/social-media-service/build/extracted-include-protos/main/google/api/context.proto new file mode 100644 index 0000000..8e776ec --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/context.proto @@ -0,0 +1,89 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "ContextProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// `Context` defines which contexts an API requests. +// +// Example: +// +// context: +// rules: +// - selector: "*" +// requested: +// - google.rpc.context.ProjectContext +// - google.rpc.context.OriginContext +// +// The above specifies that all methods in the API request +// `google.rpc.context.ProjectContext` and +// `google.rpc.context.OriginContext`. +// +// Available context types are defined in package +// `google.rpc.context`. +// +// This also provides mechanism to allowlist any protobuf message extension that +// can be sent in grpc metadata using โ€œx-goog-ext--binโ€ and +// โ€œx-goog-ext--jspbโ€ format. For example, list any service +// specific protobuf types that can appear in grpc metadata as follows in your +// yaml file: +// +// Example: +// +// context: +// rules: +// - selector: "google.example.library.v1.LibraryService.CreateBook" +// allowed_request_extensions: +// - google.foo.v1.NewExtension +// allowed_response_extensions: +// - google.foo.v1.NewExtension +// +// You can also specify extension ID instead of fully qualified extension name +// here. +message Context { + // A list of RPC context rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated ContextRule rules = 1; +} + +// A context rule provides information about the context for an individual API +// element. +message ContextRule { + // Selects the methods to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // A list of full type names of requested contexts. + repeated string requested = 2; + + // A list of full type names of provided contexts. + repeated string provided = 3; + + // A list of full type names or extension IDs of extensions allowed in grpc + // side channel from client to backend. + repeated string allowed_request_extensions = 4; + + // A list of full type names or extension IDs of extensions allowed in grpc + // side channel from backend to client. + repeated string allowed_response_extensions = 5; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/control.proto b/social-media-service/build/extracted-include-protos/main/google/api/control.proto new file mode 100644 index 0000000..6eb1958 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/control.proto @@ -0,0 +1,32 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "ControlProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Selects and configures the service controller used by the service. The +// service controller handles features like abuse, quota, billing, logging, +// monitoring, etc. +message Control { + // The service control environment to use. If empty, no control plane + // feature (like quota and billing) will be enabled. + string environment = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/distribution.proto b/social-media-service/build/extracted-include-protos/main/google/api/distribution.proto new file mode 100644 index 0000000..b079a43 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/distribution.proto @@ -0,0 +1,211 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/distribution;distribution"; +option java_multiple_files = true; +option java_outer_classname = "DistributionProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// `Distribution` contains summary statistics for a population of values. It +// optionally contains a histogram representing the distribution of those values +// across a set of buckets. +// +// The summary statistics are the count, mean, sum of the squared deviation from +// the mean, the minimum, and the maximum of the set of population of values. +// The histogram is based on a sequence of buckets and gives a count of values +// that fall into each bucket. The boundaries of the buckets are given either +// explicitly or by formulas for buckets of fixed or exponentially increasing +// widths. +// +// Although it is not forbidden, it is generally a bad idea to include +// non-finite values (infinities or NaNs) in the population of values, as this +// will render the `mean` and `sum_of_squared_deviation` fields meaningless. +message Distribution { + // The range of the population values. + message Range { + // The minimum of the population values. + double min = 1; + + // The maximum of the population values. + double max = 2; + } + + // `BucketOptions` describes the bucket boundaries used to create a histogram + // for the distribution. The buckets can be in a linear sequence, an + // exponential sequence, or each bucket can be specified explicitly. + // `BucketOptions` does not include the number of values in each bucket. + // + // A bucket has an inclusive lower bound and exclusive upper bound for the + // values that are counted for that bucket. The upper bound of a bucket must + // be strictly greater than the lower bound. The sequence of N buckets for a + // distribution consists of an underflow bucket (number 0), zero or more + // finite buckets (number 1 through N - 2) and an overflow bucket (number N - + // 1). The buckets are contiguous: the lower bound of bucket i (i > 0) is the + // same as the upper bound of bucket i - 1. The buckets span the whole range + // of finite values: lower bound of the underflow bucket is -infinity and the + // upper bound of the overflow bucket is +infinity. The finite buckets are + // so-called because both bounds are finite. + message BucketOptions { + // Specifies a linear sequence of buckets that all have the same width + // (except overflow and underflow). Each bucket represents a constant + // absolute uncertainty on the specific value in the bucket. + // + // There are `num_finite_buckets + 2` (= N) buckets. Bucket `i` has the + // following boundaries: + // + // Upper bound (0 <= i < N-1): offset + (width * i). + // Lower bound (1 <= i < N): offset + (width * (i - 1)). + message Linear { + // Must be greater than 0. + int32 num_finite_buckets = 1; + + // Must be greater than 0. + double width = 2; + + // Lower bound of the first bucket. + double offset = 3; + } + + // Specifies an exponential sequence of buckets that have a width that is + // proportional to the value of the lower bound. Each bucket represents a + // constant relative uncertainty on a specific value in the bucket. + // + // There are `num_finite_buckets + 2` (= N) buckets. Bucket `i` has the + // following boundaries: + // + // Upper bound (0 <= i < N-1): scale * (growth_factor ^ i). + // Lower bound (1 <= i < N): scale * (growth_factor ^ (i - 1)). + message Exponential { + // Must be greater than 0. + int32 num_finite_buckets = 1; + + // Must be greater than 1. + double growth_factor = 2; + + // Must be greater than 0. + double scale = 3; + } + + // Specifies a set of buckets with arbitrary widths. + // + // There are `size(bounds) + 1` (= N) buckets. Bucket `i` has the following + // boundaries: + // + // Upper bound (0 <= i < N-1): bounds[i] + // Lower bound (1 <= i < N); bounds[i - 1] + // + // The `bounds` field must contain at least one element. If `bounds` has + // only one element, then there are no finite buckets, and that single + // element is the common boundary of the overflow and underflow buckets. + message Explicit { + // The values must be monotonically increasing. + repeated double bounds = 1; + } + + // Exactly one of these three fields must be set. + oneof options { + // The linear bucket. + Linear linear_buckets = 1; + + // The exponential buckets. + Exponential exponential_buckets = 2; + + // The explicit buckets. + Explicit explicit_buckets = 3; + } + } + + // Exemplars are example points that may be used to annotate aggregated + // distribution values. They are metadata that gives information about a + // particular value added to a Distribution bucket, such as a trace ID that + // was active when a value was added. They may contain further information, + // such as a example values and timestamps, origin, etc. + message Exemplar { + // Value of the exemplar point. This value determines to which bucket the + // exemplar belongs. + double value = 1; + + // The observation (sampling) time of the above value. + google.protobuf.Timestamp timestamp = 2; + + // Contextual information about the example value. Examples are: + // + // Trace: type.googleapis.com/google.monitoring.v3.SpanContext + // + // Literal string: type.googleapis.com/google.protobuf.StringValue + // + // Labels dropped during aggregation: + // type.googleapis.com/google.monitoring.v3.DroppedLabels + // + // There may be only a single attachment of any given message type in a + // single exemplar, and this is enforced by the system. + repeated google.protobuf.Any attachments = 3; + } + + // The number of values in the population. Must be non-negative. This value + // must equal the sum of the values in `bucket_counts` if a histogram is + // provided. + int64 count = 1; + + // The arithmetic mean of the values in the population. If `count` is zero + // then this field must be zero. + double mean = 2; + + // The sum of squared deviations from the mean of the values in the + // population. For values x_i this is: + // + // Sum[i=1..n]((x_i - mean)^2) + // + // Knuth, "The Art of Computer Programming", Vol. 2, page 232, 3rd edition + // describes Welford's method for accumulating this sum in one pass. + // + // If `count` is zero then this field must be zero. + double sum_of_squared_deviation = 3; + + // If specified, contains the range of the population values. The field + // must not be present if the `count` is zero. + Range range = 4; + + // Defines the histogram bucket boundaries. If the distribution does not + // contain a histogram, then omit this field. + BucketOptions bucket_options = 6; + + // The number of values in each bucket of the histogram, as described in + // `bucket_options`. If the distribution does not have a histogram, then omit + // this field. If there is a histogram, then the sum of the values in + // `bucket_counts` must equal the value in the `count` field of the + // distribution. + // + // If present, `bucket_counts` should contain N values, where N is the number + // of buckets specified in `bucket_options`. If you supply fewer than N + // values, the remaining values are assumed to be 0. + // + // The order of the values in `bucket_counts` follows the bucket numbering + // schemes described for the three bucket types. The first value must be the + // count for the underflow bucket (number 0). The next N-2 values are the + // counts for the finite buckets (number 1 through N-2). The N'th value in + // `bucket_counts` is the count for the overflow bucket (number N-1). + repeated int64 bucket_counts = 7; + + // Must be in increasing order of `value` field. + repeated Exemplar exemplars = 10; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/documentation.proto b/social-media-service/build/extracted-include-protos/main/google/api/documentation.proto new file mode 100644 index 0000000..7288169 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/documentation.proto @@ -0,0 +1,162 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "DocumentationProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// `Documentation` provides the information for describing a service. +// +// Example: +//
documentation:
+//   summary: >
+//     The Google Calendar API gives access
+//     to most calendar features.
+//   pages:
+//   - name: Overview
+//     content: (== include google/foo/overview.md ==)
+//   - name: Tutorial
+//     content: (== include google/foo/tutorial.md ==)
+//     subpages;
+//     - name: Java
+//       content: (== include google/foo/tutorial_java.md ==)
+//   rules:
+//   - selector: google.calendar.Calendar.Get
+//     description: >
+//       ...
+//   - selector: google.calendar.Calendar.Put
+//     description: >
+//       ...
+// 
+// Documentation is provided in markdown syntax. In addition to +// standard markdown features, definition lists, tables and fenced +// code blocks are supported. Section headers can be provided and are +// interpreted relative to the section nesting of the context where +// a documentation fragment is embedded. +// +// Documentation from the IDL is merged with documentation defined +// via the config at normalization time, where documentation provided +// by config rules overrides IDL provided. +// +// A number of constructs specific to the API platform are supported +// in documentation text. +// +// In order to reference a proto element, the following +// notation can be used: +//
[fully.qualified.proto.name][]
+// To override the display text used for the link, this can be used: +//
[display text][fully.qualified.proto.name]
+// Text can be excluded from doc using the following notation: +//
(-- internal comment --)
+// +// A few directives are available in documentation. Note that +// directives must appear on a single line to be properly +// identified. The `include` directive includes a markdown file from +// an external source: +//
(== include path/to/file ==)
+// The `resource_for` directive marks a message to be the resource of +// a collection in REST view. If it is not specified, tools attempt +// to infer the resource from the operations in a collection: +//
(== resource_for v1.shelves.books ==)
+// The directive `suppress_warning` does not directly affect documentation +// and is documented together with service config validation. +message Documentation { + // A short summary of what the service does. Can only be provided by + // plain text. + string summary = 1; + + // The top level pages for the documentation set. + repeated Page pages = 5; + + // A list of documentation rules that apply to individual API elements. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated DocumentationRule rules = 3; + + // The URL to the root of documentation. + string documentation_root_url = 4; + + // Specifies the service root url if the default one (the service name + // from the yaml file) is not suitable. This can be seen in any fully + // specified service urls as well as sections that show a base that other + // urls are relative to. + string service_root_url = 6; + + // Declares a single overview page. For example: + //
documentation:
+  //   summary: ...
+  //   overview: (== include overview.md ==)
+  // 
+ // This is a shortcut for the following declaration (using pages style): + //
documentation:
+  //   summary: ...
+  //   pages:
+  //   - name: Overview
+  //     content: (== include overview.md ==)
+  // 
+ // Note: you cannot specify both `overview` field and `pages` field. + string overview = 2; +} + +// A documentation rule provides information about individual API elements. +message DocumentationRule { + // The selector is a comma-separated list of patterns. Each pattern is a + // qualified name of the element which may end in "*", indicating a wildcard. + // Wildcards are only allowed at the end and for a whole component of the + // qualified name, i.e. "foo.*" is ok, but not "foo.b*" or "foo.*.bar". A + // wildcard will match one or more components. To specify a default for all + // applicable elements, the whole pattern "*" is used. + string selector = 1; + + // Description of the selected API(s). + string description = 2; + + // Deprecation description of the selected element(s). It can be provided if + // an element is marked as `deprecated`. + string deprecation_description = 3; +} + +// Represents a documentation page. A page can contain subpages to represent +// nested documentation set structure. +message Page { + // The name of the page. It will be used as an identity of the page to + // generate URI of the page, text of the link to this page in navigation, + // etc. The full page name (start from the root page name to this page + // concatenated with `.`) can be used as reference to the page in your + // documentation. For example: + //
pages:
+  // - name: Tutorial
+  //   content: (== include tutorial.md ==)
+  //   subpages:
+  //   - name: Java
+  //     content: (== include tutorial_java.md ==)
+  // 
+ // You can reference `Java` page using Markdown reference link syntax: + // `[Java][Tutorial.Java]`. + string name = 1; + + // The Markdown content of the page. You can use (== include {path} + // ==) to include content from a Markdown file. + string content = 2; + + // Subpages of this page. The order of subpages specified here will be + // honored in the generated docset. + repeated Page subpages = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/endpoint.proto b/social-media-service/build/extracted-include-protos/main/google/api/endpoint.proto new file mode 100644 index 0000000..a434e8e --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/endpoint.proto @@ -0,0 +1,68 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "EndpointProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// `Endpoint` describes a network endpoint of a service that serves a set of +// APIs. It is commonly known as a service endpoint. A service may expose +// any number of service endpoints, and all service endpoints share the same +// service definition, such as quota limits and monitoring metrics. +// +// Example service configuration: +// +// name: library-example.googleapis.com +// endpoints: +// # Below entry makes 'google.example.library.v1.Library' +// # API be served from endpoint address library-example.googleapis.com. +// # It also allows HTTP OPTIONS calls to be passed to the backend, for +// # it to decide whether the subsequent cross-origin request is +// # allowed to proceed. +// - name: library-example.googleapis.com +// allow_cors: true +message Endpoint { + // The canonical name of this endpoint. + string name = 1; + + // Unimplemented. Dot not use. + // + // DEPRECATED: This field is no longer supported. Instead of using aliases, + // please specify multiple [google.api.Endpoint][google.api.Endpoint] for each of the intended + // aliases. + // + // Additional names that this endpoint will be hosted on. + repeated string aliases = 2 [deprecated = true]; + + // The specification of an Internet routable address of API frontend that will + // handle requests to this [API + // Endpoint](https://cloud.google.com/apis/design/glossary). It should be + // either a valid IPv4 address or a fully-qualified domain name. For example, + // "8.8.8.8" or "myservice.appspot.com". + string target = 101; + + // Allowing + // [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing), aka + // cross-domain traffic, would allow the backends served from this endpoint to + // receive and respond to HTTP OPTIONS requests. The response will be used by + // the browser to determine whether the subsequent cross-origin request is + // allowed to proceed. + bool allow_cors = 5; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/error_reason.proto b/social-media-service/build/extracted-include-protos/main/google/api/error_reason.proto new file mode 100644 index 0000000..393c808 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/error_reason.proto @@ -0,0 +1,397 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/error_reason;error_reason"; +option java_multiple_files = true; +option java_outer_classname = "ErrorReasonProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines the supported values for `google.rpc.ErrorInfo.reason` for the +// `googleapis.com` error domain. This error domain is reserved for [Service +// Infrastructure](https://cloud.google.com/service-infrastructure/docs/overview). +// For each error info of this domain, the metadata key "service" refers to the +// logical identifier of an API service, such as "pubsub.googleapis.com". The +// "consumer" refers to the entity that consumes an API Service. It typically is +// a Google project that owns the client application or the server resource, +// such as "projects/123". Other metadata keys are specific to each error +// reason. For more information, see the definition of the specific error +// reason. +enum ErrorReason { + // Do not use this default value. + ERROR_REASON_UNSPECIFIED = 0; + + // The request is calling a disabled service for a consumer. + // + // Example of an ErrorInfo when the consumer "projects/123" contacting + // "pubsub.googleapis.com" service which is disabled: + // + // { "reason": "SERVICE_DISABLED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "pubsub.googleapis.com" + // } + // } + // + // This response indicates the "pubsub.googleapis.com" has been disabled in + // "projects/123". + SERVICE_DISABLED = 1; + + // The request whose associated billing account is disabled. + // + // Example of an ErrorInfo when the consumer "projects/123" fails to contact + // "pubsub.googleapis.com" service because the associated billing account is + // disabled: + // + // { "reason": "BILLING_DISABLED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "pubsub.googleapis.com" + // } + // } + // + // This response indicates the billing account associated has been disabled. + BILLING_DISABLED = 2; + + // The request is denied because the provided [API + // key](https://cloud.google.com/docs/authentication/api-keys) is invalid. It + // may be in a bad format, cannot be found, or has been expired). + // + // Example of an ErrorInfo when the request is contacting + // "storage.googleapis.com" service with an invalid API key: + // + // { "reason": "API_KEY_INVALID", + // "domain": "googleapis.com", + // "metadata": { + // "service": "storage.googleapis.com", + // } + // } + API_KEY_INVALID = 3; + + // The request is denied because it violates [API key API + // restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_api_restrictions). + // + // Example of an ErrorInfo when the consumer "projects/123" fails to call the + // "storage.googleapis.com" service because this service is restricted in the + // API key: + // + // { "reason": "API_KEY_SERVICE_BLOCKED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com" + // } + // } + API_KEY_SERVICE_BLOCKED = 4; + + // The request is denied because it violates [API key HTTP + // restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_http_restrictions). + // + // Example of an ErrorInfo when the consumer "projects/123" fails to call + // "storage.googleapis.com" service because the http referrer of the request + // violates API key HTTP restrictions: + // + // { "reason": "API_KEY_HTTP_REFERRER_BLOCKED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com", + // } + // } + API_KEY_HTTP_REFERRER_BLOCKED = 7; + + // The request is denied because it violates [API key IP address + // restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_application_restrictions). + // + // Example of an ErrorInfo when the consumer "projects/123" fails to call + // "storage.googleapis.com" service because the caller IP of the request + // violates API key IP address restrictions: + // + // { "reason": "API_KEY_IP_ADDRESS_BLOCKED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com", + // } + // } + API_KEY_IP_ADDRESS_BLOCKED = 8; + + // The request is denied because it violates [API key Android application + // restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_application_restrictions). + // + // Example of an ErrorInfo when the consumer "projects/123" fails to call + // "storage.googleapis.com" service because the request from the Android apps + // violates the API key Android application restrictions: + // + // { "reason": "API_KEY_ANDROID_APP_BLOCKED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com" + // } + // } + API_KEY_ANDROID_APP_BLOCKED = 9; + + // The request is denied because it violates [API key iOS application + // restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_application_restrictions). + // + // Example of an ErrorInfo when the consumer "projects/123" fails to call + // "storage.googleapis.com" service because the request from the iOS apps + // violates the API key iOS application restrictions: + // + // { "reason": "API_KEY_IOS_APP_BLOCKED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com" + // } + // } + API_KEY_IOS_APP_BLOCKED = 13; + + // The request is denied because there is not enough rate quota for the + // consumer. + // + // Example of an ErrorInfo when the consumer "projects/123" fails to contact + // "pubsub.googleapis.com" service because consumer's rate quota usage has + // reached the maximum value set for the quota limit + // "ReadsPerMinutePerProject" on the quota metric + // "pubsub.googleapis.com/read_requests": + // + // { "reason": "RATE_LIMIT_EXCEEDED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "pubsub.googleapis.com", + // "quota_metric": "pubsub.googleapis.com/read_requests", + // "quota_limit": "ReadsPerMinutePerProject" + // } + // } + // + // Example of an ErrorInfo when the consumer "projects/123" checks quota on + // the service "dataflow.googleapis.com" and hits the organization quota + // limit "DefaultRequestsPerMinutePerOrganization" on the metric + // "dataflow.googleapis.com/default_requests". + // + // { "reason": "RATE_LIMIT_EXCEEDED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "dataflow.googleapis.com", + // "quota_metric": "dataflow.googleapis.com/default_requests", + // "quota_limit": "DefaultRequestsPerMinutePerOrganization" + // } + // } + RATE_LIMIT_EXCEEDED = 5; + + // The request is denied because there is not enough resource quota for the + // consumer. + // + // Example of an ErrorInfo when the consumer "projects/123" fails to contact + // "compute.googleapis.com" service because consumer's resource quota usage + // has reached the maximum value set for the quota limit "VMsPerProject" + // on the quota metric "compute.googleapis.com/vms": + // + // { "reason": "RESOURCE_QUOTA_EXCEEDED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "compute.googleapis.com", + // "quota_metric": "compute.googleapis.com/vms", + // "quota_limit": "VMsPerProject" + // } + // } + // + // Example of an ErrorInfo when the consumer "projects/123" checks resource + // quota on the service "dataflow.googleapis.com" and hits the organization + // quota limit "jobs-per-organization" on the metric + // "dataflow.googleapis.com/job_count". + // + // { "reason": "RESOURCE_QUOTA_EXCEEDED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "dataflow.googleapis.com", + // "quota_metric": "dataflow.googleapis.com/job_count", + // "quota_limit": "jobs-per-organization" + // } + // } + RESOURCE_QUOTA_EXCEEDED = 6; + + // The request whose associated billing account address is in a tax restricted + // location, violates the local tax restrictions when creating resources in + // the restricted region. + // + // Example of an ErrorInfo when creating the Cloud Storage Bucket in the + // container "projects/123" under a tax restricted region + // "locations/asia-northeast3": + // + // { "reason": "LOCATION_TAX_POLICY_VIOLATED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com", + // "location": "locations/asia-northeast3" + // } + // } + // + // This response indicates creating the Cloud Storage Bucket in + // "locations/asia-northeast3" violates the location tax restriction. + LOCATION_TAX_POLICY_VIOLATED = 10; + + // The request is denied because the caller does not have required permission + // on the user project "projects/123" or the user project is invalid. For more + // information, check the [userProject System + // Parameters](https://cloud.google.com/apis/docs/system-parameters). + // + // Example of an ErrorInfo when the caller is calling Cloud Storage service + // with insufficient permissions on the user project: + // + // { "reason": "USER_PROJECT_DENIED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com" + // } + // } + USER_PROJECT_DENIED = 11; + + // The request is denied because the consumer "projects/123" is suspended due + // to Terms of Service(Tos) violations. Check [Project suspension + // guidelines](https://cloud.google.com/resource-manager/docs/project-suspension-guidelines) + // for more information. + // + // Example of an ErrorInfo when calling Cloud Storage service with the + // suspended consumer "projects/123": + // + // { "reason": "CONSUMER_SUSPENDED", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com" + // } + // } + CONSUMER_SUSPENDED = 12; + + // The request is denied because the associated consumer is invalid. It may be + // in a bad format, cannot be found, or have been deleted. + // + // Example of an ErrorInfo when calling Cloud Storage service with the + // invalid consumer "projects/123": + // + // { "reason": "CONSUMER_INVALID", + // "domain": "googleapis.com", + // "metadata": { + // "consumer": "projects/123", + // "service": "storage.googleapis.com" + // } + // } + CONSUMER_INVALID = 14; + + // The request is denied because it violates [VPC Service + // Controls](https://cloud.google.com/vpc-service-controls/docs/overview). + // The 'uid' field is a random generated identifier that customer can use it + // to search the audit log for a request rejected by VPC Service Controls. For + // more information, please refer [VPC Service Controls + // Troubleshooting](https://cloud.google.com/vpc-service-controls/docs/troubleshooting#unique-id) + // + // Example of an ErrorInfo when the consumer "projects/123" fails to call + // Cloud Storage service because the request is prohibited by the VPC Service + // Controls. + // + // { "reason": "SECURITY_POLICY_VIOLATED", + // "domain": "googleapis.com", + // "metadata": { + // "uid": "123456789abcde", + // "consumer": "projects/123", + // "service": "storage.googleapis.com" + // } + // } + SECURITY_POLICY_VIOLATED = 15; + + // The request is denied because the provided access token has expired. + // + // Example of an ErrorInfo when the request is calling Cloud Storage service + // with an expired access token: + // + // { "reason": "ACCESS_TOKEN_EXPIRED", + // "domain": "googleapis.com", + // "metadata": { + // "service": "storage.googleapis.com", + // "method": "google.storage.v1.Storage.GetObject" + // } + // } + ACCESS_TOKEN_EXPIRED = 16; + + // The request is denied because the provided access token doesn't have at + // least one of the acceptable scopes required for the API. Please check + // [OAuth 2.0 Scopes for Google + // APIs](https://developers.google.com/identity/protocols/oauth2/scopes) for + // the list of the OAuth 2.0 scopes that you might need to request to access + // the API. + // + // Example of an ErrorInfo when the request is calling Cloud Storage service + // with an access token that is missing required scopes: + // + // { "reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT", + // "domain": "googleapis.com", + // "metadata": { + // "service": "storage.googleapis.com", + // "method": "google.storage.v1.Storage.GetObject" + // } + // } + ACCESS_TOKEN_SCOPE_INSUFFICIENT = 17; + + // The request is denied because the account associated with the provided + // access token is in an invalid state, such as disabled or deleted. + // For more information, see https://cloud.google.com/docs/authentication. + // + // Warning: For privacy reasons, the server may not be able to disclose the + // email address for some accounts. The client MUST NOT depend on the + // availability of the `email` attribute. + // + // Example of an ErrorInfo when the request is to the Cloud Storage API with + // an access token that is associated with a disabled or deleted [service + // account](http://cloud/iam/docs/service-accounts): + // + // { "reason": "ACCOUNT_STATE_INVALID", + // "domain": "googleapis.com", + // "metadata": { + // "service": "storage.googleapis.com", + // "method": "google.storage.v1.Storage.GetObject", + // "email": "user@123.iam.gserviceaccount.com" + // } + // } + ACCOUNT_STATE_INVALID = 18; + + // The request is denied because the type of the provided access token is not + // supported by the API being called. + // + // Example of an ErrorInfo when the request is to the Cloud Storage API with + // an unsupported token type. + // + // { "reason": "ACCESS_TOKEN_TYPE_UNSUPPORTED", + // "domain": "googleapis.com", + // "metadata": { + // "service": "storage.googleapis.com", + // "method": "google.storage.v1.Storage.GetObject" + // } + // } + ACCESS_TOKEN_TYPE_UNSUPPORTED = 19; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/field_behavior.proto b/social-media-service/build/extracted-include-protos/main/google/api/field_behavior.proto new file mode 100644 index 0000000..c4abe3b --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/field_behavior.proto @@ -0,0 +1,90 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "FieldBehaviorProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.FieldOptions { + // A designation of a specific field behavior (required, output only, etc.) + // in protobuf messages. + // + // Examples: + // + // string name = 1 [(google.api.field_behavior) = REQUIRED]; + // State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; + // google.protobuf.Duration ttl = 1 + // [(google.api.field_behavior) = INPUT_ONLY]; + // google.protobuf.Timestamp expire_time = 1 + // [(google.api.field_behavior) = OUTPUT_ONLY, + // (google.api.field_behavior) = IMMUTABLE]; + repeated google.api.FieldBehavior field_behavior = 1052; +} + +// An indicator of the behavior of a given field (for example, that a field +// is required in requests, or given as output but ignored as input). +// This **does not** change the behavior in protocol buffers itself; it only +// denotes the behavior and may affect how API tooling handles the field. +// +// Note: This enum **may** receive new values in the future. +enum FieldBehavior { + // Conventional default for enums. Do not use this. + FIELD_BEHAVIOR_UNSPECIFIED = 0; + + // Specifically denotes a field as optional. + // While all fields in protocol buffers are optional, this may be specified + // for emphasis if appropriate. + OPTIONAL = 1; + + // Denotes a field as required. + // This indicates that the field **must** be provided as part of the request, + // and failure to do so will cause an error (usually `INVALID_ARGUMENT`). + REQUIRED = 2; + + // Denotes a field as output only. + // This indicates that the field is provided in responses, but including the + // field in a request does nothing (the server *must* ignore it and + // *must not* throw an error as a result of the field's presence). + OUTPUT_ONLY = 3; + + // Denotes a field as input only. + // This indicates that the field is provided in requests, and the + // corresponding field is not included in output. + INPUT_ONLY = 4; + + // Denotes a field as immutable. + // This indicates that the field may be set once in a request to create a + // resource, but may not be changed thereafter. + IMMUTABLE = 5; + + // Denotes that a (repeated) field is an unordered list. + // This indicates that the service may provide the elements of the list + // in any arbitrary order, rather than the order the user originally + // provided. Additionally, the list's order may or may not be stable. + UNORDERED_LIST = 6; + + // Denotes that this field returns a non-empty default value if not set. + // This indicates that if the user provides the empty value in a request, + // a non-empty value will be returned. The user will not be aware of what + // non-empty value to expect. + NON_EMPTY_DEFAULT = 7; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/http.proto b/social-media-service/build/extracted-include-protos/main/google/api/http.proto new file mode 100644 index 0000000..113fa93 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/http.proto @@ -0,0 +1,375 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// # gRPC Transcoding +// +// gRPC Transcoding is a feature for mapping between a gRPC method and one or +// more HTTP REST endpoints. It allows developers to build a single API service +// that supports both gRPC APIs and REST APIs. Many systems, including [Google +// APIs](https://github.com/googleapis/googleapis), +// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC +// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), +// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature +// and use it for large scale production services. +// +// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +// how different portions of the gRPC request message are mapped to the URL +// path, URL query parameters, and HTTP request body. It also controls how the +// gRPC response message is mapped to the HTTP response body. `HttpRule` is +// typically specified as an `google.api.http` annotation on the gRPC method. +// +// Each mapping specifies a URL path template and an HTTP method. The path +// template may refer to one or more fields in the gRPC request message, as long +// as each field is a non-repeated field with a primitive (non-message) type. +// The path template controls how fields of the request message are mapped to +// the URL path. +// +// Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } +// +// This enables an HTTP REST to gRPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// +// Any fields in the request message which are not bound by the path template +// automatically become HTTP query parameters if there is no HTTP request body. +// For example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +// "foo"))` +// +// Note that fields which are mapped to URL query parameters must have a +// primitive type or a repeated primitive type or a non-repeated message type. +// In the case of a repeated type, the parameter can be repeated in the URL +// as `...?param=A¶m=B`. In the case of a message type, each field of the +// message is mapped to a separate parameter, such as +// `...?foo.a=A&foo.b=B&foo.c=C`. +// +// For HTTP methods that allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice when +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// This enables the following two alternative HTTP JSON to RPC mappings: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +// "123456")` +// +// ## Rules for HTTP mapping +// +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// are passed via URL path and HTTP request body. +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// fields are passed via URL path and URL query parameters. +// +// ### Path template syntax +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single URL path segment. The syntax `**` matches +// zero or more URL path segments, which must be the last part of the URL path +// except the `Verb`. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +// contains any reserved character, such characters should be percent-encoded +// before the matching. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path on the client +// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The +// server side does the reverse decoding. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{var}`. +// +// If a variable contains multiple path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path on the +// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. +// The server side does the reverse decoding, except "%2F" and "%2f" are left +// unchanged. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{+var}`. +// +// ## Using gRPC API Service Configuration +// +// gRPC API Service Configuration (service config) is a configuration language +// for configuring a gRPC service to become a user-facing product. The +// service config is simply the YAML representation of the `google.api.Service` +// proto message. +// +// As an alternative to annotating your proto file, you can configure gRPC +// transcoding in your service config YAML files. You do this by specifying a +// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +// effect as the proto annotation. This can be particularly useful if you +// have a proto that is reused in multiple services. Note that any transcoding +// specified in the service config will override any matching transcoding +// configuration in the proto. +// +// Example: +// +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// ## Special notes +// +// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +// proto to JSON conversion must follow the [proto3 +// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). +// +// While the single segment variable follows the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String +// Expansion, the multi segment variable **does not** follow RFC 6570 Section +// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +// for multi segment variables. +// +// The path variables **must not** refer to any repeated or mapped field, +// because client libraries are not capable of handling such variable expansion. +// +// The path variables **must not** capture the leading "/" character. The reason +// is that the most common use case "{var}" does not capture the leading "/" +// character. For consistency, all path variables must share the same behavior. +// +// Repeated message fields must not be mapped to URL query parameters, because +// no client library can support such complicated mapping. +// +// If an API needs to use a JSON array for request or response body, it can map +// the request or response body to a repeated field. However, some gRPC +// Transcoding implementations may not support this feature. +message HttpRule { + // Selects a method to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Maps to HTTP GET. Used for listing and getting information about + // resources. + string get = 2; + + // Maps to HTTP PUT. Used for replacing a resource. + string put = 3; + + // Maps to HTTP POST. Used for creating a resource or performing an action. + string post = 4; + + // Maps to HTTP DELETE. Used for deleting a resource. + string delete = 5; + + // Maps to HTTP PATCH. Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP request + // body, or `*` for mapping all request fields not captured by the path + // pattern to the HTTP body, or omitted for not having any HTTP request body. + // + // NOTE: the referred field must be present at the top-level of the request + // message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // response body. When omitted, the entire response message will be used + // as the HTTP response body. + // + // NOTE: The referred field must be present at the top-level of the response + // message type. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/httpbody.proto b/social-media-service/build/extracted-include-protos/main/google/api/httpbody.proto new file mode 100644 index 0000000..00c80ab --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/httpbody.proto @@ -0,0 +1,81 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; +option java_multiple_files = true; +option java_outer_classname = "HttpBodyProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Message that represents an arbitrary HTTP body. It should only be used for +// payload formats that can't be represented as JSON, such as raw binary or +// an HTML page. +// +// +// This message can be used both in streaming and non-streaming API methods in +// the request as well as the response. +// +// It can be used as a top-level request field, which is convenient if one +// wants to extract parameters from either the URL or HTTP template into the +// request fields and also want access to the raw HTTP body. +// +// Example: +// +// message GetResourceRequest { +// // A unique request id. +// string request_id = 1; +// +// // The raw HTTP body is bound to this field. +// google.api.HttpBody http_body = 2; +// +// } +// +// service ResourceService { +// rpc GetResource(GetResourceRequest) +// returns (google.api.HttpBody); +// rpc UpdateResource(google.api.HttpBody) +// returns (google.protobuf.Empty); +// +// } +// +// Example with streaming methods: +// +// service CaldavService { +// rpc GetCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// rpc UpdateCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// +// } +// +// Use of this type only changes how the request and response bodies are +// handled, all other features will continue to work unchanged. +message HttpBody { + // The HTTP Content-Type header value specifying the content type of the body. + string content_type = 1; + + // The HTTP request/response body as raw binary. + bytes data = 2; + + // Application specific response metadata. Must be set in the first response + // for streaming APIs. + repeated google.protobuf.Any extensions = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/label.proto b/social-media-service/build/extracted-include-protos/main/google/api/label.proto new file mode 100644 index 0000000..af294c9 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/label.proto @@ -0,0 +1,48 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/label;label"; +option java_multiple_files = true; +option java_outer_classname = "LabelProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// A description of a label. +message LabelDescriptor { + // Value types that can be used as label values. + enum ValueType { + // A variable-length string. This is the default. + STRING = 0; + + // Boolean; true or false. + BOOL = 1; + + // A 64-bit signed integer. + INT64 = 2; + } + + // The label key. + string key = 1; + + // The type of data that can be assigned to the label. + ValueType value_type = 2; + + // A human-readable description for the label. + string description = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/launch_stage.proto b/social-media-service/build/extracted-include-protos/main/google/api/launch_stage.proto new file mode 100644 index 0000000..cca8419 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/launch_stage.proto @@ -0,0 +1,72 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api;api"; +option java_multiple_files = true; +option java_outer_classname = "LaunchStageProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// The launch stage as defined by [Google Cloud Platform +// Launch Stages](http://cloud.google.com/terms/launch-stages). +enum LaunchStage { + // Do not use this default value. + LAUNCH_STAGE_UNSPECIFIED = 0; + + // The feature is not yet implemented. Users can not use it. + UNIMPLEMENTED = 6; + + // Prelaunch features are hidden from users and are only visible internally. + PRELAUNCH = 7; + + // Early Access features are limited to a closed group of testers. To use + // these features, you must sign up in advance and sign a Trusted Tester + // agreement (which includes confidentiality provisions). These features may + // be unstable, changed in backward-incompatible ways, and are not + // guaranteed to be released. + EARLY_ACCESS = 1; + + // Alpha is a limited availability test for releases before they are cleared + // for widespread use. By Alpha, all significant design issues are resolved + // and we are in the process of verifying functionality. Alpha customers + // need to apply for access, agree to applicable terms, and have their + // projects allowlisted. Alpha releases donโ€™t have to be feature complete, + // no SLAs are provided, and there are no technical support obligations, but + // they will be far enough along that customers can actually use them in + // test environments or for limited-use tests -- just like they would in + // normal production cases. + ALPHA = 2; + + // Beta is the point at which we are ready to open a release for any + // customer to use. There are no SLA or technical support obligations in a + // Beta release. Products will be complete from a feature perspective, but + // may have some open outstanding issues. Beta releases are suitable for + // limited production use cases. + BETA = 3; + + // GA features are open to all developers and are considered stable and + // fully qualified for production use. + GA = 4; + + // Deprecated features are scheduled to be shut down and removed. For more + // information, see the โ€œDeprecation Policyโ€ section of our [Terms of + // Service](https://cloud.google.com/terms/) + // and the [Google Cloud Platform Subject to the Deprecation + // Policy](https://cloud.google.com/terms/deprecation) documentation. + DEPRECATED = 5; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/log.proto b/social-media-service/build/extracted-include-protos/main/google/api/log.proto new file mode 100644 index 0000000..22ee289 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/log.proto @@ -0,0 +1,54 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/label.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "LogProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// A description of a log type. Example in YAML format: +// +// - name: library.googleapis.com/activity_history +// description: The history of borrowing and returning library items. +// display_name: Activity +// labels: +// - key: /customer_id +// description: Identifier of a library customer +message LogDescriptor { + // The name of the log. It must be less than 512 characters long and can + // include the following characters: upper- and lower-case alphanumeric + // characters [A-Za-z0-9], and punctuation characters including + // slash, underscore, hyphen, period [/_-.]. + string name = 1; + + // The set of labels that are available to describe a specific log entry. + // Runtime requests that contain labels not specified here are + // considered invalid. + repeated LabelDescriptor labels = 2; + + // A human-readable description of this log. This information appears in + // the documentation and can contain details. + string description = 3; + + // The human-readable name for this log. This information appears on + // the user interface and should be concise. + string display_name = 4; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/logging.proto b/social-media-service/build/extracted-include-protos/main/google/api/logging.proto new file mode 100644 index 0000000..e60f77c --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/logging.proto @@ -0,0 +1,80 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "LoggingProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Logging configuration of the service. +// +// The following example shows how to configure logs to be sent to the +// producer and consumer projects. In the example, the `activity_history` +// log is sent to both the producer and consumer projects, whereas the +// `purchase_history` log is only sent to the producer project. +// +// monitored_resources: +// - type: library.googleapis.com/branch +// labels: +// - key: /city +// description: The city where the library branch is located in. +// - key: /name +// description: The name of the branch. +// logs: +// - name: activity_history +// labels: +// - key: /customer_id +// - name: purchase_history +// logging: +// producer_destinations: +// - monitored_resource: library.googleapis.com/branch +// logs: +// - activity_history +// - purchase_history +// consumer_destinations: +// - monitored_resource: library.googleapis.com/branch +// logs: +// - activity_history +message Logging { + // Configuration of a specific logging destination (the producer project + // or the consumer project). + message LoggingDestination { + // The monitored resource type. The type must be defined in the + // [Service.monitored_resources][google.api.Service.monitored_resources] section. + string monitored_resource = 3; + + // Names of the logs to be sent to this destination. Each name must + // be defined in the [Service.logs][google.api.Service.logs] section. If the log name is + // not a domain scoped name, it will be automatically prefixed with + // the service name followed by "/". + repeated string logs = 1; + } + + // Logging configurations for sending logs to the producer project. + // There can be multiple producer destinations, each one must have a + // different monitored resource type. A log can be used in at most + // one producer destination. + repeated LoggingDestination producer_destinations = 1; + + // Logging configurations for sending logs to the consumer project. + // There can be multiple consumer destinations, each one must have a + // different monitored resource type. A log can be used in at most + // one consumer destination. + repeated LoggingDestination consumer_destinations = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/metric.proto b/social-media-service/build/extracted-include-protos/main/google/api/metric.proto new file mode 100644 index 0000000..aadc196 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/metric.proto @@ -0,0 +1,264 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/label.proto"; +import "google/api/launch_stage.proto"; +import "google/protobuf/duration.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/metric;metric"; +option java_multiple_files = true; +option java_outer_classname = "MetricProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines a metric type and its schema. Once a metric descriptor is created, +// deleting or altering it stops data collection and makes the metric type's +// existing data unusable. +// +message MetricDescriptor { + // Additional annotations that can be used to guide the usage of a metric. + message MetricDescriptorMetadata { + // Deprecated. Must use the [MetricDescriptor.launch_stage][google.api.MetricDescriptor.launch_stage] instead. + LaunchStage launch_stage = 1 [deprecated = true]; + + // The sampling period of metric data points. For metrics which are written + // periodically, consecutive data points are stored at this time interval, + // excluding data loss due to errors. Metrics with a higher granularity have + // a smaller sampling period. + google.protobuf.Duration sample_period = 2; + + // The delay of data points caused by ingestion. Data points older than this + // age are guaranteed to be ingested and available to be read, excluding + // data loss due to errors. + google.protobuf.Duration ingest_delay = 3; + } + + // The kind of measurement. It describes how the data is reported. + // For information on setting the start time and end time based on + // the MetricKind, see [TimeInterval][google.monitoring.v3.TimeInterval]. + enum MetricKind { + // Do not use this default value. + METRIC_KIND_UNSPECIFIED = 0; + + // An instantaneous measurement of a value. + GAUGE = 1; + + // The change in a value during a time interval. + DELTA = 2; + + // A value accumulated over a time interval. Cumulative + // measurements in a time series should have the same start time + // and increasing end times, until an event resets the cumulative + // value to zero and sets a new start time for the following + // points. + CUMULATIVE = 3; + } + + // The value type of a metric. + enum ValueType { + // Do not use this default value. + VALUE_TYPE_UNSPECIFIED = 0; + + // The value is a boolean. + // This value type can be used only if the metric kind is `GAUGE`. + BOOL = 1; + + // The value is a signed 64-bit integer. + INT64 = 2; + + // The value is a double precision floating point number. + DOUBLE = 3; + + // The value is a text string. + // This value type can be used only if the metric kind is `GAUGE`. + STRING = 4; + + // The value is a [`Distribution`][google.api.Distribution]. + DISTRIBUTION = 5; + + // The value is money. + MONEY = 6; + } + + // The resource name of the metric descriptor. + string name = 1; + + // The metric type, including its DNS name prefix. The type is not + // URL-encoded. All user-defined metric types have the DNS name + // `custom.googleapis.com` or `external.googleapis.com`. Metric types should + // use a natural hierarchical grouping. For example: + // + // "custom.googleapis.com/invoice/paid/amount" + // "external.googleapis.com/prometheus/up" + // "appengine.googleapis.com/http/server/response_latencies" + string type = 8; + + // The set of labels that can be used to describe a specific + // instance of this metric type. For example, the + // `appengine.googleapis.com/http/server/response_latencies` metric + // type has a label for the HTTP response code, `response_code`, so + // you can look at latencies for successful responses or just + // for responses that failed. + repeated LabelDescriptor labels = 2; + + // Whether the metric records instantaneous values, changes to a value, etc. + // Some combinations of `metric_kind` and `value_type` might not be supported. + MetricKind metric_kind = 3; + + // Whether the measurement is an integer, a floating-point number, etc. + // Some combinations of `metric_kind` and `value_type` might not be supported. + ValueType value_type = 4; + + // The units in which the metric value is reported. It is only applicable + // if the `value_type` is `INT64`, `DOUBLE`, or `DISTRIBUTION`. The `unit` + // defines the representation of the stored metric values. + // + // Different systems might scale the values to be more easily displayed (so a + // value of `0.02kBy` _might_ be displayed as `20By`, and a value of + // `3523kBy` _might_ be displayed as `3.5MBy`). However, if the `unit` is + // `kBy`, then the value of the metric is always in thousands of bytes, no + // matter how it might be displayed. + // + // If you want a custom metric to record the exact number of CPU-seconds used + // by a job, you can create an `INT64 CUMULATIVE` metric whose `unit` is + // `s{CPU}` (or equivalently `1s{CPU}` or just `s`). If the job uses 12,005 + // CPU-seconds, then the value is written as `12005`. + // + // Alternatively, if you want a custom metric to record data in a more + // granular way, you can create a `DOUBLE CUMULATIVE` metric whose `unit` is + // `ks{CPU}`, and then write the value `12.005` (which is `12005/1000`), + // or use `Kis{CPU}` and write `11.723` (which is `12005/1024`). + // + // The supported units are a subset of [The Unified Code for Units of + // Measure](https://unitsofmeasure.org/ucum.html) standard: + // + // **Basic units (UNIT)** + // + // * `bit` bit + // * `By` byte + // * `s` second + // * `min` minute + // * `h` hour + // * `d` day + // * `1` dimensionless + // + // **Prefixes (PREFIX)** + // + // * `k` kilo (10^3) + // * `M` mega (10^6) + // * `G` giga (10^9) + // * `T` tera (10^12) + // * `P` peta (10^15) + // * `E` exa (10^18) + // * `Z` zetta (10^21) + // * `Y` yotta (10^24) + // + // * `m` milli (10^-3) + // * `u` micro (10^-6) + // * `n` nano (10^-9) + // * `p` pico (10^-12) + // * `f` femto (10^-15) + // * `a` atto (10^-18) + // * `z` zepto (10^-21) + // * `y` yocto (10^-24) + // + // * `Ki` kibi (2^10) + // * `Mi` mebi (2^20) + // * `Gi` gibi (2^30) + // * `Ti` tebi (2^40) + // * `Pi` pebi (2^50) + // + // **Grammar** + // + // The grammar also includes these connectors: + // + // * `/` division or ratio (as an infix operator). For examples, + // `kBy/{email}` or `MiBy/10ms` (although you should almost never + // have `/s` in a metric `unit`; rates should always be computed at + // query time from the underlying cumulative or delta value). + // * `.` multiplication or composition (as an infix operator). For + // examples, `GBy.d` or `k{watt}.h`. + // + // The grammar for a unit is as follows: + // + // Expression = Component { "." Component } { "/" Component } ; + // + // Component = ( [ PREFIX ] UNIT | "%" ) [ Annotation ] + // | Annotation + // | "1" + // ; + // + // Annotation = "{" NAME "}" ; + // + // Notes: + // + // * `Annotation` is just a comment if it follows a `UNIT`. If the annotation + // is used alone, then the unit is equivalent to `1`. For examples, + // `{request}/s == 1/s`, `By{transmitted}/s == By/s`. + // * `NAME` is a sequence of non-blank printable ASCII characters not + // containing `{` or `}`. + // * `1` represents a unitary [dimensionless + // unit](https://en.wikipedia.org/wiki/Dimensionless_quantity) of 1, such + // as in `1/s`. It is typically used when none of the basic units are + // appropriate. For example, "new users per day" can be represented as + // `1/d` or `{new-users}/d` (and a metric value `5` would mean "5 new + // users). Alternatively, "thousands of page views per day" would be + // represented as `1000/d` or `k1/d` or `k{page_views}/d` (and a metric + // value of `5.3` would mean "5300 page views per day"). + // * `%` represents dimensionless value of 1/100, and annotates values giving + // a percentage (so the metric values are typically in the range of 0..100, + // and a metric value `3` means "3 percent"). + // * `10^2.%` indicates a metric contains a ratio, typically in the range + // 0..1, that will be multiplied by 100 and displayed as a percentage + // (so a metric value `0.03` means "3 percent"). + string unit = 5; + + // A detailed description of the metric, which can be used in documentation. + string description = 6; + + // A concise name for the metric, which can be displayed in user interfaces. + // Use sentence case without an ending period, for example "Request count". + // This field is optional but it is recommended to be set for any metrics + // associated with user-visible concepts, such as Quota. + string display_name = 7; + + // Optional. Metadata which can be used to guide usage of the metric. + MetricDescriptorMetadata metadata = 10; + + // Optional. The launch stage of the metric definition. + LaunchStage launch_stage = 12; + + // Read-only. If present, then a [time + // series][google.monitoring.v3.TimeSeries], which is identified partially by + // a metric type and a [MonitoredResourceDescriptor][google.api.MonitoredResourceDescriptor], that is associated + // with this metric type can only be associated with one of the monitored + // resource types listed here. + repeated string monitored_resource_types = 13; +} + +// A specific metric, identified by specifying values for all of the +// labels of a [`MetricDescriptor`][google.api.MetricDescriptor]. +message Metric { + // An existing metric type, see [google.api.MetricDescriptor][google.api.MetricDescriptor]. + // For example, `custom.googleapis.com/invoice/paid/amount`. + string type = 3; + + // The set of label values that uniquely identify this metric. All + // labels listed in the `MetricDescriptor` must be assigned values. + map labels = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/monitored_resource.proto b/social-media-service/build/extracted-include-protos/main/google/api/monitored_resource.proto new file mode 100644 index 0000000..bd5be4e --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/monitored_resource.proto @@ -0,0 +1,118 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/label.proto"; +import "google/api/launch_stage.proto"; +import "google/protobuf/struct.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/monitoredres;monitoredres"; +option java_multiple_files = true; +option java_outer_classname = "MonitoredResourceProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// An object that describes the schema of a [MonitoredResource][google.api.MonitoredResource] object using a +// type name and a set of labels. For example, the monitored resource +// descriptor for Google Compute Engine VM instances has a type of +// `"gce_instance"` and specifies the use of the labels `"instance_id"` and +// `"zone"` to identify particular VM instances. +// +// Different APIs can support different monitored resource types. APIs generally +// provide a `list` method that returns the monitored resource descriptors used +// by the API. +// +message MonitoredResourceDescriptor { + // Optional. The resource name of the monitored resource descriptor: + // `"projects/{project_id}/monitoredResourceDescriptors/{type}"` where + // {type} is the value of the `type` field in this object and + // {project_id} is a project ID that provides API-specific context for + // accessing the type. APIs that do not use project information can use the + // resource name format `"monitoredResourceDescriptors/{type}"`. + string name = 5; + + // Required. The monitored resource type. For example, the type + // `"cloudsql_database"` represents databases in Google Cloud SQL. + string type = 1; + + // Optional. A concise name for the monitored resource type that might be + // displayed in user interfaces. It should be a Title Cased Noun Phrase, + // without any article or other determiners. For example, + // `"Google Cloud SQL Database"`. + string display_name = 2; + + // Optional. A detailed description of the monitored resource type that might + // be used in documentation. + string description = 3; + + // Required. A set of labels used to describe instances of this monitored + // resource type. For example, an individual Google Cloud SQL database is + // identified by values for the labels `"database_id"` and `"zone"`. + repeated LabelDescriptor labels = 4; + + // Optional. The launch stage of the monitored resource definition. + LaunchStage launch_stage = 7; +} + +// An object representing a resource that can be used for monitoring, logging, +// billing, or other purposes. Examples include virtual machine instances, +// databases, and storage devices such as disks. The `type` field identifies a +// [MonitoredResourceDescriptor][google.api.MonitoredResourceDescriptor] object that describes the resource's +// schema. Information in the `labels` field identifies the actual resource and +// its attributes according to the schema. For example, a particular Compute +// Engine VM instance could be represented by the following object, because the +// [MonitoredResourceDescriptor][google.api.MonitoredResourceDescriptor] for `"gce_instance"` has labels +// `"instance_id"` and `"zone"`: +// +// { "type": "gce_instance", +// "labels": { "instance_id": "12345678901234", +// "zone": "us-central1-a" }} +message MonitoredResource { + // Required. The monitored resource type. This field must match + // the `type` field of a [MonitoredResourceDescriptor][google.api.MonitoredResourceDescriptor] object. For + // example, the type of a Compute Engine VM instance is `gce_instance`. + string type = 1; + + // Required. Values for all of the labels listed in the associated monitored + // resource descriptor. For example, Compute Engine VM instances use the + // labels `"project_id"`, `"instance_id"`, and `"zone"`. + map labels = 2; +} + +// Auxiliary metadata for a [MonitoredResource][google.api.MonitoredResource] object. +// [MonitoredResource][google.api.MonitoredResource] objects contain the minimum set of information to +// uniquely identify a monitored resource instance. There is some other useful +// auxiliary metadata. Monitoring and Logging use an ingestion +// pipeline to extract metadata for cloud resources of all types, and store +// the metadata in this message. +message MonitoredResourceMetadata { + // Output only. Values for predefined system metadata labels. + // System labels are a kind of metadata extracted by Google, including + // "machine_image", "vpc", "subnet_id", + // "security_group", "name", etc. + // System label values can be only strings, Boolean values, or a list of + // strings. For example: + // + // { "name": "my-test-instance", + // "security_group": ["a", "b", "c"], + // "spot_instance": false } + google.protobuf.Struct system_labels = 1; + + // Output only. A map of user-defined metadata labels. + map user_labels = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/monitoring.proto b/social-media-service/build/extracted-include-protos/main/google/api/monitoring.proto new file mode 100644 index 0000000..60770ec --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/monitoring.proto @@ -0,0 +1,105 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "MonitoringProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Monitoring configuration of the service. +// +// The example below shows how to configure monitored resources and metrics +// for monitoring. In the example, a monitored resource and two metrics are +// defined. The `library.googleapis.com/book/returned_count` metric is sent +// to both producer and consumer projects, whereas the +// `library.googleapis.com/book/num_overdue` metric is only sent to the +// consumer project. +// +// monitored_resources: +// - type: library.googleapis.com/Branch +// display_name: "Library Branch" +// description: "A branch of a library." +// launch_stage: GA +// labels: +// - key: resource_container +// description: "The Cloud container (ie. project id) for the Branch." +// - key: location +// description: "The location of the library branch." +// - key: branch_id +// description: "The id of the branch." +// metrics: +// - name: library.googleapis.com/book/returned_count +// display_name: "Books Returned" +// description: "The count of books that have been returned." +// launch_stage: GA +// metric_kind: DELTA +// value_type: INT64 +// unit: "1" +// labels: +// - key: customer_id +// description: "The id of the customer." +// - name: library.googleapis.com/book/num_overdue +// display_name: "Books Overdue" +// description: "The current number of overdue books." +// launch_stage: GA +// metric_kind: GAUGE +// value_type: INT64 +// unit: "1" +// labels: +// - key: customer_id +// description: "The id of the customer." +// monitoring: +// producer_destinations: +// - monitored_resource: library.googleapis.com/Branch +// metrics: +// - library.googleapis.com/book/returned_count +// consumer_destinations: +// - monitored_resource: library.googleapis.com/Branch +// metrics: +// - library.googleapis.com/book/returned_count +// - library.googleapis.com/book/num_overdue +message Monitoring { + // Configuration of a specific monitoring destination (the producer project + // or the consumer project). + message MonitoringDestination { + // The monitored resource type. The type must be defined in + // [Service.monitored_resources][google.api.Service.monitored_resources] section. + string monitored_resource = 1; + + // Types of the metrics to report to this monitoring destination. + // Each type must be defined in [Service.metrics][google.api.Service.metrics] section. + repeated string metrics = 2; + } + + // Monitoring configurations for sending metrics to the producer project. + // There can be multiple producer destinations. A monitored resource type may + // appear in multiple monitoring destinations if different aggregations are + // needed for different sets of metrics associated with that monitored + // resource type. A monitored resource and metric pair may only be used once + // in the Monitoring configuration. + repeated MonitoringDestination producer_destinations = 1; + + // Monitoring configurations for sending metrics to the consumer project. + // There can be multiple consumer destinations. A monitored resource type may + // appear in multiple monitoring destinations if different aggregations are + // needed for different sets of metrics associated with that monitored + // resource type. A monitored resource and metric pair may only be used once + // in the Monitoring configuration. + repeated MonitoringDestination consumer_destinations = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/quota.proto b/social-media-service/build/extracted-include-protos/main/google/api/quota.proto new file mode 100644 index 0000000..dae89de --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/quota.proto @@ -0,0 +1,183 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "QuotaProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Quota configuration helps to achieve fairness and budgeting in service +// usage. +// +// The metric based quota configuration works this way: +// - The service configuration defines a set of metrics. +// - For API calls, the quota.metric_rules maps methods to metrics with +// corresponding costs. +// - The quota.limits defines limits on the metrics, which will be used for +// quota checks at runtime. +// +// An example quota configuration in yaml format: +// +// quota: +// limits: +// +// - name: apiWriteQpsPerProject +// metric: library.googleapis.com/write_calls +// unit: "1/min/{project}" # rate limit for consumer projects +// values: +// STANDARD: 10000 +// +// +// # The metric rules bind all methods to the read_calls metric, +// # except for the UpdateBook and DeleteBook methods. These two methods +// # are mapped to the write_calls metric, with the UpdateBook method +// # consuming at twice rate as the DeleteBook method. +// metric_rules: +// - selector: "*" +// metric_costs: +// library.googleapis.com/read_calls: 1 +// - selector: google.example.library.v1.LibraryService.UpdateBook +// metric_costs: +// library.googleapis.com/write_calls: 2 +// - selector: google.example.library.v1.LibraryService.DeleteBook +// metric_costs: +// library.googleapis.com/write_calls: 1 +// +// Corresponding Metric definition: +// +// metrics: +// - name: library.googleapis.com/read_calls +// display_name: Read requests +// metric_kind: DELTA +// value_type: INT64 +// +// - name: library.googleapis.com/write_calls +// display_name: Write requests +// metric_kind: DELTA +// value_type: INT64 +// +// +message Quota { + // List of `QuotaLimit` definitions for the service. + repeated QuotaLimit limits = 3; + + // List of `MetricRule` definitions, each one mapping a selected method to one + // or more metrics. + repeated MetricRule metric_rules = 4; +} + +// Bind API methods to metrics. Binding a method to a metric causes that +// metric's configured quota behaviors to apply to the method call. +message MetricRule { + // Selects the methods to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Metrics to update when the selected methods are called, and the associated + // cost applied to each metric. + // + // The key of the map is the metric name, and the values are the amount + // increased for the metric against which the quota limits are defined. + // The value must not be negative. + map metric_costs = 2; +} + +// `QuotaLimit` defines a specific limit that applies over a specified duration +// for a limit type. There can be at most one limit for a duration and limit +// type combination defined within a `QuotaGroup`. +message QuotaLimit { + // Name of the quota limit. + // + // The name must be provided, and it must be unique within the service. The + // name can only include alphanumeric characters as well as '-'. + // + // The maximum length of the limit name is 64 characters. + string name = 6; + + // Optional. User-visible, extended description for this quota limit. + // Should be used only when more context is needed to understand this limit + // than provided by the limit's display name (see: `display_name`). + string description = 2; + + // Default number of tokens that can be consumed during the specified + // duration. This is the number of tokens assigned when a client + // application developer activates the service for his/her project. + // + // Specifying a value of 0 will block all requests. This can be used if you + // are provisioning quota to selected consumers and blocking others. + // Similarly, a value of -1 will indicate an unlimited quota. No other + // negative values are allowed. + // + // Used by group-based quotas only. + int64 default_limit = 3; + + // Maximum number of tokens that can be consumed during the specified + // duration. Client application developers can override the default limit up + // to this maximum. If specified, this value cannot be set to a value less + // than the default limit. If not specified, it is set to the default limit. + // + // To allow clients to apply overrides with no upper bound, set this to -1, + // indicating unlimited maximum quota. + // + // Used by group-based quotas only. + int64 max_limit = 4; + + // Free tier value displayed in the Developers Console for this limit. + // The free tier is the number of tokens that will be subtracted from the + // billed amount when billing is enabled. + // This field can only be set on a limit with duration "1d", in a billable + // group; it is invalid on any other limit. If this field is not set, it + // defaults to 0, indicating that there is no free tier for this service. + // + // Used by group-based quotas only. + int64 free_tier = 7; + + // Duration of this limit in textual notation. Must be "100s" or "1d". + // + // Used by group-based quotas only. + string duration = 5; + + // The name of the metric this quota limit applies to. The quota limits with + // the same metric will be checked together during runtime. The metric must be + // defined within the service config. + string metric = 8; + + // Specify the unit of the quota limit. It uses the same syntax as + // [Metric.unit][]. The supported unit kinds are determined by the quota + // backend system. + // + // Here are some examples: + // * "1/min/{project}" for quota per minute per project. + // + // Note: the order of unit components is insignificant. + // The "1" at the beginning is required to follow the metric unit syntax. + string unit = 9; + + // Tiered limit values. You must specify this as a key:value pair, with an + // integer value that is the maximum number of requests allowed for the + // specified unit. Currently only STANDARD is supported. + map values = 10; + + // User-visible display name for this limit. + // Optional. If not set, the UI will provide a default display name based on + // the quota configuration. This field can be used to override the default + // display name generated from the configuration. + string display_name = 12; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/resource.proto b/social-media-service/build/extracted-include-protos/main/google/api/resource.proto new file mode 100644 index 0000000..0ce0344 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/resource.proto @@ -0,0 +1,238 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "ResourceProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.FieldOptions { + // An annotation that describes a resource reference, see + // [ResourceReference][]. + google.api.ResourceReference resource_reference = 1055; +} + +extend google.protobuf.FileOptions { + // An annotation that describes a resource definition without a corresponding + // message; see [ResourceDescriptor][]. + repeated google.api.ResourceDescriptor resource_definition = 1053; +} + +extend google.protobuf.MessageOptions { + // An annotation that describes a resource definition, see + // [ResourceDescriptor][]. + google.api.ResourceDescriptor resource = 1053; +} + +// A simple descriptor of a resource type. +// +// ResourceDescriptor annotates a resource message (either by means of a +// protobuf annotation or use in the service config), and associates the +// resource's schema, the resource type, and the pattern of the resource name. +// +// Example: +// +// message Topic { +// // Indicates this message defines a resource schema. +// // Declares the resource type in the format of {service}/{kind}. +// // For Kubernetes resources, the format is {api group}/{kind}. +// option (google.api.resource) = { +// type: "pubsub.googleapis.com/Topic" +// pattern: "projects/{project}/topics/{topic}" +// }; +// } +// +// The ResourceDescriptor Yaml config will look like: +// +// resources: +// - type: "pubsub.googleapis.com/Topic" +// pattern: "projects/{project}/topics/{topic}" +// +// Sometimes, resources have multiple patterns, typically because they can +// live under multiple parents. +// +// Example: +// +// message LogEntry { +// option (google.api.resource) = { +// type: "logging.googleapis.com/LogEntry" +// pattern: "projects/{project}/logs/{log}" +// pattern: "folders/{folder}/logs/{log}" +// pattern: "organizations/{organization}/logs/{log}" +// pattern: "billingAccounts/{billing_account}/logs/{log}" +// }; +// } +// +// The ResourceDescriptor Yaml config will look like: +// +// resources: +// - type: 'logging.googleapis.com/LogEntry' +// pattern: "projects/{project}/logs/{log}" +// pattern: "folders/{folder}/logs/{log}" +// pattern: "organizations/{organization}/logs/{log}" +// pattern: "billingAccounts/{billing_account}/logs/{log}" +message ResourceDescriptor { + // A description of the historical or future-looking state of the + // resource pattern. + enum History { + // The "unset" value. + HISTORY_UNSPECIFIED = 0; + + // The resource originally had one pattern and launched as such, and + // additional patterns were added later. + ORIGINALLY_SINGLE_PATTERN = 1; + + // The resource has one pattern, but the API owner expects to add more + // later. (This is the inverse of ORIGINALLY_SINGLE_PATTERN, and prevents + // that from being necessary once there are multiple patterns.) + FUTURE_MULTI_PATTERN = 2; + } + + // A flag representing a specific style that a resource claims to conform to. + enum Style { + // The unspecified value. Do not use. + STYLE_UNSPECIFIED = 0; + + // This resource is intended to be "declarative-friendly". + // + // Declarative-friendly resources must be more strictly consistent, and + // setting this to true communicates to tools that this resource should + // adhere to declarative-friendly expectations. + // + // Note: This is used by the API linter (linter.aip.dev) to enable + // additional checks. + DECLARATIVE_FRIENDLY = 1; + } + + // The resource type. It must be in the format of + // {service_name}/{resource_type_kind}. The `resource_type_kind` must be + // singular and must not include version numbers. + // + // Example: `storage.googleapis.com/Bucket` + // + // The value of the resource_type_kind must follow the regular expression + // /[A-Za-z][a-zA-Z0-9]+/. It should start with an upper case character and + // should use PascalCase (UpperCamelCase). The maximum number of + // characters allowed for the `resource_type_kind` is 100. + string type = 1; + + // Optional. The relative resource name pattern associated with this resource + // type. The DNS prefix of the full resource name shouldn't be specified here. + // + // The path pattern must follow the syntax, which aligns with HTTP binding + // syntax: + // + // Template = Segment { "/" Segment } ; + // Segment = LITERAL | Variable ; + // Variable = "{" LITERAL "}" ; + // + // Examples: + // + // - "projects/{project}/topics/{topic}" + // - "projects/{project}/knowledgeBases/{knowledge_base}" + // + // The components in braces correspond to the IDs for each resource in the + // hierarchy. It is expected that, if multiple patterns are provided, + // the same component name (e.g. "project") refers to IDs of the same + // type of resource. + repeated string pattern = 2; + + // Optional. The field on the resource that designates the resource name + // field. If omitted, this is assumed to be "name". + string name_field = 3; + + // Optional. The historical or future-looking state of the resource pattern. + // + // Example: + // + // // The InspectTemplate message originally only supported resource + // // names with organization, and project was added later. + // message InspectTemplate { + // option (google.api.resource) = { + // type: "dlp.googleapis.com/InspectTemplate" + // pattern: + // "organizations/{organization}/inspectTemplates/{inspect_template}" + // pattern: "projects/{project}/inspectTemplates/{inspect_template}" + // history: ORIGINALLY_SINGLE_PATTERN + // }; + // } + History history = 4; + + // The plural name used in the resource name and permission names, such as + // 'projects' for the resource name of 'projects/{project}' and the permission + // name of 'cloudresourcemanager.googleapis.com/projects.get'. It is the same + // concept of the `plural` field in k8s CRD spec + // https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/ + // + // Note: The plural form is required even for singleton resources. See + // https://aip.dev/156 + string plural = 5; + + // The same concept of the `singular` field in k8s CRD spec + // https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/ + // Such as "project" for the `resourcemanager.googleapis.com/Project` type. + string singular = 6; + + // Style flag(s) for this resource. + // These indicate that a resource is expected to conform to a given + // style. See the specific style flags for additional information. + repeated Style style = 10; +} + +// Defines a proto annotation that describes a string field that refers to +// an API resource. +message ResourceReference { + // The resource type that the annotated field references. + // + // Example: + // + // message Subscription { + // string topic = 2 [(google.api.resource_reference) = { + // type: "pubsub.googleapis.com/Topic" + // }]; + // } + // + // Occasionally, a field may reference an arbitrary resource. In this case, + // APIs use the special value * in their resource reference. + // + // Example: + // + // message GetIamPolicyRequest { + // string resource = 2 [(google.api.resource_reference) = { + // type: "*" + // }]; + // } + string type = 1; + + // The resource type of a child collection that the annotated field + // references. This is useful for annotating the `parent` field that + // doesn't have a fixed resource type. + // + // Example: + // + // message ListLogEntriesRequest { + // string parent = 1 [(google.api.resource_reference) = { + // child_type: "logging.googleapis.com/LogEntry" + // }; + // } + string child_type = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/routing.proto b/social-media-service/build/extracted-include-protos/main/google/api/routing.proto new file mode 100644 index 0000000..0138283 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/routing.proto @@ -0,0 +1,461 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "RoutingProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See RoutingRule. + google.api.RoutingRule routing = 72295729; +} + +// Specifies the routing information that should be sent along with the request +// in the form of routing header. +// **NOTE:** All service configuration rules follow the "last one wins" order. +// +// The examples below will apply to an RPC which has the following request type: +// +// Message Definition: +// +// message Request { +// // The name of the Table +// // Values can be of the following formats: +// // - `projects//tables/` +// // - `projects//instances//tables/
` +// // - `region//zones//tables/
` +// string table_name = 1; +// +// // This value specifies routing for replication. +// // It can be in the following formats: +// // - `profiles/` +// // - a legacy `profile_id` that can be any string +// string app_profile_id = 2; +// } +// +// Example message: +// +// { +// table_name: projects/proj_foo/instances/instance_bar/table/table_baz, +// app_profile_id: profiles/prof_qux +// } +// +// The routing header consists of one or multiple key-value pairs. Every key +// and value must be percent-encoded, and joined together in the format of +// `key1=value1&key2=value2`. +// In the examples below I am skipping the percent-encoding for readablity. +// +// Example 1 +// +// Extracting a field from the request to put into the routing header +// unchanged, with the key equal to the field name. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `app_profile_id`. +// routing_parameters { +// field: "app_profile_id" +// } +// }; +// +// result: +// +// x-goog-request-params: app_profile_id=profiles/prof_qux +// +// Example 2 +// +// Extracting a field from the request to put into the routing header +// unchanged, with the key different from the field name. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `app_profile_id`, but name it `routing_id` in the header. +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// }; +// +// result: +// +// x-goog-request-params: routing_id=profiles/prof_qux +// +// Example 3 +// +// Extracting a field from the request to put into the routing +// header, while matching a path template syntax on the field's value. +// +// NB: it is more useful to send nothing than to send garbage for the purpose +// of dynamic routing, since garbage pollutes cache. Thus the matching. +// +// Sub-example 3a +// +// The field matches the template. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `table_name`, if it's well-formed (with project-based +// // syntax). +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=projects/*/instances/*/**}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// table_name=projects/proj_foo/instances/instance_bar/table/table_baz +// +// Sub-example 3b +// +// The field does not match the template. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `table_name`, if it's well-formed (with region-based +// // syntax). +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=regions/*/zones/*/**}" +// } +// }; +// +// result: +// +// +// +// Sub-example 3c +// +// Multiple alternative conflictingly named path templates are +// specified. The one that matches is used to construct the header. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `table_name`, if it's well-formed, whether +// // using the region- or projects-based syntax. +// +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=regions/*/zones/*/**}" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=projects/*/instances/*/**}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// table_name=projects/proj_foo/instances/instance_bar/table/table_baz +// +// Example 4 +// +// Extracting a single routing header key-value pair by matching a +// template syntax on (a part of) a single request field. +// +// annotation: +// +// option (google.api.routing) = { +// // Take just the project id from the `table_name` field. +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// }; +// +// result: +// +// x-goog-request-params: routing_id=projects/proj_foo +// +// Example 5 +// +// Extracting a single routing header key-value pair by matching +// several conflictingly named path templates on (parts of) a single request +// field. The last template to match "wins" the conflict. +// +// annotation: +// +// option (google.api.routing) = { +// // If the `table_name` does not have instances information, +// // take just the project id for routing. +// // Otherwise take project + instance. +// +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*/instances/*}/**" +// } +// }; +// +// result: +// +// x-goog-request-params: +// routing_id=projects/proj_foo/instances/instance_bar +// +// Example 6 +// +// Extracting multiple routing header key-value pairs by matching +// several non-conflicting path templates on (parts of) a single request field. +// +// Sub-example 6a +// +// Make the templates strict, so that if the `table_name` does not +// have an instance information, nothing is sent. +// +// annotation: +// +// option (google.api.routing) = { +// // The routing code needs two keys instead of one composite +// // but works only for the tables with the "project-instance" name +// // syntax. +// +// routing_parameters { +// field: "table_name" +// path_template: "{project_id=projects/*}/instances/*/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "projects/*/{instance_id=instances/*}/**" +// } +// }; +// +// result: +// +// x-goog-request-params: +// project_id=projects/proj_foo&instance_id=instances/instance_bar +// +// Sub-example 6b +// +// Make the templates loose, so that if the `table_name` does not +// have an instance information, just the project id part is sent. +// +// annotation: +// +// option (google.api.routing) = { +// // The routing code wants two keys instead of one composite +// // but will work with just the `project_id` for tables without +// // an instance in the `table_name`. +// +// routing_parameters { +// field: "table_name" +// path_template: "{project_id=projects/*}/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "projects/*/{instance_id=instances/*}/**" +// } +// }; +// +// result (is the same as 6a for our example message because it has the instance +// information): +// +// x-goog-request-params: +// project_id=projects/proj_foo&instance_id=instances/instance_bar +// +// Example 7 +// +// Extracting multiple routing header key-value pairs by matching +// several path templates on multiple request fields. +// +// NB: note that here there is no way to specify sending nothing if one of the +// fields does not match its template. E.g. if the `table_name` is in the wrong +// format, the `project_id` will not be sent, but the `routing_id` will be. +// The backend routing code has to be aware of that and be prepared to not +// receive a full complement of keys if it expects multiple. +// +// annotation: +// +// option (google.api.routing) = { +// // The routing needs both `project_id` and `routing_id` +// // (from the `app_profile_id` field) for routing. +// +// routing_parameters { +// field: "table_name" +// path_template: "{project_id=projects/*}/**" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// project_id=projects/proj_foo&routing_id=profiles/prof_qux +// +// Example 8 +// +// Extracting a single routing header key-value pair by matching +// several conflictingly named path templates on several request fields. The +// last template to match "wins" the conflict. +// +// annotation: +// +// option (google.api.routing) = { +// // The `routing_id` can be a project id or a region id depending on +// // the table name format, but only if the `app_profile_id` is not set. +// // If `app_profile_id` is set it should be used instead. +// +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=regions/*}/**" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// }; +// +// result: +// +// x-goog-request-params: routing_id=profiles/prof_qux +// +// Example 9 +// +// Bringing it all together. +// +// annotation: +// +// option (google.api.routing) = { +// // For routing both `table_location` and a `routing_id` are needed. +// // +// // table_location can be either an instance id or a region+zone id. +// // +// // For `routing_id`, take the value of `app_profile_id` +// // - If it's in the format `profiles/`, send +// // just the `` part. +// // - If it's any other literal, send it as is. +// // If the `app_profile_id` is empty, and the `table_name` starts with +// // the project_id, send that instead. +// +// routing_parameters { +// field: "table_name" +// path_template: "projects/*/{table_location=instances/*}/tables/*" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{table_location=regions/*/zones/*}/tables/*" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "profiles/{routing_id=*}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// table_location=instances/instance_bar&routing_id=prof_qux +message RoutingRule { + // A collection of Routing Parameter specifications. + // **NOTE:** If multiple Routing Parameters describe the same key + // (via the `path_template` field or via the `field` field when + // `path_template` is not provided), "last one wins" rule + // determines which Parameter gets used. + // See the examples for more details. + repeated RoutingParameter routing_parameters = 2; +} + +// A projection from an input message to the GRPC or REST header. +message RoutingParameter { + // A request field to extract the header key-value pair from. + string field = 1; + + // A pattern matching the key-value field. Optional. + // If not specified, the whole field specified in the `field` field will be + // taken as value, and its name used as key. If specified, it MUST contain + // exactly one named segment (along with any number of unnamed segments) The + // pattern will be matched over the field specified in the `field` field, then + // if the match is successful: + // - the name of the single named segment will be used as a header name, + // - the match value of the segment will be used as a header value; + // if the match is NOT successful, nothing will be sent. + // + // Example: + // + // -- This is a field in the request message + // | that the header value will be extracted from. + // | + // | -- This is the key name in the + // | | routing header. + // V | + // field: "table_name" v + // path_template: "projects/*/{table_location=instances/*}/tables/*" + // ^ ^ + // | | + // In the {} brackets is the pattern that -- | + // specifies what to extract from the | + // field as a value to be sent. | + // | + // The string in the field must match the whole pattern -- + // before brackets, inside brackets, after brackets. + // + // When looking at this specific example, we can see that: + // - A key-value pair with the key `table_location` + // and the value matching `instances/*` should be added + // to the x-goog-request-params routing header. + // - The value is extracted from the request message's `table_name` field + // if it matches the full pattern specified: + // `projects/*/instances/*/tables/*`. + // + // **NB:** If the `path_template` field is not provided, the key name is + // equal to the field name, and the whole field should be sent as a value. + // This makes the pattern for the field and the value functionally equivalent + // to `**`, and the configuration + // + // { + // field: "table_name" + // } + // + // is a functionally equivalent shorthand to: + // + // { + // field: "table_name" + // path_template: "{table_name=**}" + // } + // + // See Example 1 for more details. + string path_template = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/service.proto b/social-media-service/build/extracted-include-protos/main/google/api/service.proto new file mode 100644 index 0000000..bb988a9 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/service.proto @@ -0,0 +1,175 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/auth.proto"; +import "google/api/backend.proto"; +import "google/api/billing.proto"; +import "google/api/context.proto"; +import "google/api/control.proto"; +import "google/api/documentation.proto"; +import "google/api/endpoint.proto"; +import "google/api/http.proto"; +import "google/api/label.proto"; +import "google/api/log.proto"; +import "google/api/logging.proto"; +import "google/api/metric.proto"; +import "google/api/monitored_resource.proto"; +import "google/api/monitoring.proto"; +import "google/api/quota.proto"; +import "google/api/resource.proto"; +import "google/api/source_info.proto"; +import "google/api/system_parameter.proto"; +import "google/api/usage.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/api.proto"; +import "google/protobuf/type.proto"; +import "google/protobuf/wrappers.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "ServiceProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// `Service` is the root object of Google service configuration schema. It +// describes basic information about a service, such as the name and the +// title, and delegates other aspects to sub-sections. Each sub-section is +// either a proto message or a repeated proto message that configures a +// specific aspect, such as auth. See each proto message definition for details. +// +// Example: +// +// type: google.api.Service +// name: calendar.googleapis.com +// title: Google Calendar API +// apis: +// - name: google.calendar.v3.Calendar +// authentication: +// providers: +// - id: google_calendar_auth +// jwks_uri: https://www.googleapis.com/oauth2/v1/certs +// issuer: https://securetoken.google.com +// rules: +// - selector: "*" +// requirements: +// provider_id: google_calendar_auth +message Service { + // The service name, which is a DNS-like logical identifier for the + // service, such as `calendar.googleapis.com`. The service name + // typically goes through DNS verification to make sure the owner + // of the service also owns the DNS name. + string name = 1; + + // The product title for this service. + string title = 2; + + // The Google project that owns this service. + string producer_project_id = 22; + + // A unique ID for a specific instance of this message, typically assigned + // by the client for tracking purpose. Must be no longer than 63 characters + // and only lower case letters, digits, '.', '_' and '-' are allowed. If + // empty, the server may choose to generate one instead. + string id = 33; + + // A list of API interfaces exported by this service. Only the `name` field + // of the [google.protobuf.Api][google.protobuf.Api] needs to be provided by the configuration + // author, as the remaining fields will be derived from the IDL during the + // normalization process. It is an error to specify an API interface here + // which cannot be resolved against the associated IDL files. + repeated google.protobuf.Api apis = 3; + + // A list of all proto message types included in this API service. + // Types referenced directly or indirectly by the `apis` are + // automatically included. Messages which are not referenced but + // shall be included, such as types used by the `google.protobuf.Any` type, + // should be listed here by name. Example: + // + // types: + // - name: google.protobuf.Int32 + repeated google.protobuf.Type types = 4; + + // A list of all enum types included in this API service. Enums + // referenced directly or indirectly by the `apis` are automatically + // included. Enums which are not referenced but shall be included + // should be listed here by name. Example: + // + // enums: + // - name: google.someapi.v1.SomeEnum + repeated google.protobuf.Enum enums = 5; + + // Additional API documentation. + Documentation documentation = 6; + + // API backend configuration. + Backend backend = 8; + + // HTTP configuration. + Http http = 9; + + // Quota configuration. + Quota quota = 10; + + // Auth configuration. + Authentication authentication = 11; + + // Context configuration. + Context context = 12; + + // Configuration controlling usage of this service. + Usage usage = 15; + + // Configuration for network endpoints. If this is empty, then an endpoint + // with the same name as the service is automatically generated to service all + // defined APIs. + repeated Endpoint endpoints = 18; + + // Configuration for the service control plane. + Control control = 21; + + // Defines the logs used by this service. + repeated LogDescriptor logs = 23; + + // Defines the metrics used by this service. + repeated MetricDescriptor metrics = 24; + + // Defines the monitored resources used by this service. This is required + // by the [Service.monitoring][google.api.Service.monitoring] and [Service.logging][google.api.Service.logging] configurations. + repeated MonitoredResourceDescriptor monitored_resources = 25; + + // Billing configuration. + Billing billing = 26; + + // Logging configuration. + Logging logging = 27; + + // Monitoring configuration. + Monitoring monitoring = 28; + + // System parameter configuration. + SystemParameters system_parameters = 29; + + // Output only. The source information for this configuration if available. + SourceInfo source_info = 37; + + // Obsolete. Do not use. + // + // This field has no semantic meaning. The service config compiler always + // sets this field to `3`. + google.protobuf.UInt32Value config_version = 20 [deprecated = true]; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/source_info.proto b/social-media-service/build/extracted-include-protos/main/google/api/source_info.proto new file mode 100644 index 0000000..cbdd625 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/source_info.proto @@ -0,0 +1,31 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/any.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "SourceInfoProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Source information used to create a Service Config +message SourceInfo { + // All files used during config generation. + repeated google.protobuf.Any source_files = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/system_parameter.proto b/social-media-service/build/extracted-include-protos/main/google/api/system_parameter.proto new file mode 100644 index 0000000..7d0b1d5 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/system_parameter.proto @@ -0,0 +1,95 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "SystemParameterProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// ### System parameter configuration +// +// A system parameter is a special kind of parameter defined by the API +// system, not by an individual API. It is typically mapped to an HTTP header +// and/or a URL query parameter. This configuration specifies which methods +// change the names of the system parameters. +message SystemParameters { + // Define system parameters. + // + // The parameters defined here will override the default parameters + // implemented by the system. If this field is missing from the service + // config, default system parameters will be used. Default system parameters + // and names is implementation-dependent. + // + // Example: define api key for all methods + // + // system_parameters + // rules: + // - selector: "*" + // parameters: + // - name: api_key + // url_query_parameter: api_key + // + // + // Example: define 2 api key names for a specific method. + // + // system_parameters + // rules: + // - selector: "/ListShelves" + // parameters: + // - name: api_key + // http_header: Api-Key1 + // - name: api_key + // http_header: Api-Key2 + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated SystemParameterRule rules = 1; +} + +// Define a system parameter rule mapping system parameter definitions to +// methods. +message SystemParameterRule { + // Selects the methods to which this rule applies. Use '*' to indicate all + // methods in all APIs. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Define parameters. Multiple names may be defined for a parameter. + // For a given method call, only one of them should be used. If multiple + // names are used the behavior is implementation-dependent. + // If none of the specified names are present the behavior is + // parameter-dependent. + repeated SystemParameter parameters = 2; +} + +// Define a parameter's name and location. The parameter may be passed as either +// an HTTP header or a URL query parameter, and if both are passed the behavior +// is implementation-dependent. +message SystemParameter { + // Define the name of the parameter, such as "api_key" . It is case sensitive. + string name = 1; + + // Define the HTTP header name to use for the parameter. It is case + // insensitive. + string http_header = 2; + + // Define the URL query parameter name to use for the parameter. It is case + // sensitive. + string url_query_parameter = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/usage.proto b/social-media-service/build/extracted-include-protos/main/google/api/usage.proto new file mode 100644 index 0000000..ad2764c --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/usage.proto @@ -0,0 +1,95 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "UsageProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Configuration controlling usage of a service. +message Usage { + // Requirements that must be satisfied before a consumer project can use the + // service. Each requirement is of the form /; + // for example 'serviceusage.googleapis.com/billing-enabled'. + // + // For Google APIs, a Terms of Service requirement must be included here. + // Google Cloud APIs must include "serviceusage.googleapis.com/tos/cloud". + // Other Google APIs should include + // "serviceusage.googleapis.com/tos/universal". Additional ToS can be + // included based on the business needs. + repeated string requirements = 1; + + // A list of usage rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated UsageRule rules = 6; + + // The full resource name of a channel used for sending notifications to the + // service producer. + // + // Google Service Management currently only supports + // [Google Cloud Pub/Sub](https://cloud.google.com/pubsub) as a notification + // channel. To use Google Cloud Pub/Sub as the channel, this must be the name + // of a Cloud Pub/Sub topic that uses the Cloud Pub/Sub topic name format + // documented in https://cloud.google.com/pubsub/docs/overview. + string producer_notification_channel = 7; +} + +// Usage configuration rules for the service. +// +// NOTE: Under development. +// +// +// Use this rule to configure unregistered calls for the service. Unregistered +// calls are calls that do not contain consumer project identity. +// (Example: calls that do not contain an API key). +// By default, API methods do not allow unregistered calls, and each method call +// must be identified by a consumer project identity. Use this rule to +// allow/disallow unregistered calls. +// +// Example of an API that wants to allow unregistered calls for entire service. +// +// usage: +// rules: +// - selector: "*" +// allow_unregistered_calls: true +// +// Example of a method that wants to allow unregistered calls. +// +// usage: +// rules: +// - selector: "google.example.library.v1.LibraryService.CreateBook" +// allow_unregistered_calls: true +message UsageRule { + // Selects the methods to which this rule applies. Use '*' to indicate all + // methods in all APIs. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // If true, the selected method allows unregistered calls, e.g. calls + // that don't identify any user or application. + bool allow_unregistered_calls = 2; + + // If true, the selected method should skip service control and the control + // plane features, such as quota and billing, will not be available. + // This flag is used by Google Cloud Endpoints to bypass checks for internal + // methods, such as service health check methods. + bool skip_service_control = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/api/visibility.proto b/social-media-service/build/extracted-include-protos/main/google/api/visibility.proto new file mode 100644 index 0000000..bde48dd --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/api/visibility.proto @@ -0,0 +1,111 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/visibility;visibility"; +option java_multiple_files = true; +option java_outer_classname = "VisibilityProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.EnumOptions { + // See `VisibilityRule`. + google.api.VisibilityRule enum_visibility = 72295727; +} + +extend google.protobuf.EnumValueOptions { + // See `VisibilityRule`. + google.api.VisibilityRule value_visibility = 72295727; +} + +extend google.protobuf.FieldOptions { + // See `VisibilityRule`. + google.api.VisibilityRule field_visibility = 72295727; +} + +extend google.protobuf.MessageOptions { + // See `VisibilityRule`. + google.api.VisibilityRule message_visibility = 72295727; +} + +extend google.protobuf.MethodOptions { + // See `VisibilityRule`. + google.api.VisibilityRule method_visibility = 72295727; +} + +extend google.protobuf.ServiceOptions { + // See `VisibilityRule`. + google.api.VisibilityRule api_visibility = 72295727; +} + +// `Visibility` defines restrictions for the visibility of service +// elements. Restrictions are specified using visibility labels +// (e.g., PREVIEW) that are elsewhere linked to users and projects. +// +// Users and projects can have access to more than one visibility label. The +// effective visibility for multiple labels is the union of each label's +// elements, plus any unrestricted elements. +// +// If an element and its parents have no restrictions, visibility is +// unconditionally granted. +// +// Example: +// +// visibility: +// rules: +// - selector: google.calendar.Calendar.EnhancedSearch +// restriction: PREVIEW +// - selector: google.calendar.Calendar.Delegate +// restriction: INTERNAL +// +// Here, all methods are publicly visible except for the restricted methods +// EnhancedSearch and Delegate. +message Visibility { + // A list of visibility rules that apply to individual API elements. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated VisibilityRule rules = 1; +} + +// A visibility rule provides visibility configuration for an individual API +// element. +message VisibilityRule { + // Selects methods, messages, fields, enums, etc. to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // A comma-separated list of visibility labels that apply to the `selector`. + // Any of the listed labels can be used to grant the visibility. + // + // If a rule has multiple labels, removing one of the labels but not all of + // them can break clients. + // + // Example: + // + // visibility: + // rules: + // - selector: google.calendar.Calendar.EnhancedSearch + // restriction: INTERNAL, PREVIEW + // + // Removing INTERNAL from this restriction will break clients that rely on + // this method and only had access to it through INTERNAL. + string restriction = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/cloud/audit/audit_log.proto b/social-media-service/build/extracted-include-protos/main/google/cloud/audit/audit_log.proto new file mode 100644 index 0000000..33d5008 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/cloud/audit/audit_log.proto @@ -0,0 +1,283 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.cloud.audit; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; +import "google/rpc/context/attribute_context.proto"; +import "google/rpc/status.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/cloud/audit;audit"; +option java_multiple_files = true; +option java_outer_classname = "AuditLogProto"; +option java_package = "com.google.cloud.audit"; + +// Common audit log format for Google Cloud Platform API operations. +message AuditLog { + // The name of the API service performing the operation. For example, + // `"compute.googleapis.com"`. + string service_name = 7; + + // The name of the service method or operation. + // For API calls, this should be the name of the API method. + // For example, + // + // "google.cloud.bigquery.v2.TableService.InsertTable" + // "google.logging.v2.ConfigServiceV2.CreateSink" + string method_name = 8; + + // The resource or collection that is the target of the operation. + // The name is a scheme-less URI, not including the API service name. + // For example: + // + // "projects/PROJECT_ID/zones/us-central1-a/instances" + // "projects/PROJECT_ID/datasets/DATASET_ID" + string resource_name = 11; + + // The resource location information. + ResourceLocation resource_location = 20; + + // The resource's original state before mutation. Present only for + // operations which have successfully modified the targeted resource(s). + // In general, this field should contain all changed fields, except those + // that are already been included in `request`, `response`, `metadata` or + // `service_data` fields. + // When the JSON object represented here has a proto equivalent, + // the proto name will be indicated in the `@type` property. + google.protobuf.Struct resource_original_state = 19; + + // The number of items returned from a List or Query API method, + // if applicable. + int64 num_response_items = 12; + + // The status of the overall operation. + google.rpc.Status status = 2; + + // Authentication information. + AuthenticationInfo authentication_info = 3; + + // Authorization information. If there are multiple + // resources or permissions involved, then there is + // one AuthorizationInfo element for each {resource, permission} tuple. + repeated AuthorizationInfo authorization_info = 9; + + // Metadata about the operation. + RequestMetadata request_metadata = 4; + + // The operation request. This may not include all request parameters, + // such as those that are too large, privacy-sensitive, or duplicated + // elsewhere in the log record. + // It should never include user-generated data, such as file contents. + // When the JSON object represented here has a proto equivalent, the proto + // name will be indicated in the `@type` property. + google.protobuf.Struct request = 16; + + // The operation response. This may not include all response elements, + // such as those that are too large, privacy-sensitive, or duplicated + // elsewhere in the log record. + // It should never include user-generated data, such as file contents. + // When the JSON object represented here has a proto equivalent, the proto + // name will be indicated in the `@type` property. + google.protobuf.Struct response = 17; + + // Other service-specific data about the request, response, and other + // information associated with the current audited event. + google.protobuf.Struct metadata = 18; + + // Deprecated. Use the `metadata` field instead. + // Other service-specific data about the request, response, and other + // activities. + google.protobuf.Any service_data = 15 [deprecated = true]; +} + +// Authentication information for the operation. +message AuthenticationInfo { + // The email address of the authenticated user (or service account on behalf + // of third party principal) making the request. For third party identity + // callers, the `principal_subject` field is populated instead of this field. + // For privacy reasons, the principal email address is sometimes redacted. + // For more information, see + // https://cloud.google.com/logging/docs/audit#user-id. + string principal_email = 1; + + // The authority selector specified by the requestor, if any. + // It is not guaranteed that the principal was allowed to use this authority. + string authority_selector = 2; + + // The third party identification (if any) of the authenticated user making + // the request. + // When the JSON object represented here has a proto equivalent, the proto + // name will be indicated in the `@type` property. + google.protobuf.Struct third_party_principal = 4; + + // The name of the service account key used to create or exchange + // credentials for authenticating the service account making the request. + // This is a scheme-less URI full resource name. For example: + // + // "//iam.googleapis.com/projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT}/keys/{key}" + string service_account_key_name = 5; + + // Identity delegation history of an authenticated service account that makes + // the request. It contains information on the real authorities that try to + // access GCP resources by delegating on a service account. When multiple + // authorities present, they are guaranteed to be sorted based on the original + // ordering of the identity delegation events. + repeated ServiceAccountDelegationInfo service_account_delegation_info = 6; + + // String representation of identity of requesting party. + // Populated for both first and third party identities. + string principal_subject = 8; +} + +// Authorization information for the operation. +message AuthorizationInfo { + // The resource being accessed, as a REST-style or cloud resource string. + // For example: + // + // bigquery.googleapis.com/projects/PROJECTID/datasets/DATASETID + // or + // projects/PROJECTID/datasets/DATASETID + string resource = 1; + + // The required IAM permission. + string permission = 2; + + // Whether or not authorization for `resource` and `permission` + // was granted. + bool granted = 3; + + // Resource attributes used in IAM condition evaluation. This field contains + // resource attributes like resource type and resource name. + // + // To get the whole view of the attributes used in IAM + // condition evaluation, the user must also look into + // `AuditLog.request_metadata.request_attributes`. + google.rpc.context.AttributeContext.Resource resource_attributes = 5; +} + +// Metadata about the request. +message RequestMetadata { + // The IP address of the caller. + // For caller from internet, this will be public IPv4 or IPv6 address. + // For caller from a Compute Engine VM with external IP address, this + // will be the VM's external IP address. For caller from a Compute + // Engine VM without external IP address, if the VM is in the same + // organization (or project) as the accessed resource, `caller_ip` will + // be the VM's internal IPv4 address, otherwise the `caller_ip` will be + // redacted to "gce-internal-ip". + // See https://cloud.google.com/compute/docs/vpc/ for more information. + string caller_ip = 1; + + // The user agent of the caller. + // This information is not authenticated and should be treated accordingly. + // For example: + // + // + `google-api-python-client/1.4.0`: + // The request was made by the Google API client for Python. + // + `Cloud SDK Command Line Tool apitools-client/1.0 gcloud/0.9.62`: + // The request was made by the Google Cloud SDK CLI (gcloud). + // + `AppEngine-Google; (+http://code.google.com/appengine; appid: + // s~my-project`: + // The request was made from the `my-project` App Engine app. + string caller_supplied_user_agent = 2; + + // The network of the caller. + // Set only if the network host project is part of the same GCP organization + // (or project) as the accessed resource. + // See https://cloud.google.com/compute/docs/vpc/ for more information. + // This is a scheme-less URI full resource name. For example: + // + // "//compute.googleapis.com/projects/PROJECT_ID/global/networks/NETWORK_ID" + string caller_network = 3; + + // Request attributes used in IAM condition evaluation. This field contains + // request attributes like request time and access levels associated with + // the request. + // + // + // To get the whole view of the attributes used in IAM + // condition evaluation, the user must also look into + // `AuditLog.authentication_info.resource_attributes`. + google.rpc.context.AttributeContext.Request request_attributes = 7; + + // The destination of a network activity, such as accepting a TCP connection. + // In a multi hop network activity, the destination represents the receiver of + // the last hop. Only two fields are used in this message, Peer.port and + // Peer.ip. These fields are optionally populated by those services utilizing + // the IAM condition feature. + google.rpc.context.AttributeContext.Peer destination_attributes = 8; +} + +// Location information about a resource. +message ResourceLocation { + // The locations of a resource after the execution of the operation. + // Requests to create or delete a location based resource must populate + // the 'current_locations' field and not the 'original_locations' field. + // For example: + // + // "europe-west1-a" + // "us-east1" + // "nam3" + repeated string current_locations = 1; + + // The locations of a resource prior to the execution of the operation. + // Requests that mutate the resource's location must populate both the + // 'original_locations' as well as the 'current_locations' fields. + // For example: + // + // "europe-west1-a" + // "us-east1" + // "nam3" + repeated string original_locations = 2; +} + +// Identity delegation history of an authenticated service account. +message ServiceAccountDelegationInfo { + // First party identity principal. + message FirstPartyPrincipal { + // The email address of a Google account. + string principal_email = 1; + + // Metadata about the service that uses the service account. + google.protobuf.Struct service_metadata = 2; + } + + // Third party identity principal. + message ThirdPartyPrincipal { + // Metadata about third party identity. + google.protobuf.Struct third_party_claims = 1; + } + + // A string representing the principal_subject associated with the identity. + // For most identities, the format will be + // `principal://iam.googleapis.com/{identity pool name}/subject/{subject)` + // except for some GKE identities (GKE_WORKLOAD, FREEFORM, GKE_HUB_WORKLOAD) + // that are still in the legacy format `serviceAccount:{identity pool + // name}[{subject}]` + string principal_subject = 3; + + // Entity that creates credentials for service account and assumes its + // identity for authentication. + oneof Authority { + // First party (Google) identity as the real authority. + FirstPartyPrincipal first_party_principal = 1; + + // Third party identity as the real authority. + ThirdPartyPrincipal third_party_principal = 2; + } +} diff --git a/social-media-service/build/extracted-include-protos/main/google/cloud/extended_operations.proto b/social-media-service/build/extracted-include-protos/main/google/cloud/extended_operations.proto new file mode 100644 index 0000000..1477d2d --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/cloud/extended_operations.proto @@ -0,0 +1,150 @@ +// Copyright 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains custom annotations that are used by GAPIC generators to +// handle Long Running Operation methods (LRO) that are NOT compliant with +// https://google.aip.dev/151. These annotations are public for technical +// reasons only. Please DO NOT USE them in your protos. +syntax = "proto3"; + +package google.cloud; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/extendedops;extendedops"; +option java_multiple_files = true; +option java_outer_classname = "ExtendedOperationsProto"; +option java_package = "com.google.cloud"; +option objc_class_prefix = "GAPI"; + +// FieldOptions to match corresponding fields in the initial request, +// polling request and operation response messages. +// +// Example: +// +// In an API-specific operation message: +// +// message MyOperation { +// string http_error_message = 1 [(operation_field) = ERROR_MESSAGE]; +// int32 http_error_status_code = 2 [(operation_field) = ERROR_CODE]; +// string id = 3 [(operation_field) = NAME]; +// Status status = 4 [(operation_field) = STATUS]; +// } +// +// In a polling request message (the one which is used to poll for an LRO +// status): +// +// message MyPollingRequest { +// string operation = 1 [(operation_response_field) = "id"]; +// string project = 2; +// string region = 3; +// } +// +// In an initial request message (the one which starts an LRO): +// +// message MyInitialRequest { +// string my_project = 2 [(operation_request_field) = "project"]; +// string my_region = 3 [(operation_request_field) = "region"]; +// } +// +extend google.protobuf.FieldOptions { + // A field annotation that maps fields in an API-specific Operation object to + // their standard counterparts in google.longrunning.Operation. See + // OperationResponseMapping enum definition. + OperationResponseMapping operation_field = 1149; + + // A field annotation that maps fields in the initial request message + // (the one which started the LRO) to their counterparts in the polling + // request message. For non-standard LRO, the polling response may be missing + // some of the information needed to make a subsequent polling request. The + // missing information (for example, project or region ID) is contained in the + // fields of the initial request message that this annotation must be applied + // to. The string value of the annotation corresponds to the name of the + // counterpart field in the polling request message that the annotated field's + // value will be copied to. + string operation_request_field = 1150; + + // A field annotation that maps fields in the polling request message to their + // counterparts in the initial and/or polling response message. The initial + // and the polling methods return an API-specific Operation object. Some of + // the fields from that response object must be reused in the subsequent + // request (like operation name/ID) to fully identify the polled operation. + // This annotation must be applied to the fields in the polling request + // message, the string value of the annotation must correspond to the name of + // the counterpart field in the Operation response object whose value will be + // copied to the annotated field. + string operation_response_field = 1151; +} + +// MethodOptions to identify the actual service and method used for operation +// status polling. +// +// Example: +// +// In a method, which starts an LRO: +// +// service MyService { +// rpc Foo(MyInitialRequest) returns (MyOperation) { +// option (operation_service) = "MyPollingService"; +// } +// } +// +// In a polling method: +// +// service MyPollingService { +// rpc Get(MyPollingRequest) returns (MyOperation) { +// option (operation_polling_method) = true; +// } +// } +extend google.protobuf.MethodOptions { + // A method annotation that maps an LRO method (the one which starts an LRO) + // to the service, which will be used to poll for the operation status. The + // annotation must be applied to the method which starts an LRO, the string + // value of the annotation must correspond to the name of the service used to + // poll for the operation status. + string operation_service = 1249; + + // A method annotation that marks methods that can be used for polling + // operation status (e.g. the MyPollingService.Get(MyPollingRequest) method). + bool operation_polling_method = 1250; +} + +// An enum to be used to mark the essential (for polling) fields in an +// API-specific Operation object. A custom Operation object may contain many +// different fields, but only few of them are essential to conduct a successful +// polling process. +enum OperationResponseMapping { + // Do not use. + UNDEFINED = 0; + + // A field in an API-specific (custom) Operation object which carries the same + // meaning as google.longrunning.Operation.name. + NAME = 1; + + // A field in an API-specific (custom) Operation object which carries the same + // meaning as google.longrunning.Operation.done. If the annotated field is of + // an enum type, `annotated_field_name == EnumType.DONE` semantics should be + // equivalent to `Operation.done == true`. If the annotated field is of type + // boolean, then it should follow the same semantics as Operation.done. + // Otherwise, a non-empty value should be treated as `Operation.done == true`. + STATUS = 2; + + // A field in an API-specific (custom) Operation object which carries the same + // meaning as google.longrunning.Operation.error.code. + ERROR_CODE = 3; + + // A field in an API-specific (custom) Operation object which carries the same + // meaning as google.longrunning.Operation.error.message. + ERROR_MESSAGE = 4; +} \ No newline at end of file diff --git a/social-media-service/build/extracted-include-protos/main/google/geo/type/viewport.proto b/social-media-service/build/extracted-include-protos/main/google/geo/type/viewport.proto new file mode 100644 index 0000000..ad5029f --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/geo/type/viewport.proto @@ -0,0 +1,69 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package google.geo.type; + +import "google/type/latlng.proto"; + +option go_package = "google.golang.org/genproto/googleapis/geo/type/viewport;viewport"; +option java_multiple_files = true; +option java_outer_classname = "ViewportProto"; +option java_package = "com.google.geo.type"; +option objc_class_prefix = "GGTP"; + +// A latitude-longitude viewport, represented as two diagonally opposite `low` +// and `high` points. A viewport is considered a closed region, i.e. it includes +// its boundary. The latitude bounds must range between -90 to 90 degrees +// inclusive, and the longitude bounds must range between -180 to 180 degrees +// inclusive. Various cases include: +// +// - If `low` = `high`, the viewport consists of that single point. +// +// - If `low.longitude` > `high.longitude`, the longitude range is inverted +// (the viewport crosses the 180 degree longitude line). +// +// - If `low.longitude` = -180 degrees and `high.longitude` = 180 degrees, +// the viewport includes all longitudes. +// +// - If `low.longitude` = 180 degrees and `high.longitude` = -180 degrees, +// the longitude range is empty. +// +// - If `low.latitude` > `high.latitude`, the latitude range is empty. +// +// Both `low` and `high` must be populated, and the represented box cannot be +// empty (as specified by the definitions above). An empty viewport will result +// in an error. +// +// For example, this viewport fully encloses New York City: +// +// { +// "low": { +// "latitude": 40.477398, +// "longitude": -74.259087 +// }, +// "high": { +// "latitude": 40.91618, +// "longitude": -73.70018 +// } +// } +message Viewport { + // Required. The low point of the viewport. + google.type.LatLng low = 1; + + // Required. The high point of the viewport. + google.type.LatLng high = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/logging/type/http_request.proto b/social-media-service/build/extracted-include-protos/main/google/logging/type/http_request.proto new file mode 100644 index 0000000..b878d60 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/logging/type/http_request.proto @@ -0,0 +1,95 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.logging.type; + +import "google/protobuf/duration.proto"; + +option csharp_namespace = "Google.Cloud.Logging.Type"; +option go_package = "google.golang.org/genproto/googleapis/logging/type;ltype"; +option java_multiple_files = true; +option java_outer_classname = "HttpRequestProto"; +option java_package = "com.google.logging.type"; +option php_namespace = "Google\\Cloud\\Logging\\Type"; +option ruby_package = "Google::Cloud::Logging::Type"; + +// A common proto for logging HTTP requests. Only contains semantics +// defined by the HTTP specification. Product-specific logging +// information MUST be defined in a separate message. +message HttpRequest { + // The request method. Examples: `"GET"`, `"HEAD"`, `"PUT"`, `"POST"`. + string request_method = 1; + + // The scheme (http, https), the host name, the path and the query + // portion of the URL that was requested. + // Example: `"http://example.com/some/info?color=red"`. + string request_url = 2; + + // The size of the HTTP request message in bytes, including the request + // headers and the request body. + int64 request_size = 3; + + // The response code indicating the status of response. + // Examples: 200, 404. + int32 status = 4; + + // The size of the HTTP response message sent back to the client, in bytes, + // including the response headers and the response body. + int64 response_size = 5; + + // The user agent sent by the client. Example: + // `"Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET + // CLR 1.0.3705)"`. + string user_agent = 6; + + // The IP address (IPv4 or IPv6) of the client that issued the HTTP + // request. This field can include port information. Examples: + // `"192.168.1.1"`, `"10.0.0.1:80"`, `"FE80::0202:B3FF:FE1E:8329"`. + string remote_ip = 7; + + // The IP address (IPv4 or IPv6) of the origin server that the request was + // sent to. This field can include port information. Examples: + // `"192.168.1.1"`, `"10.0.0.1:80"`, `"FE80::0202:B3FF:FE1E:8329"`. + string server_ip = 13; + + // The referer URL of the request, as defined in + // [HTTP/1.1 Header Field + // Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html). + string referer = 8; + + // The request processing latency on the server, from the time the request was + // received until the response was sent. + google.protobuf.Duration latency = 14; + + // Whether or not a cache lookup was attempted. + bool cache_lookup = 11; + + // Whether or not an entity was served from cache + // (with or without validation). + bool cache_hit = 9; + + // Whether or not the response was validated with the origin server before + // being served from cache. This field is only meaningful if `cache_hit` is + // True. + bool cache_validated_with_origin_server = 10; + + // The number of HTTP response bytes inserted into cache. Set only when a + // cache fill was attempted. + int64 cache_fill_bytes = 12; + + // Protocol used for the request. Examples: "HTTP/1.1", "HTTP/2", "websocket" + string protocol = 15; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/logging/type/log_severity.proto b/social-media-service/build/extracted-include-protos/main/google/logging/type/log_severity.proto new file mode 100644 index 0000000..bed7193 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/logging/type/log_severity.proto @@ -0,0 +1,71 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.logging.type; + +option csharp_namespace = "Google.Cloud.Logging.Type"; +option go_package = "google.golang.org/genproto/googleapis/logging/type;ltype"; +option java_multiple_files = true; +option java_outer_classname = "LogSeverityProto"; +option java_package = "com.google.logging.type"; +option objc_class_prefix = "GLOG"; +option php_namespace = "Google\\Cloud\\Logging\\Type"; +option ruby_package = "Google::Cloud::Logging::Type"; + +// The severity of the event described in a log entry, expressed as one of the +// standard severity levels listed below. For your reference, the levels are +// assigned the listed numeric values. The effect of using numeric values other +// than those listed is undefined. +// +// You can filter for log entries by severity. For example, the following +// filter expression will match log entries with severities `INFO`, `NOTICE`, +// and `WARNING`: +// +// severity > DEBUG AND severity <= WARNING +// +// If you are writing log entries, you should map other severity encodings to +// one of these standard levels. For example, you might map all of Java's FINE, +// FINER, and FINEST levels to `LogSeverity.DEBUG`. You can preserve the +// original severity level in the log entry payload if you wish. +enum LogSeverity { + // (0) The log entry has no assigned severity level. + DEFAULT = 0; + + // (100) Debug or trace information. + DEBUG = 100; + + // (200) Routine information, such as ongoing status or performance. + INFO = 200; + + // (300) Normal but significant events, such as start up, shut down, or + // a configuration change. + NOTICE = 300; + + // (400) Warning events might cause problems. + WARNING = 400; + + // (500) Error events are likely to cause problems. + ERROR = 500; + + // (600) Critical events cause more severe problems or outages. + CRITICAL = 600; + + // (700) A person must take an action immediately. + ALERT = 700; + + // (800) One or more systems are unusable. + EMERGENCY = 800; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/longrunning/operations.proto b/social-media-service/build/extracted-include-protos/main/google/longrunning/operations.proto new file mode 100644 index 0000000..c1fdc6f --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/longrunning/operations.proto @@ -0,0 +1,247 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.longrunning; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/empty.proto"; +import "google/rpc/status.proto"; +import "google/protobuf/descriptor.proto"; + +option cc_enable_arenas = true; +option csharp_namespace = "Google.LongRunning"; +option go_package = "google.golang.org/genproto/googleapis/longrunning;longrunning"; +option java_multiple_files = true; +option java_outer_classname = "OperationsProto"; +option java_package = "com.google.longrunning"; +option php_namespace = "Google\\LongRunning"; + +extend google.protobuf.MethodOptions { + // Additional information regarding long-running operations. + // In particular, this specifies the types that are returned from + // long-running operations. + // + // Required for methods that return `google.longrunning.Operation`; invalid + // otherwise. + google.longrunning.OperationInfo operation_info = 1049; +} + +// Manages long-running operations with an API service. +// +// When an API method normally takes long time to complete, it can be designed +// to return [Operation][google.longrunning.Operation] to the client, and the client can use this +// interface to receive the real response asynchronously by polling the +// operation resource, or pass the operation resource to another API (such as +// Google Cloud Pub/Sub API) to receive the response. Any API service that +// returns long-running operations should implement the `Operations` interface +// so developers can have a consistent client experience. +service Operations { + option (google.api.default_host) = "longrunning.googleapis.com"; + + // Lists operations that match the specified filter in the request. If the + // server doesn't support this method, it returns `UNIMPLEMENTED`. + // + // NOTE: the `name` binding allows API services to override the binding + // to use different resource name schemes, such as `users/*/operations`. To + // override the binding, API services can add a binding such as + // `"/v1/{name=users/*}/operations"` to their service configuration. + // For backwards compatibility, the default name includes the operations + // collection id, however overriding users must ensure the name binding + // is the parent resource, without the operations collection id. + rpc ListOperations(ListOperationsRequest) returns (ListOperationsResponse) { + option (google.api.http) = { + get: "/v1/{name=operations}" + }; + option (google.api.method_signature) = "name,filter"; + } + + // Gets the latest state of a long-running operation. Clients can use this + // method to poll the operation result at intervals as recommended by the API + // service. + rpc GetOperation(GetOperationRequest) returns (Operation) { + option (google.api.http) = { + get: "/v1/{name=operations/**}" + }; + option (google.api.method_signature) = "name"; + } + + // Deletes a long-running operation. This method indicates that the client is + // no longer interested in the operation result. It does not cancel the + // operation. If the server doesn't support this method, it returns + // `google.rpc.Code.UNIMPLEMENTED`. + rpc DeleteOperation(DeleteOperationRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=operations/**}" + }; + option (google.api.method_signature) = "name"; + } + + // Starts asynchronous cancellation on a long-running operation. The server + // makes a best effort to cancel the operation, but success is not + // guaranteed. If the server doesn't support this method, it returns + // `google.rpc.Code.UNIMPLEMENTED`. Clients can use + // [Operations.GetOperation][google.longrunning.Operations.GetOperation] or + // other methods to check whether the cancellation succeeded or whether the + // operation completed despite cancellation. On successful cancellation, + // the operation is not deleted; instead, it becomes an operation with + // an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, + // corresponding to `Code.CANCELLED`. + rpc CancelOperation(CancelOperationRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/{name=operations/**}:cancel" + body: "*" + }; + option (google.api.method_signature) = "name"; + } + + // Waits until the specified long-running operation is done or reaches at most + // a specified timeout, returning the latest state. If the operation is + // already done, the latest state is immediately returned. If the timeout + // specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + // timeout is used. If the server does not support this method, it returns + // `google.rpc.Code.UNIMPLEMENTED`. + // Note that this method is on a best-effort basis. It may return the latest + // state before the specified timeout (including immediately), meaning even an + // immediate response is no guarantee that the operation is done. + rpc WaitOperation(WaitOperationRequest) returns (Operation) { + } +} + +// This resource represents a long-running operation that is the result of a +// network API call. +message Operation { + // The server-assigned name, which is only unique within the same service that + // originally returns it. If you use the default HTTP mapping, the + // `name` should be a resource name ending with `operations/{unique_id}`. + string name = 1; + + // Service-specific metadata associated with the operation. It typically + // contains progress information and common metadata such as create time. + // Some services might not provide such metadata. Any method that returns a + // long-running operation should document the metadata type, if any. + google.protobuf.Any metadata = 2; + + // If the value is `false`, it means the operation is still in progress. + // If `true`, the operation is completed, and either `error` or `response` is + // available. + bool done = 3; + + // The operation result, which can be either an `error` or a valid `response`. + // If `done` == `false`, neither `error` nor `response` is set. + // If `done` == `true`, exactly one of `error` or `response` is set. + oneof result { + // The error result of the operation in case of failure or cancellation. + google.rpc.Status error = 4; + + // The normal response of the operation in case of success. If the original + // method returns no data on success, such as `Delete`, the response is + // `google.protobuf.Empty`. If the original method is standard + // `Get`/`Create`/`Update`, the response should be the resource. For other + // methods, the response should have the type `XxxResponse`, where `Xxx` + // is the original method name. For example, if the original method name + // is `TakeSnapshot()`, the inferred response type is + // `TakeSnapshotResponse`. + google.protobuf.Any response = 5; + } +} + +// The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation]. +message GetOperationRequest { + // The name of the operation resource. + string name = 1; +} + +// The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. +message ListOperationsRequest { + // The name of the operation's parent resource. + string name = 4; + + // The standard list filter. + string filter = 1; + + // The standard list page size. + int32 page_size = 2; + + // The standard list page token. + string page_token = 3; +} + +// The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. +message ListOperationsResponse { + // A list of operations that matches the specified filter in the request. + repeated Operation operations = 1; + + // The standard List next-page token. + string next_page_token = 2; +} + +// The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]. +message CancelOperationRequest { + // The name of the operation resource to be cancelled. + string name = 1; +} + +// The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation]. +message DeleteOperationRequest { + // The name of the operation resource to be deleted. + string name = 1; +} + +// The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. +message WaitOperationRequest { + // The name of the operation resource to wait on. + string name = 1; + + // The maximum duration to wait before timing out. If left blank, the wait + // will be at most the time permitted by the underlying HTTP/RPC protocol. + // If RPC context deadline is also specified, the shorter one will be used. + google.protobuf.Duration timeout = 2; +} + +// A message representing the message types used by a long-running operation. +// +// Example: +// +// rpc LongRunningRecognize(LongRunningRecognizeRequest) +// returns (google.longrunning.Operation) { +// option (google.longrunning.operation_info) = { +// response_type: "LongRunningRecognizeResponse" +// metadata_type: "LongRunningRecognizeMetadata" +// }; +// } +message OperationInfo { + // Required. The message name of the primary return type for this + // long-running operation. + // This type will be used to deserialize the LRO's response. + // + // If the response is in a different package from the rpc, a fully-qualified + // message name must be used (e.g. `google.protobuf.Struct`). + // + // Note: Altering this value constitutes a breaking change. + string response_type = 1; + + // Required. The message name of the metadata type for this long-running + // operation. + // + // If the response is in a different package from the rpc, a fully-qualified + // message name must be used (e.g. `google.protobuf.Struct`). + // + // Note: Altering this value constitutes a breaking change. + string metadata_type = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/any.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/any.proto new file mode 100644 index 0000000..e2c2042 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/any.proto @@ -0,0 +1,158 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/anypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/api.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/api.proto new file mode 100644 index 0000000..3d598fc --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/api.proto @@ -0,0 +1,208 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/source_context.proto"; +import "google/protobuf/type.proto"; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "ApiProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/apipb"; + +// Api is a light-weight descriptor for an API Interface. +// +// Interfaces are also described as "protocol buffer services" in some contexts, +// such as by the "service" keyword in a .proto file, but they are different +// from API Services, which represent a concrete implementation of an interface +// as opposed to simply a description of methods and bindings. They are also +// sometimes simply referred to as "APIs" in other contexts, such as the name of +// this message itself. See https://cloud.google.com/apis/design/glossary for +// detailed terminology. +message Api { + // The fully qualified name of this interface, including package name + // followed by the interface's simple name. + string name = 1; + + // The methods of this interface, in unspecified order. + repeated Method methods = 2; + + // Any metadata attached to the interface. + repeated Option options = 3; + + // A version string for this interface. If specified, must have the form + // `major-version.minor-version`, as in `1.10`. If the minor version is + // omitted, it defaults to zero. If the entire version field is empty, the + // major version is derived from the package name, as outlined below. If the + // field is not empty, the version in the package name will be verified to be + // consistent with what is provided here. + // + // The versioning schema uses [semantic + // versioning](http://semver.org) where the major version number + // indicates a breaking change and the minor version an additive, + // non-breaking change. Both version numbers are signals to users + // what to expect from different versions, and should be carefully + // chosen based on the product plan. + // + // The major version is also reflected in the package name of the + // interface, which must end in `v`, as in + // `google.feature.v1`. For major versions 0 and 1, the suffix can + // be omitted. Zero major versions must only be used for + // experimental, non-GA interfaces. + // + // + string version = 4; + + // Source context for the protocol buffer service represented by this + // message. + SourceContext source_context = 5; + + // Included interfaces. See [Mixin][]. + repeated Mixin mixins = 6; + + // The source syntax of the service. + Syntax syntax = 7; +} + +// Method represents a method of an API interface. +message Method { + // The simple name of this method. + string name = 1; + + // A URL of the input message type. + string request_type_url = 2; + + // If true, the request is streamed. + bool request_streaming = 3; + + // The URL of the output message type. + string response_type_url = 4; + + // If true, the response is streamed. + bool response_streaming = 5; + + // Any metadata attached to the method. + repeated Option options = 6; + + // The source syntax of this method. + Syntax syntax = 7; +} + +// Declares an API Interface to be included in this interface. The including +// interface must redeclare all the methods from the included interface, but +// documentation and options are inherited as follows: +// +// - If after comment and whitespace stripping, the documentation +// string of the redeclared method is empty, it will be inherited +// from the original method. +// +// - Each annotation belonging to the service config (http, +// visibility) which is not set in the redeclared method will be +// inherited. +// +// - If an http annotation is inherited, the path pattern will be +// modified as follows. Any version prefix will be replaced by the +// version of the including interface plus the [root][] path if +// specified. +// +// Example of a simple mixin: +// +// package google.acl.v1; +// service AccessControl { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v1/{resource=**}:getAcl"; +// } +// } +// +// package google.storage.v2; +// service Storage { +// rpc GetAcl(GetAclRequest) returns (Acl); +// +// // Get a data record. +// rpc GetData(GetDataRequest) returns (Data) { +// option (google.api.http).get = "/v2/{resource=**}"; +// } +// } +// +// Example of a mixin configuration: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// +// The mixin construct implies that all methods in `AccessControl` are +// also declared with same name and request/response types in +// `Storage`. A documentation generator or annotation processor will +// see the effective `Storage.GetAcl` method after inheriting +// documentation and annotations as follows: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/{resource=**}:getAcl"; +// } +// ... +// } +// +// Note how the version in the path pattern changed from `v1` to `v2`. +// +// If the `root` field in the mixin is specified, it should be a +// relative path under which inherited HTTP paths are placed. Example: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// root: acls +// +// This implies the following inherited HTTP annotation: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; +// } +// ... +// } +message Mixin { + // The fully qualified name of the interface which is included. + string name = 1; + + // If non-empty specifies a path under which inherited HTTP paths + // are rooted. + string root = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/compiler/plugin.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/compiler/plugin.proto new file mode 100644 index 0000000..9242aac --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/compiler/plugin.proto @@ -0,0 +1,183 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to +// change. +// +// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is +// just a program that reads a CodeGeneratorRequest from stdin and writes a +// CodeGeneratorResponse to stdout. +// +// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead +// of dealing with the raw protocol defined here. +// +// A plugin executable needs only to be placed somewhere in the path. The +// plugin should be named "protoc-gen-$NAME", and will then be used when the +// flag "--${NAME}_out" is passed to protoc. + +syntax = "proto2"; + +package google.protobuf.compiler; +option java_package = "com.google.protobuf.compiler"; +option java_outer_classname = "PluginProtos"; + +option go_package = "google.golang.org/protobuf/types/pluginpb"; + +import "google/protobuf/descriptor.proto"; + +// The version number of protocol compiler. +message Version { + optional int32 major = 1; + optional int32 minor = 2; + optional int32 patch = 3; + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + optional string suffix = 4; +} + +// An encoded CodeGeneratorRequest is written to the plugin's stdin. +message CodeGeneratorRequest { + // The .proto files that were explicitly listed on the command-line. The + // code generator should generate code only for these files. Each file's + // descriptor will be included in proto_file, below. + repeated string file_to_generate = 1; + + // The generator parameter passed on the command-line. + optional string parameter = 2; + + // FileDescriptorProtos for all files in files_to_generate and everything + // they import. The files will appear in topological order, so each file + // appears before any file that imports it. + // + // protoc guarantees that all proto_files will be written after + // the fields above, even though this is not technically guaranteed by the + // protobuf wire format. This theoretically could allow a plugin to stream + // in the FileDescriptorProtos and handle them one by one rather than read + // the entire set into memory at once. However, as of this writing, this + // is not similarly optimized on protoc's end -- it will store all fields in + // memory at once before sending them to the plugin. + // + // Type names of fields and extensions in the FileDescriptorProto are always + // fully qualified. + repeated FileDescriptorProto proto_file = 15; + + // The version number of protocol compiler. + optional Version compiler_version = 3; + +} + +// The plugin writes an encoded CodeGeneratorResponse to stdout. +message CodeGeneratorResponse { + // Error message. If non-empty, code generation failed. The plugin process + // should exit with status code zero even if it reports an error in this way. + // + // This should be used to indicate errors in .proto files which prevent the + // code generator from generating correct code. Errors which indicate a + // problem in protoc itself -- such as the input CodeGeneratorRequest being + // unparseable -- should be reported by writing a message to stderr and + // exiting with a non-zero status code. + optional string error = 1; + + // A bitmask of supported features that the code generator supports. + // This is a bitwise "or" of values from the Feature enum. + optional uint64 supported_features = 2; + + // Sync with code_generator.h. + enum Feature { + FEATURE_NONE = 0; + FEATURE_PROTO3_OPTIONAL = 1; + } + + // Represents a single generated file. + message File { + // The file name, relative to the output directory. The name must not + // contain "." or ".." components and must be relative, not be absolute (so, + // the file cannot lie outside the output directory). "/" must be used as + // the path separator, not "\". + // + // If the name is omitted, the content will be appended to the previous + // file. This allows the generator to break large files into small chunks, + // and allows the generated text to be streamed back to protoc so that large + // files need not reside completely in memory at one time. Note that as of + // this writing protoc does not optimize for this -- it will read the entire + // CodeGeneratorResponse before writing files to disk. + optional string name = 1; + + // If non-empty, indicates that the named file should already exist, and the + // content here is to be inserted into that file at a defined insertion + // point. This feature allows a code generator to extend the output + // produced by another code generator. The original generator may provide + // insertion points by placing special annotations in the file that look + // like: + // @@protoc_insertion_point(NAME) + // The annotation can have arbitrary text before and after it on the line, + // which allows it to be placed in a comment. NAME should be replaced with + // an identifier naming the point -- this is what other generators will use + // as the insertion_point. Code inserted at this point will be placed + // immediately above the line containing the insertion point (thus multiple + // insertions to the same point will come out in the order they were added). + // The double-@ is intended to make it unlikely that the generated code + // could contain things that look like insertion points by accident. + // + // For example, the C++ code generator places the following line in the + // .pb.h files that it generates: + // // @@protoc_insertion_point(namespace_scope) + // This line appears within the scope of the file's package namespace, but + // outside of any particular class. Another plugin can then specify the + // insertion_point "namespace_scope" to generate additional classes or + // other declarations that should be placed in this scope. + // + // Note that if the line containing the insertion point begins with + // whitespace, the same whitespace will be added to every line of the + // inserted text. This is useful for languages like Python, where + // indentation matters. In these languages, the insertion point comment + // should be indented the same amount as any inserted code will need to be + // in order to work correctly in that context. + // + // The code generator that generates the initial file and the one which + // inserts into it must both run as part of a single invocation of protoc. + // Code generators are executed in the order in which they appear on the + // command line. + // + // If |insertion_point| is present, |name| must also be present. + optional string insertion_point = 2; + + // The file contents. + optional string content = 15; + + // Information describing the file content being inserted. If an insertion + // point is used, this information will be appropriately offset and inserted + // into the code generation metadata for the generated files. + optional GeneratedCodeInfo generated_code_info = 16; + } + repeated File file = 15; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/descriptor.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/descriptor.proto new file mode 100644 index 0000000..f8eb216 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/descriptor.proto @@ -0,0 +1,921 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + + +syntax = "proto2"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; +option csharp_namespace = "Google.Protobuf.Reflection"; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2" and "proto3". + optional string syntax = 12; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + + optional ExtensionRangeOptions options = 3; + } + repeated ExtensionRange extension_range = 5; + + repeated OneofDescriptorProto oneof_decl = 8; + + optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; +} + +message ExtensionRangeOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + // Tag-delimited aggregate. + // Group type is deprecated and not supported in proto3. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + } + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + } + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; + + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must be belong to a oneof to + // signal to old proto3 clients that presence is tracked for this field. This + // oneof is known as a "synthetic" oneof, and this field must be its sole + // member (each proto3 optional field gets its own synthetic oneof). Synthetic + // oneofs exist in the descriptor only, and do not generate any API. Synthetic + // oneofs must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + optional bool proto3_optional = 17; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default = false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default = false]; +} + + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + + // Controls the name of the wrapper Java class generated for the .proto file. + // That class will always contain the .proto file's getDescriptor() method as + // well as any top-level extensions defined in the .proto file. + // If java_multiple_files is disabled, then all the other classes from the + // .proto file will be nested inside the single wrapper outer class. + optional string java_outer_classname = 8; + + // If enabled, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the wrapper class + // named by java_outer_classname. However, the wrapper class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default = false]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // If set true, then the Java2 code generator will generate code that + // throws an exception whenever an attempt is made to assign a non-UTF-8 + // byte sequence to a string field. + // Message reflection will do the same. + // However, an extension field still accepts non-UTF-8 byte sequences. + // This option has no effect on when used with the lite runtime. + optional bool java_string_check_utf8 = 27 [default = false]; + + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default = SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + + + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + optional bool php_generic_services = 42 [default = false]; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default = false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default = true]; + + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be + // used for determining the namespace. + optional string php_metadata_namespace = 44; + + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + optional string ruby_package = 45; + + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default = false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default = false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default = false]; + + reserved 4, 5, 6; + + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementations still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outer message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + // + // As of 2021, lazy does no correctness checks on the byte stream during + // parsing. This may lead to crashes if and when an invalid byte stream is + // finally parsed upon access. + // + // TODO(b/211906113): Enable validation on lazy fields. + optional bool lazy = 5 [default = false]; + + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default = false]; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default = false]; + + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype +} + +message OneofOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default = false]; + + reserved 5; // javanano_as_lite + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default = false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = 34 + [default = IDEMPOTENCY_UNKNOWN]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents + // "foo.(bar.baz).moo". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendant. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition occurs. + // For example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed = true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed = true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to moo. + // // + // // Another line attached to moo. + // optional double moo = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to moo or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed = true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified offset. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + } +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/duration.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/duration.proto new file mode 100644 index 0000000..81c3e36 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/duration.proto @@ -0,0 +1,116 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/durationpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (duration.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +message Duration { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/empty.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/empty.proto new file mode 100644 index 0000000..2227462 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/empty.proto @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/emptypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +// +message Empty {} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/field_mask.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/field_mask.proto new file mode 100644 index 0000000..6b5104f --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/field_mask.proto @@ -0,0 +1,245 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "FieldMaskProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; +option cc_enable_arenas = true; + +// `FieldMask` represents a set of symbolic field paths, for example: +// +// paths: "f.a" +// paths: "f.b.d" +// +// Here `f` represents a field in some root message, `a` and `b` +// fields in the message found in `f`, and `d` a field found in the +// message in `f.b`. +// +// Field masks are used to specify a subset of fields that should be +// returned by a get operation or modified by an update operation. +// Field masks also have a custom JSON encoding (see below). +// +// # Field Masks in Projections +// +// When used in the context of a projection, a response message or +// sub-message is filtered by the API to only contain those fields as +// specified in the mask. For example, if the mask in the previous +// example is applied to a response message as follows: +// +// f { +// a : 22 +// b { +// d : 1 +// x : 2 +// } +// y : 13 +// } +// z: 8 +// +// The result will not contain specific values for fields x,y and z +// (their value will be set to the default, and omitted in proto text +// output): +// +// +// f { +// a : 22 +// b { +// d : 1 +// } +// } +// +// A repeated field is not allowed except at the last position of a +// paths string. +// +// If a FieldMask object is not present in a get operation, the +// operation applies to all fields (as if a FieldMask of all fields +// had been specified). +// +// Note that a field mask does not necessarily apply to the +// top-level response message. In case of a REST get operation, the +// field mask applies directly to the response, but in case of a REST +// list operation, the mask instead applies to each individual message +// in the returned resource list. In case of a REST custom method, +// other definitions may be used. Where the mask applies will be +// clearly documented together with its declaration in the API. In +// any case, the effect on the returned resource/resources is required +// behavior for APIs. +// +// # Field Masks in Update Operations +// +// A field mask in update operations specifies which fields of the +// targeted resource are going to be updated. The API is required +// to only change the values of the fields as specified in the mask +// and leave the others untouched. If a resource is passed in to +// describe the updated values, the API ignores the values of all +// fields not covered by the mask. +// +// If a repeated field is specified for an update operation, new values will +// be appended to the existing repeated field in the target resource. Note that +// a repeated field is only allowed in the last position of a `paths` string. +// +// If a sub-message is specified in the last position of the field mask for an +// update operation, then new value will be merged into the existing sub-message +// in the target resource. +// +// For example, given the target message: +// +// f { +// b { +// d: 1 +// x: 2 +// } +// c: [1] +// } +// +// And an update message: +// +// f { +// b { +// d: 10 +// } +// c: [2] +// } +// +// then if the field mask is: +// +// paths: ["f.b", "f.c"] +// +// then the result will be: +// +// f { +// b { +// d: 10 +// x: 2 +// } +// c: [1, 2] +// } +// +// An implementation may provide options to override this default behavior for +// repeated and message fields. +// +// In order to reset a field's value to the default, the field must +// be in the mask and set to the default value in the provided resource. +// Hence, in order to reset all fields of a resource, provide a default +// instance of the resource and set all fields in the mask, or do +// not provide a mask as described below. +// +// If a field mask is not present on update, the operation applies to +// all fields (as if a field mask of all fields has been specified). +// Note that in the presence of schema evolution, this may mean that +// fields the client does not know and has therefore not filled into +// the request will be reset to their default. If this is unwanted +// behavior, a specific service may require a client to always specify +// a field mask, producing an error if not. +// +// As with get operations, the location of the resource which +// describes the updated values in the request message depends on the +// operation kind. In any case, the effect of the field mask is +// required to be honored by the API. +// +// ## Considerations for HTTP REST +// +// The HTTP kind of an update operation which uses a field mask must +// be set to PATCH instead of PUT in order to satisfy HTTP semantics +// (PUT must only be used for full updates). +// +// # JSON Encoding of Field Masks +// +// In JSON, a field mask is encoded as a single string where paths are +// separated by a comma. Fields name in each path are converted +// to/from lower-camel naming conventions. +// +// As an example, consider the following message declarations: +// +// message Profile { +// User user = 1; +// Photo photo = 2; +// } +// message User { +// string display_name = 1; +// string address = 2; +// } +// +// In proto a field mask for `Profile` may look as such: +// +// mask { +// paths: "user.display_name" +// paths: "photo" +// } +// +// In JSON, the same mask is represented as below: +// +// { +// mask: "user.displayName,photo" +// } +// +// # Field Masks and Oneof Fields +// +// Field masks treat fields in oneofs just as regular fields. Consider the +// following message: +// +// message SampleMessage { +// oneof test_oneof { +// string name = 4; +// SubMessage sub_message = 9; +// } +// } +// +// The field mask can be: +// +// mask { +// paths: "name" +// } +// +// Or: +// +// mask { +// paths: "sub_message" +// } +// +// Note that oneof type names ("test_oneof" in this case) cannot be used in +// paths. +// +// ## Field Mask Verification +// +// The implementation of any API method which has a FieldMask type field in the +// request should verify the included field paths, and return an +// `INVALID_ARGUMENT` error if any path is unmappable. +message FieldMask { + // The set of field mask paths. + repeated string paths = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/source_context.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/source_context.proto new file mode 100644 index 0000000..06bfc43 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/source_context.proto @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "SourceContextProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; + +// `SourceContext` represents information about the source of a +// protobuf element, like the file in which it is defined. +message SourceContext { + // The path-qualified name of the .proto file that contained the associated + // protobuf element. For example: `"google/protobuf/source_context.proto"`. + string file_name = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/struct.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/struct.proto new file mode 100644 index 0000000..0ac843c --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/struct.proto @@ -0,0 +1,95 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/structpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "StructProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Struct` represents a structured data value, consisting of fields +// which map to dynamically typed values. In some languages, `Struct` +// might be supported by a native representation. For example, in +// scripting languages like JS a struct is represented as an +// object. The details of that representation are described together +// with the proto support for the language. +// +// The JSON representation for `Struct` is JSON object. +message Struct { + // Unordered map of dynamically typed values. + map fields = 1; +} + +// `Value` represents a dynamically typed value which can be either +// null, a number, a string, a boolean, a recursive struct value, or a +// list of values. A producer of value is expected to set one of these +// variants. Absence of any variant indicates an error. +// +// The JSON representation for `Value` is JSON value. +message Value { + // The kind of value. + oneof kind { + // Represents a null value. + NullValue null_value = 1; + // Represents a double value. + double number_value = 2; + // Represents a string value. + string string_value = 3; + // Represents a boolean value. + bool bool_value = 4; + // Represents a structured value. + Struct struct_value = 5; + // Represents a repeated `Value`. + ListValue list_value = 6; + } +} + +// `NullValue` is a singleton enumeration to represent the null value for the +// `Value` type union. +// +// The JSON representation for `NullValue` is JSON `null`. +enum NullValue { + // Null value. + NULL_VALUE = 0; +} + +// `ListValue` is a wrapper around a repeated field of values. +// +// The JSON representation for `ListValue` is JSON array. +message ListValue { + // Repeated field of dynamically typed values. + repeated Value values = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/timestamp.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/timestamp.proto new file mode 100644 index 0000000..3b2df6d --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/timestamp.proto @@ -0,0 +1,147 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/timestamppb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Timestamp represents a point in time independent of any time zone or local +// calendar, encoded as a count of seconds and fractions of seconds at +// nanosecond resolution. The count is relative to an epoch at UTC midnight on +// January 1, 1970, in the proleptic Gregorian calendar which extends the +// Gregorian calendar backwards to year one. +// +// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +// second table is needed for interpretation, using a [24-hour linear +// smear](https://developers.google.com/time/smear). +// +// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +// restricting to that range, we ensure that we can convert to and from [RFC +// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from Java `Instant.now()`. +// +// Instant now = Instant.now(); +// +// Timestamp timestamp = +// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) +// .setNanos(now.getNano()).build(); +// +// +// Example 6: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required. A proto3 JSON serializer should always use UTC (as indicated by +// "Z") when printing the Timestamp type and a proto3 JSON parser should be +// able to accept both UTC and other timezones (as indicated by an offset). +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard +// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using +// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +// the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D +// ) to obtain a formatter capable of generating timestamps in this format. +// +// +message Timestamp { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/type.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/type.proto new file mode 100644 index 0000000..d3f6a68 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/type.proto @@ -0,0 +1,187 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/any.proto"; +import "google/protobuf/source_context.proto"; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TypeProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/typepb"; + +// A protocol buffer message type. +message Type { + // The fully qualified message name. + string name = 1; + // The list of fields. + repeated Field fields = 2; + // The list of types appearing in `oneof` definitions in this type. + repeated string oneofs = 3; + // The protocol buffer options. + repeated Option options = 4; + // The source context. + SourceContext source_context = 5; + // The source syntax. + Syntax syntax = 6; +} + +// A single field of a message type. +message Field { + // Basic field types. + enum Kind { + // Field type unknown. + TYPE_UNKNOWN = 0; + // Field type double. + TYPE_DOUBLE = 1; + // Field type float. + TYPE_FLOAT = 2; + // Field type int64. + TYPE_INT64 = 3; + // Field type uint64. + TYPE_UINT64 = 4; + // Field type int32. + TYPE_INT32 = 5; + // Field type fixed64. + TYPE_FIXED64 = 6; + // Field type fixed32. + TYPE_FIXED32 = 7; + // Field type bool. + TYPE_BOOL = 8; + // Field type string. + TYPE_STRING = 9; + // Field type group. Proto2 syntax only, and deprecated. + TYPE_GROUP = 10; + // Field type message. + TYPE_MESSAGE = 11; + // Field type bytes. + TYPE_BYTES = 12; + // Field type uint32. + TYPE_UINT32 = 13; + // Field type enum. + TYPE_ENUM = 14; + // Field type sfixed32. + TYPE_SFIXED32 = 15; + // Field type sfixed64. + TYPE_SFIXED64 = 16; + // Field type sint32. + TYPE_SINT32 = 17; + // Field type sint64. + TYPE_SINT64 = 18; + } + + // Whether a field is optional, required, or repeated. + enum Cardinality { + // For fields with unknown cardinality. + CARDINALITY_UNKNOWN = 0; + // For optional fields. + CARDINALITY_OPTIONAL = 1; + // For required fields. Proto2 syntax only. + CARDINALITY_REQUIRED = 2; + // For repeated fields. + CARDINALITY_REPEATED = 3; + } + + // The field type. + Kind kind = 1; + // The field cardinality. + Cardinality cardinality = 2; + // The field number. + int32 number = 3; + // The field name. + string name = 4; + // The field type URL, without the scheme, for message or enumeration + // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. + string type_url = 6; + // The index of the field type in `Type.oneofs`, for message or enumeration + // types. The first type has index 1; zero means the type is not in the list. + int32 oneof_index = 7; + // Whether to use alternative packed wire representation. + bool packed = 8; + // The protocol buffer options. + repeated Option options = 9; + // The field JSON name. + string json_name = 10; + // The string value of the default value of this field. Proto2 syntax only. + string default_value = 11; +} + +// Enum type definition. +message Enum { + // Enum type name. + string name = 1; + // Enum value definitions. + repeated EnumValue enumvalue = 2; + // Protocol buffer options. + repeated Option options = 3; + // The source context. + SourceContext source_context = 4; + // The source syntax. + Syntax syntax = 5; +} + +// Enum value definition. +message EnumValue { + // Enum value name. + string name = 1; + // Enum value number. + int32 number = 2; + // Protocol buffer options. + repeated Option options = 3; +} + +// A protocol buffer option, which can be attached to a message, field, +// enumeration, etc. +message Option { + // The option's name. For protobuf built-in options (options defined in + // descriptor.proto), this is the short name. For example, `"map_entry"`. + // For custom options, it should be the fully-qualified name. For example, + // `"google.api.http"`. + string name = 1; + // The option's value packed in an Any message. If the value is a primitive, + // the corresponding wrapper type defined in google/protobuf/wrappers.proto + // should be used. If the value is an enum, it should be stored as an int32 + // value using the google.protobuf.Int32Value type. + Any value = 2; +} + +// The syntax in which a protocol buffer element is defined. +enum Syntax { + // Syntax `proto2`. + SYNTAX_PROTO2 = 0; + // Syntax `proto3`. + SYNTAX_PROTO3 = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/protobuf/wrappers.proto b/social-media-service/build/extracted-include-protos/main/google/protobuf/wrappers.proto new file mode 100644 index 0000000..d49dd53 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/protobuf/wrappers.proto @@ -0,0 +1,123 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Wrappers for primitive (non-message) types. These types are useful +// for embedding primitives in the `google.protobuf.Any` type and for places +// where we need to distinguish between the absence of a primitive +// typed field and its default value. +// +// These wrappers have no meaningful use within repeated fields as they lack +// the ability to detect presence on individual elements. +// These wrappers have no meaningful use within a map or a oneof since +// individual entries of a map or fields of a oneof can already detect presence. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "WrappersProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// Wrapper message for `double`. +// +// The JSON representation for `DoubleValue` is JSON number. +message DoubleValue { + // The double value. + double value = 1; +} + +// Wrapper message for `float`. +// +// The JSON representation for `FloatValue` is JSON number. +message FloatValue { + // The float value. + float value = 1; +} + +// Wrapper message for `int64`. +// +// The JSON representation for `Int64Value` is JSON string. +message Int64Value { + // The int64 value. + int64 value = 1; +} + +// Wrapper message for `uint64`. +// +// The JSON representation for `UInt64Value` is JSON string. +message UInt64Value { + // The uint64 value. + uint64 value = 1; +} + +// Wrapper message for `int32`. +// +// The JSON representation for `Int32Value` is JSON number. +message Int32Value { + // The int32 value. + int32 value = 1; +} + +// Wrapper message for `uint32`. +// +// The JSON representation for `UInt32Value` is JSON number. +message UInt32Value { + // The uint32 value. + uint32 value = 1; +} + +// Wrapper message for `bool`. +// +// The JSON representation for `BoolValue` is JSON `true` and `false`. +message BoolValue { + // The bool value. + bool value = 1; +} + +// Wrapper message for `string`. +// +// The JSON representation for `StringValue` is JSON string. +message StringValue { + // The string value. + string value = 1; +} + +// Wrapper message for `bytes`. +// +// The JSON representation for `BytesValue` is JSON string. +message BytesValue { + // The bytes value. + bytes value = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/rpc/code.proto b/social-media-service/build/extracted-include-protos/main/google/rpc/code.proto new file mode 100644 index 0000000..98ae0ac --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/rpc/code.proto @@ -0,0 +1,186 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc; + +option go_package = "google.golang.org/genproto/googleapis/rpc/code;code"; +option java_multiple_files = true; +option java_outer_classname = "CodeProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The canonical error codes for gRPC APIs. +// +// +// Sometimes multiple error codes may apply. Services should return +// the most specific error code that applies. For example, prefer +// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. +// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. +enum Code { + // Not an error; returned on success + // + // HTTP Mapping: 200 OK + OK = 0; + + // The operation was cancelled, typically by the caller. + // + // HTTP Mapping: 499 Client Closed Request + CANCELLED = 1; + + // Unknown error. For example, this error may be returned when + // a `Status` value received from another address space belongs to + // an error space that is not known in this address space. Also + // errors raised by APIs that do not return enough error information + // may be converted to this error. + // + // HTTP Mapping: 500 Internal Server Error + UNKNOWN = 2; + + // The client specified an invalid argument. Note that this differs + // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments + // that are problematic regardless of the state of the system + // (e.g., a malformed file name). + // + // HTTP Mapping: 400 Bad Request + INVALID_ARGUMENT = 3; + + // The deadline expired before the operation could complete. For operations + // that change the state of the system, this error may be returned + // even if the operation has completed successfully. For example, a + // successful response from a server could have been delayed long + // enough for the deadline to expire. + // + // HTTP Mapping: 504 Gateway Timeout + DEADLINE_EXCEEDED = 4; + + // Some requested entity (e.g., file or directory) was not found. + // + // Note to server developers: if a request is denied for an entire class + // of users, such as gradual feature rollout or undocumented whitelist, + // `NOT_FOUND` may be used. If a request is denied for some users within + // a class of users, such as user-based access control, `PERMISSION_DENIED` + // must be used. + // + // HTTP Mapping: 404 Not Found + NOT_FOUND = 5; + + // The entity that a client attempted to create (e.g., file or directory) + // already exists. + // + // HTTP Mapping: 409 Conflict + ALREADY_EXISTS = 6; + + // The caller does not have permission to execute the specified + // operation. `PERMISSION_DENIED` must not be used for rejections + // caused by exhausting some resource (use `RESOURCE_EXHAUSTED` + // instead for those errors). `PERMISSION_DENIED` must not be + // used if the caller can not be identified (use `UNAUTHENTICATED` + // instead for those errors). This error code does not imply the + // request is valid or the requested entity exists or satisfies + // other pre-conditions. + // + // HTTP Mapping: 403 Forbidden + PERMISSION_DENIED = 7; + + // The request does not have valid authentication credentials for the + // operation. + // + // HTTP Mapping: 401 Unauthorized + UNAUTHENTICATED = 16; + + // Some resource has been exhausted, perhaps a per-user quota, or + // perhaps the entire file system is out of space. + // + // HTTP Mapping: 429 Too Many Requests + RESOURCE_EXHAUSTED = 8; + + // The operation was rejected because the system is not in a state + // required for the operation's execution. For example, the directory + // to be deleted is non-empty, an rmdir operation is applied to + // a non-directory, etc. + // + // Service implementors can use the following guidelines to decide + // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: + // (a) Use `UNAVAILABLE` if the client can retry just the failing call. + // (b) Use `ABORTED` if the client should retry at a higher level + // (e.g., when a client-specified test-and-set fails, indicating the + // client should restart a read-modify-write sequence). + // (c) Use `FAILED_PRECONDITION` if the client should not retry until + // the system state has been explicitly fixed. E.g., if an "rmdir" + // fails because the directory is non-empty, `FAILED_PRECONDITION` + // should be returned since the client should not retry unless + // the files are deleted from the directory. + // + // HTTP Mapping: 400 Bad Request + FAILED_PRECONDITION = 9; + + // The operation was aborted, typically due to a concurrency issue such as + // a sequencer check failure or transaction abort. + // + // See the guidelines above for deciding between `FAILED_PRECONDITION`, + // `ABORTED`, and `UNAVAILABLE`. + // + // HTTP Mapping: 409 Conflict + ABORTED = 10; + + // The operation was attempted past the valid range. E.g., seeking or + // reading past end-of-file. + // + // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may + // be fixed if the system state changes. For example, a 32-bit file + // system will generate `INVALID_ARGUMENT` if asked to read at an + // offset that is not in the range [0,2^32-1], but it will generate + // `OUT_OF_RANGE` if asked to read from an offset past the current + // file size. + // + // There is a fair bit of overlap between `FAILED_PRECONDITION` and + // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific + // error) when it applies so that callers who are iterating through + // a space can easily look for an `OUT_OF_RANGE` error to detect when + // they are done. + // + // HTTP Mapping: 400 Bad Request + OUT_OF_RANGE = 11; + + // The operation is not implemented or is not supported/enabled in this + // service. + // + // HTTP Mapping: 501 Not Implemented + UNIMPLEMENTED = 12; + + // Internal errors. This means that some invariants expected by the + // underlying system have been broken. This error code is reserved + // for serious errors. + // + // HTTP Mapping: 500 Internal Server Error + INTERNAL = 13; + + // The service is currently unavailable. This is most likely a + // transient condition, which can be corrected by retrying with + // a backoff. Note that it is not always safe to retry + // non-idempotent operations. + // + // See the guidelines above for deciding between `FAILED_PRECONDITION`, + // `ABORTED`, and `UNAVAILABLE`. + // + // HTTP Mapping: 503 Service Unavailable + UNAVAILABLE = 14; + + // Unrecoverable data loss or corruption. + // + // HTTP Mapping: 500 Internal Server Error + DATA_LOSS = 15; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/rpc/context/attribute_context.proto b/social-media-service/build/extracted-include-protos/main/google/rpc/context/attribute_context.proto new file mode 100644 index 0000000..30fe6f2 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/rpc/context/attribute_context.proto @@ -0,0 +1,343 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc.context; + +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/rpc/context/attribute_context;attribute_context"; +option java_multiple_files = true; +option java_outer_classname = "AttributeContextProto"; +option java_package = "com.google.rpc.context"; + +// This message defines the standard attribute vocabulary for Google APIs. +// +// An attribute is a piece of metadata that describes an activity on a network +// service. For example, the size of an HTTP request, or the status code of +// an HTTP response. +// +// Each attribute has a type and a name, which is logically defined as +// a proto message field in `AttributeContext`. The field type becomes the +// attribute type, and the field path becomes the attribute name. For example, +// the attribute `source.ip` maps to field `AttributeContext.source.ip`. +// +// This message definition is guaranteed not to have any wire breaking change. +// So you can use it directly for passing attributes across different systems. +// +// NOTE: Different system may generate different subset of attributes. Please +// verify the system specification before relying on an attribute generated +// a system. +message AttributeContext { + // This message defines attributes for a node that handles a network request. + // The node can be either a service or an application that sends, forwards, + // or receives the request. Service peers should fill in + // `principal` and `labels` as appropriate. + message Peer { + // The IP address of the peer. + string ip = 1; + + // The network port of the peer. + int64 port = 2; + + // The labels associated with the peer. + map labels = 6; + + // The identity of this peer. Similar to `Request.auth.principal`, but + // relative to the peer instead of the request. For example, the + // idenity associated with a load balancer that forwared the request. + string principal = 7; + + // The CLDR country/region code associated with the above IP address. + // If the IP address is private, the `region_code` should reflect the + // physical location where this peer is running. + string region_code = 8; + } + + // This message defines attributes associated with API operations, such as + // a network API request. The terminology is based on the conventions used + // by Google APIs, Istio, and OpenAPI. + message Api { + // The API service name. It is a logical identifier for a networked API, + // such as "pubsub.googleapis.com". The naming syntax depends on the + // API management system being used for handling the request. + string service = 1; + + // The API operation name. For gRPC requests, it is the fully qualified API + // method name, such as "google.pubsub.v1.Publisher.Publish". For OpenAPI + // requests, it is the `operationId`, such as "getPet". + string operation = 2; + + // The API protocol used for sending the request, such as "http", "https", + // "grpc", or "internal". + string protocol = 3; + + // The API version associated with the API operation above, such as "v1" or + // "v1alpha1". + string version = 4; + } + + // This message defines request authentication attributes. Terminology is + // based on the JSON Web Token (JWT) standard, but the terms also + // correlate to concepts in other standards. + message Auth { + // The authenticated principal. Reflects the issuer (`iss`) and subject + // (`sub`) claims within a JWT. The issuer and subject should be `/` + // delimited, with `/` percent-encoded within the subject fragment. For + // Google accounts, the principal format is: + // "https://accounts.google.com/{id}" + string principal = 1; + + // The intended audience(s) for this authentication information. Reflects + // the audience (`aud`) claim within a JWT. The audience + // value(s) depends on the `issuer`, but typically include one or more of + // the following pieces of information: + // + // * The services intended to receive the credential. For example, + // ["https://pubsub.googleapis.com/", "https://storage.googleapis.com/"]. + // * A set of service-based scopes. For example, + // ["https://www.googleapis.com/auth/cloud-platform"]. + // * The client id of an app, such as the Firebase project id for JWTs + // from Firebase Auth. + // + // Consult the documentation for the credential issuer to determine the + // information provided. + repeated string audiences = 2; + + // The authorized presenter of the credential. Reflects the optional + // Authorized Presenter (`azp`) claim within a JWT or the + // OAuth client id. For example, a Google Cloud Platform client id looks + // as follows: "123456789012.apps.googleusercontent.com". + string presenter = 3; + + // Structured claims presented with the credential. JWTs include + // `{key: value}` pairs for standard and private claims. The following + // is a subset of the standard required and optional claims that would + // typically be presented for a Google-based JWT: + // + // {'iss': 'accounts.google.com', + // 'sub': '113289723416554971153', + // 'aud': ['123456789012', 'pubsub.googleapis.com'], + // 'azp': '123456789012.apps.googleusercontent.com', + // 'email': 'jsmith@example.com', + // 'iat': 1353601026, + // 'exp': 1353604926} + // + // SAML assertions are similarly specified, but with an identity provider + // dependent structure. + google.protobuf.Struct claims = 4; + + // A list of access level resource names that allow resources to be + // accessed by authenticated requester. It is part of Secure GCP processing + // for the incoming request. An access level string has the format: + // "//{api_service_name}/accessPolicies/{policy_id}/accessLevels/{short_name}" + // + // Example: + // "//accesscontextmanager.googleapis.com/accessPolicies/MY_POLICY_ID/accessLevels/MY_LEVEL" + repeated string access_levels = 5; + } + + // This message defines attributes for an HTTP request. If the actual + // request is not an HTTP request, the runtime system should try to map + // the actual request to an equivalent HTTP request. + message Request { + // The unique ID for a request, which can be propagated to downstream + // systems. The ID should have low probability of collision + // within a single day for a specific service. + string id = 1; + + // The HTTP request method, such as `GET`, `POST`. + string method = 2; + + // The HTTP request headers. If multiple headers share the same key, they + // must be merged according to the HTTP spec. All header keys must be + // lowercased, because HTTP header keys are case-insensitive. + map headers = 3; + + // The HTTP URL path. + string path = 4; + + // The HTTP request `Host` header value. + string host = 5; + + // The HTTP URL scheme, such as `http` and `https`. + string scheme = 6; + + // The HTTP URL query in the format of `name1=value1&name2=value2`, as it + // appears in the first line of the HTTP request. No decoding is performed. + string query = 7; + + // The timestamp when the `destination` service receives the last byte of + // the request. + google.protobuf.Timestamp time = 9; + + // The HTTP request size in bytes. If unknown, it must be -1. + int64 size = 10; + + // The network protocol used with the request, such as "http/1.1", + // "spdy/3", "h2", "h2c", "webrtc", "tcp", "udp", "quic". See + // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids + // for details. + string protocol = 11; + + // A special parameter for request reason. It is used by security systems + // to associate auditing information with a request. + string reason = 12; + + // The request authentication. May be absent for unauthenticated requests. + // Derived from the HTTP request `Authorization` header or equivalent. + Auth auth = 13; + } + + // This message defines attributes for a typical network response. It + // generally models semantics of an HTTP response. + message Response { + // The HTTP response status code, such as `200` and `404`. + int64 code = 1; + + // The HTTP response size in bytes. If unknown, it must be -1. + int64 size = 2; + + // The HTTP response headers. If multiple headers share the same key, they + // must be merged according to HTTP spec. All header keys must be + // lowercased, because HTTP header keys are case-insensitive. + map headers = 3; + + // The timestamp when the `destination` service sends the last byte of + // the response. + google.protobuf.Timestamp time = 4; + + // The length of time it takes the backend service to fully respond to a + // request. Measured from when the destination service starts to send the + // request to the backend until when the destination service receives the + // complete response from the backend. + google.protobuf.Duration backend_latency = 5; + } + + // This message defines core attributes for a resource. A resource is an + // addressable (named) entity provided by the destination service. For + // example, a file stored on a network storage service. + message Resource { + // The name of the service that this resource belongs to, such as + // `pubsub.googleapis.com`. The service may be different from the DNS + // hostname that actually serves the request. + string service = 1; + + // The stable identifier (name) of a resource on the `service`. A resource + // can be logically identified as "//{resource.service}/{resource.name}". + // The differences between a resource name and a URI are: + // + // * Resource name is a logical identifier, independent of network + // protocol and API version. For example, + // `//pubsub.googleapis.com/projects/123/topics/news-feed`. + // * URI often includes protocol and version information, so it can + // be used directly by applications. For example, + // `https://pubsub.googleapis.com/v1/projects/123/topics/news-feed`. + // + // See https://cloud.google.com/apis/design/resource_names for details. + string name = 2; + + // The type of the resource. The syntax is platform-specific because + // different platforms define their resources differently. + // + // For Google APIs, the type format must be "{service}/{kind}". + string type = 3; + + // The labels or tags on the resource, such as AWS resource tags and + // Kubernetes resource labels. + map labels = 4; + + // The unique identifier of the resource. UID is unique in the time + // and space for this resource within the scope of the service. It is + // typically generated by the server on successful creation of a resource + // and must not be changed. UID is used to uniquely identify resources + // with resource name reuses. This should be a UUID4. + string uid = 5; + + // Annotations is an unstructured key-value map stored with a resource that + // may be set by external tools to store and retrieve arbitrary metadata. + // They are not queryable and should be preserved when modifying objects. + // + // More info: https://kubernetes.io/docs/user-guide/annotations + map annotations = 6; + + // Mutable. The display name set by clients. Must be <= 63 characters. + string display_name = 7; + + // Output only. The timestamp when the resource was created. This may + // be either the time creation was initiated or when it was completed. + google.protobuf.Timestamp create_time = 8; + + // Output only. The timestamp when the resource was last updated. Any + // change to the resource made by users must refresh this value. + // Changes to a resource made by the service should refresh this value. + google.protobuf.Timestamp update_time = 9; + + // Output only. The timestamp when the resource was deleted. + // If the resource is not deleted, this must be empty. + google.protobuf.Timestamp delete_time = 10; + + // Output only. An opaque value that uniquely identifies a version or + // generation of a resource. It can be used to confirm that the client + // and server agree on the ordering of a resource being written. + string etag = 11; + + // Immutable. The location of the resource. The location encoding is + // specific to the service provider, and new encoding may be introduced + // as the service evolves. + // + // For Google Cloud products, the encoding is what is used by Google Cloud + // APIs, such as `us-east1`, `aws-us-east-1`, and `azure-eastus2`. The + // semantics of `location` is identical to the + // `cloud.googleapis.com/location` label used by some Google Cloud APIs. + string location = 12; + } + + // The origin of a network activity. In a multi hop network activity, + // the origin represents the sender of the first hop. For the first hop, + // the `source` and the `origin` must have the same content. + Peer origin = 7; + + // The source of a network activity, such as starting a TCP connection. + // In a multi hop network activity, the source represents the sender of the + // last hop. + Peer source = 1; + + // The destination of a network activity, such as accepting a TCP connection. + // In a multi hop network activity, the destination represents the receiver of + // the last hop. + Peer destination = 2; + + // Represents a network request, such as an HTTP request. + Request request = 3; + + // Represents a network response, such as an HTTP response. + Response response = 4; + + // Represents a target resource that is involved with a network activity. + // If multiple resources are involved with an activity, this must be the + // primary one. + Resource resource = 5; + + // Represents an API operation that is involved to a network activity. + Api api = 6; + + // Supports extensions for advanced use cases, such as logs and metrics. + repeated google.protobuf.Any extensions = 8; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/rpc/error_details.proto b/social-media-service/build/extracted-include-protos/main/google/rpc/error_details.proto new file mode 100644 index 0000000..c4d6c4b --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/rpc/error_details.proto @@ -0,0 +1,249 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc; + +import "google/protobuf/duration.proto"; + +option go_package = "google.golang.org/genproto/googleapis/rpc/errdetails;errdetails"; +option java_multiple_files = true; +option java_outer_classname = "ErrorDetailsProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// Describes when the clients can retry a failed request. Clients could ignore +// the recommendation here or retry when this information is missing from error +// responses. +// +// It's always recommended that clients should use exponential backoff when +// retrying. +// +// Clients should wait until `retry_delay` amount of time has passed since +// receiving the error response before retrying. If retrying requests also +// fail, clients should use an exponential backoff scheme to gradually increase +// the delay between retries based on `retry_delay`, until either a maximum +// number of retries have been reached or a maximum retry delay cap has been +// reached. +message RetryInfo { + // Clients should wait at least this long between retrying the same request. + google.protobuf.Duration retry_delay = 1; +} + +// Describes additional debugging info. +message DebugInfo { + // The stack trace entries indicating where the error occurred. + repeated string stack_entries = 1; + + // Additional debugging information provided by the server. + string detail = 2; +} + +// Describes how a quota check failed. +// +// For example if a daily limit was exceeded for the calling project, +// a service could respond with a QuotaFailure detail containing the project +// id and the description of the quota limit that was exceeded. If the +// calling project hasn't enabled the service in the developer console, then +// a service could respond with the project id and set `service_disabled` +// to true. +// +// Also see RetryInfo and Help types for other details about handling a +// quota failure. +message QuotaFailure { + // A message type used to describe a single quota violation. For example, a + // daily quota or a custom quota that was exceeded. + message Violation { + // The subject on which the quota check failed. + // For example, "clientip:" or "project:". + string subject = 1; + + // A description of how the quota check failed. Clients can use this + // description to find more about the quota configuration in the service's + // public documentation, or find the relevant quota limit to adjust through + // developer console. + // + // For example: "Service disabled" or "Daily Limit for read operations + // exceeded". + string description = 2; + } + + // Describes all quota violations. + repeated Violation violations = 1; +} + +// Describes the cause of the error with structured details. +// +// Example of an error when contacting the "pubsub.googleapis.com" API when it +// is not enabled: +// +// { "reason": "API_DISABLED" +// "domain": "googleapis.com" +// "metadata": { +// "resource": "projects/123", +// "service": "pubsub.googleapis.com" +// } +// } +// +// This response indicates that the pubsub.googleapis.com API is not enabled. +// +// Example of an error that is returned when attempting to create a Spanner +// instance in a region that is out of stock: +// +// { "reason": "STOCKOUT" +// "domain": "spanner.googleapis.com", +// "metadata": { +// "availableRegions": "us-central1,us-east2" +// } +// } +message ErrorInfo { + // The reason of the error. This is a constant value that identifies the + // proximate cause of the error. Error reasons are unique within a particular + // domain of errors. This should be at most 63 characters and match + // /[A-Z0-9_]+/. + string reason = 1; + + // The logical grouping to which the "reason" belongs. The error domain + // is typically the registered service name of the tool or product that + // generates the error. Example: "pubsub.googleapis.com". If the error is + // generated by some common infrastructure, the error domain must be a + // globally unique value that identifies the infrastructure. For Google API + // infrastructure, the error domain is "googleapis.com". + string domain = 2; + + // Additional structured details about this error. + // + // Keys should match /[a-zA-Z0-9-_]/ and be limited to 64 characters in + // length. When identifying the current value of an exceeded limit, the units + // should be contained in the key, not the value. For example, rather than + // {"instanceLimit": "100/request"}, should be returned as, + // {"instanceLimitPerRequest": "100"}, if the client exceeds the number of + // instances that can be created in a single (batch) request. + map metadata = 3; +} + +// Describes what preconditions have failed. +// +// For example, if an RPC failed because it required the Terms of Service to be +// acknowledged, it could list the terms of service violation in the +// PreconditionFailure message. +message PreconditionFailure { + // A message type used to describe a single precondition failure. + message Violation { + // The type of PreconditionFailure. We recommend using a service-specific + // enum type to define the supported precondition violation subjects. For + // example, "TOS" for "Terms of Service violation". + string type = 1; + + // The subject, relative to the type, that failed. + // For example, "google.com/cloud" relative to the "TOS" type would indicate + // which terms of service is being referenced. + string subject = 2; + + // A description of how the precondition failed. Developers can use this + // description to understand how to fix the failure. + // + // For example: "Terms of service not accepted". + string description = 3; + } + + // Describes all precondition violations. + repeated Violation violations = 1; +} + +// Describes violations in a client request. This error type focuses on the +// syntactic aspects of the request. +message BadRequest { + // A message type used to describe a single bad request field. + message FieldViolation { + // A path leading to a field in the request body. The value will be a + // sequence of dot-separated identifiers that identify a protocol buffer + // field. E.g., "field_violations.field" would identify this field. + string field = 1; + + // A description of why the request element is bad. + string description = 2; + } + + // Describes all violations in a client request. + repeated FieldViolation field_violations = 1; +} + +// Contains metadata about the request that clients can attach when filing a bug +// or providing other forms of feedback. +message RequestInfo { + // An opaque string that should only be interpreted by the service generating + // it. For example, it can be used to identify requests in the service's logs. + string request_id = 1; + + // Any data that was used to serve this request. For example, an encrypted + // stack trace that can be sent back to the service provider for debugging. + string serving_data = 2; +} + +// Describes the resource that is being accessed. +message ResourceInfo { + // A name for the type of resource being accessed, e.g. "sql table", + // "cloud storage bucket", "file", "Google calendar"; or the type URL + // of the resource: e.g. "type.googleapis.com/google.pubsub.v1.Topic". + string resource_type = 1; + + // The name of the resource being accessed. For example, a shared calendar + // name: "example.com_4fghdhgsrgh@group.calendar.google.com", if the current + // error is [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED]. + string resource_name = 2; + + // The owner of the resource (optional). + // For example, "user:" or "project:". + string owner = 3; + + // Describes what error is encountered when accessing this resource. + // For example, updating a cloud project may require the `writer` permission + // on the developer console project. + string description = 4; +} + +// Provides links to documentation or for performing an out of band action. +// +// For example, if a quota check failed with an error indicating the calling +// project hasn't enabled the accessed service, this can contain a URL pointing +// directly to the right place in the developer console to flip the bit. +message Help { + // Describes a URL link. + message Link { + // Describes what the link offers. + string description = 1; + + // The URL of the link. + string url = 2; + } + + // URL(s) pointing to additional information on handling the current error. + repeated Link links = 1; +} + +// Provides a localized error message that is safe to return to the user +// which can be attached to an RPC error. +message LocalizedMessage { + // The locale used following the specification defined at + // http://www.rfc-editor.org/rfc/bcp/bcp47.txt. + // Examples are: "en-US", "fr-CH", "es-MX" + string locale = 1; + + // The localized error message in the above locale. + string message = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/rpc/status.proto b/social-media-service/build/extracted-include-protos/main/google/rpc/status.proto new file mode 100644 index 0000000..3b1f7a9 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/rpc/status.proto @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; +option java_multiple_files = true; +option java_outer_classname = "StatusProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The `Status` type defines a logical error model that is suitable for +// different programming environments, including REST APIs and RPC APIs. It is +// used by [gRPC](https://github.com/grpc). Each `Status` message contains +// three pieces of data: error code, error message, and error details. +// +// You can find out more about this error model and how to work with it in the +// [API Design Guide](https://cloud.google.com/apis/design/errors). +message Status { + // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + int32 code = 1; + + // A developer-facing error message, which should be in English. Any + // user-facing error message should be localized and sent in the + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + string message = 2; + + // A list of messages that carry the error details. There is a common set of + // message types for APIs to use. + repeated google.protobuf.Any details = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/calendar_period.proto b/social-media-service/build/extracted-include-protos/main/google/type/calendar_period.proto new file mode 100644 index 0000000..82f5690 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/calendar_period.proto @@ -0,0 +1,56 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/calendarperiod;calendarperiod"; +option java_multiple_files = true; +option java_outer_classname = "CalendarPeriodProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// A `CalendarPeriod` represents the abstract concept of a time period that has +// a canonical start. Grammatically, "the start of the current +// `CalendarPeriod`." All calendar times begin at midnight UTC. +enum CalendarPeriod { + // Undefined period, raises an error. + CALENDAR_PERIOD_UNSPECIFIED = 0; + + // A day. + DAY = 1; + + // A week. Weeks begin on Monday, following + // [ISO 8601](https://en.wikipedia.org/wiki/ISO_week_date). + WEEK = 2; + + // A fortnight. The first calendar fortnight of the year begins at the start + // of week 1 according to + // [ISO 8601](https://en.wikipedia.org/wiki/ISO_week_date). + FORTNIGHT = 3; + + // A month. + MONTH = 4; + + // A quarter. Quarters start on dates 1-Jan, 1-Apr, 1-Jul, and 1-Oct of each + // year. + QUARTER = 5; + + // A half-year. Half-years start on dates 1-Jan and 1-Jul. + HALF = 6; + + // A year. + YEAR = 7; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/color.proto b/social-media-service/build/extracted-include-protos/main/google/type/color.proto new file mode 100644 index 0000000..5dc85a6 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/color.proto @@ -0,0 +1,174 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +import "google/protobuf/wrappers.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/color;color"; +option java_multiple_files = true; +option java_outer_classname = "ColorProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a color in the RGBA color space. This representation is designed +// for simplicity of conversion to/from color representations in various +// languages over compactness. For example, the fields of this representation +// can be trivially provided to the constructor of `java.awt.Color` in Java; it +// can also be trivially provided to UIColor's `+colorWithRed:green:blue:alpha` +// method in iOS; and, with just a little work, it can be easily formatted into +// a CSS `rgba()` string in JavaScript. +// +// This reference page doesn't carry information about the absolute color +// space +// that should be used to interpret the RGB value (e.g. sRGB, Adobe RGB, +// DCI-P3, BT.2020, etc.). By default, applications should assume the sRGB color +// space. +// +// When color equality needs to be decided, implementations, unless +// documented otherwise, treat two colors as equal if all their red, +// green, blue, and alpha values each differ by at most 1e-5. +// +// Example (Java): +// +// import com.google.type.Color; +// +// // ... +// public static java.awt.Color fromProto(Color protocolor) { +// float alpha = protocolor.hasAlpha() +// ? protocolor.getAlpha().getValue() +// : 1.0; +// +// return new java.awt.Color( +// protocolor.getRed(), +// protocolor.getGreen(), +// protocolor.getBlue(), +// alpha); +// } +// +// public static Color toProto(java.awt.Color color) { +// float red = (float) color.getRed(); +// float green = (float) color.getGreen(); +// float blue = (float) color.getBlue(); +// float denominator = 255.0; +// Color.Builder resultBuilder = +// Color +// .newBuilder() +// .setRed(red / denominator) +// .setGreen(green / denominator) +// .setBlue(blue / denominator); +// int alpha = color.getAlpha(); +// if (alpha != 255) { +// result.setAlpha( +// FloatValue +// .newBuilder() +// .setValue(((float) alpha) / denominator) +// .build()); +// } +// return resultBuilder.build(); +// } +// // ... +// +// Example (iOS / Obj-C): +// +// // ... +// static UIColor* fromProto(Color* protocolor) { +// float red = [protocolor red]; +// float green = [protocolor green]; +// float blue = [protocolor blue]; +// FloatValue* alpha_wrapper = [protocolor alpha]; +// float alpha = 1.0; +// if (alpha_wrapper != nil) { +// alpha = [alpha_wrapper value]; +// } +// return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; +// } +// +// static Color* toProto(UIColor* color) { +// CGFloat red, green, blue, alpha; +// if (![color getRed:&red green:&green blue:&blue alpha:&alpha]) { +// return nil; +// } +// Color* result = [[Color alloc] init]; +// [result setRed:red]; +// [result setGreen:green]; +// [result setBlue:blue]; +// if (alpha <= 0.9999) { +// [result setAlpha:floatWrapperWithValue(alpha)]; +// } +// [result autorelease]; +// return result; +// } +// // ... +// +// Example (JavaScript): +// +// // ... +// +// var protoToCssColor = function(rgb_color) { +// var redFrac = rgb_color.red || 0.0; +// var greenFrac = rgb_color.green || 0.0; +// var blueFrac = rgb_color.blue || 0.0; +// var red = Math.floor(redFrac * 255); +// var green = Math.floor(greenFrac * 255); +// var blue = Math.floor(blueFrac * 255); +// +// if (!('alpha' in rgb_color)) { +// return rgbToCssColor(red, green, blue); +// } +// +// var alphaFrac = rgb_color.alpha.value || 0.0; +// var rgbParams = [red, green, blue].join(','); +// return ['rgba(', rgbParams, ',', alphaFrac, ')'].join(''); +// }; +// +// var rgbToCssColor = function(red, green, blue) { +// var rgbNumber = new Number((red << 16) | (green << 8) | blue); +// var hexString = rgbNumber.toString(16); +// var missingZeros = 6 - hexString.length; +// var resultBuilder = ['#']; +// for (var i = 0; i < missingZeros; i++) { +// resultBuilder.push('0'); +// } +// resultBuilder.push(hexString); +// return resultBuilder.join(''); +// }; +// +// // ... +message Color { + // The amount of red in the color as a value in the interval [0, 1]. + float red = 1; + + // The amount of green in the color as a value in the interval [0, 1]. + float green = 2; + + // The amount of blue in the color as a value in the interval [0, 1]. + float blue = 3; + + // The fraction of this color that should be applied to the pixel. That is, + // the final pixel color is defined by the equation: + // + // `pixel color = alpha * (this color) + (1.0 - alpha) * (background color)` + // + // This means that a value of 1.0 corresponds to a solid color, whereas + // a value of 0.0 corresponds to a completely transparent color. This + // uses a wrapper message rather than a simple float scalar so that it is + // possible to distinguish between a default value and the value being unset. + // If omitted, this color object is rendered as a solid color + // (as if the alpha value had been explicitly given a value of 1.0). + google.protobuf.FloatValue alpha = 4; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/date.proto b/social-media-service/build/extracted-include-protos/main/google/type/date.proto new file mode 100644 index 0000000..e4e730e --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/date.proto @@ -0,0 +1,52 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/date;date"; +option java_multiple_files = true; +option java_outer_classname = "DateProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a whole or partial calendar date, such as a birthday. The time of +// day and time zone are either specified elsewhere or are insignificant. The +// date is relative to the Gregorian Calendar. This can represent one of the +// following: +// +// * A full date, with non-zero year, month, and day values +// * A month and day value, with a zero year, such as an anniversary +// * A year on its own, with zero month and day values +// * A year and month value, with a zero day, such as a credit card expiration +// date +// +// Related types are [google.type.TimeOfDay][google.type.TimeOfDay] and +// `google.protobuf.Timestamp`. +message Date { + // Year of the date. Must be from 1 to 9999, or 0 to specify a date without + // a year. + int32 year = 1; + + // Month of a year. Must be from 1 to 12, or 0 to specify a year without a + // month and day. + int32 month = 2; + + // Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 + // to specify a year by itself or a year and month where the day isn't + // significant. + int32 day = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/datetime.proto b/social-media-service/build/extracted-include-protos/main/google/type/datetime.proto new file mode 100644 index 0000000..cfed85d --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/datetime.proto @@ -0,0 +1,104 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +import "google/protobuf/duration.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/datetime;datetime"; +option java_multiple_files = true; +option java_outer_classname = "DateTimeProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents civil time (or occasionally physical time). +// +// This type can represent a civil time in one of a few possible ways: +// +// * When utc_offset is set and time_zone is unset: a civil time on a calendar +// day with a particular offset from UTC. +// * When time_zone is set and utc_offset is unset: a civil time on a calendar +// day in a particular time zone. +// * When neither time_zone nor utc_offset is set: a civil time on a calendar +// day in local time. +// +// The date is relative to the Proleptic Gregorian Calendar. +// +// If year is 0, the DateTime is considered not to have a specific year. month +// and day must have valid, non-zero values. +// +// This type may also be used to represent a physical time if all the date and +// time fields are set and either case of the `time_offset` oneof is set. +// Consider using `Timestamp` message for physical time instead. If your use +// case also would like to store the user's timezone, that can be done in +// another field. +// +// This type is more flexible than some applications may want. Make sure to +// document and validate your application's limitations. +message DateTime { + // Optional. Year of date. Must be from 1 to 9999, or 0 if specifying a + // datetime without a year. + int32 year = 1; + + // Required. Month of year. Must be from 1 to 12. + int32 month = 2; + + // Required. Day of month. Must be from 1 to 31 and valid for the year and + // month. + int32 day = 3; + + // Required. Hours of day in 24 hour format. Should be from 0 to 23. An API + // may choose to allow the value "24:00:00" for scenarios like business + // closing time. + int32 hours = 4; + + // Required. Minutes of hour of day. Must be from 0 to 59. + int32 minutes = 5; + + // Required. Seconds of minutes of the time. Must normally be from 0 to 59. An + // API may allow the value 60 if it allows leap-seconds. + int32 seconds = 6; + + // Required. Fractions of seconds in nanoseconds. Must be from 0 to + // 999,999,999. + int32 nanos = 7; + + // Optional. Specifies either the UTC offset or the time zone of the DateTime. + // Choose carefully between them, considering that time zone data may change + // in the future (for example, a country modifies their DST start/end dates, + // and future DateTimes in the affected range had already been stored). + // If omitted, the DateTime is considered to be in local time. + oneof time_offset { + // UTC offset. Must be whole seconds, between -18 hours and +18 hours. + // For example, a UTC offset of -4:00 would be represented as + // { seconds: -14400 }. + google.protobuf.Duration utc_offset = 8; + + // Time zone. + TimeZone time_zone = 9; + } +} + +// Represents a time zone from the +// [IANA Time Zone Database](https://www.iana.org/time-zones). +message TimeZone { + // IANA Time Zone Database time zone, e.g. "America/New_York". + string id = 1; + + // Optional. IANA Time Zone Database version number, e.g. "2019a". + string version = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/dayofweek.proto b/social-media-service/build/extracted-include-protos/main/google/type/dayofweek.proto new file mode 100644 index 0000000..4c80c62 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/dayofweek.proto @@ -0,0 +1,50 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/dayofweek;dayofweek"; +option java_multiple_files = true; +option java_outer_classname = "DayOfWeekProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a day of the week. +enum DayOfWeek { + // The day of the week is unspecified. + DAY_OF_WEEK_UNSPECIFIED = 0; + + // Monday + MONDAY = 1; + + // Tuesday + TUESDAY = 2; + + // Wednesday + WEDNESDAY = 3; + + // Thursday + THURSDAY = 4; + + // Friday + FRIDAY = 5; + + // Saturday + SATURDAY = 6; + + // Sunday + SUNDAY = 7; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/decimal.proto b/social-media-service/build/extracted-include-protos/main/google/type/decimal.proto new file mode 100644 index 0000000..beb18a5 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/decimal.proto @@ -0,0 +1,95 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/decimal;decimal"; +option java_multiple_files = true; +option java_outer_classname = "DecimalProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// A representation of a decimal value, such as 2.5. Clients may convert values +// into language-native decimal formats, such as Java's [BigDecimal][] or +// Python's [decimal.Decimal][]. +// +// [BigDecimal]: +// https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html +// [decimal.Decimal]: https://docs.python.org/3/library/decimal.html +message Decimal { + // The decimal value, as a string. + // + // The string representation consists of an optional sign, `+` (`U+002B`) + // or `-` (`U+002D`), followed by a sequence of zero or more decimal digits + // ("the integer"), optionally followed by a fraction, optionally followed + // by an exponent. + // + // The fraction consists of a decimal point followed by zero or more decimal + // digits. The string must contain at least one digit in either the integer + // or the fraction. The number formed by the sign, the integer and the + // fraction is referred to as the significand. + // + // The exponent consists of the character `e` (`U+0065`) or `E` (`U+0045`) + // followed by one or more decimal digits. + // + // Services **should** normalize decimal values before storing them by: + // + // - Removing an explicitly-provided `+` sign (`+2.5` -> `2.5`). + // - Replacing a zero-length integer value with `0` (`.5` -> `0.5`). + // - Coercing the exponent character to lower-case (`2.5E8` -> `2.5e8`). + // - Removing an explicitly-provided zero exponent (`2.5e0` -> `2.5`). + // + // Services **may** perform additional normalization based on its own needs + // and the internal decimal implementation selected, such as shifting the + // decimal point and exponent value together (example: `2.5e-1` <-> `0.25`). + // Additionally, services **may** preserve trailing zeroes in the fraction + // to indicate increased precision, but are not required to do so. + // + // Note that only the `.` character is supported to divide the integer + // and the fraction; `,` **should not** be supported regardless of locale. + // Additionally, thousand separators **should not** be supported. If a + // service does support them, values **must** be normalized. + // + // The ENBF grammar is: + // + // DecimalString = + // [Sign] Significand [Exponent]; + // + // Sign = '+' | '-'; + // + // Significand = + // Digits ['.'] [Digits] | [Digits] '.' Digits; + // + // Exponent = ('e' | 'E') [Sign] Digits; + // + // Digits = { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' }; + // + // Services **should** clearly document the range of supported values, the + // maximum supported precision (total number of digits), and, if applicable, + // the scale (number of digits after the decimal point), as well as how it + // behaves when receiving out-of-bounds values. + // + // Services **may** choose to accept values passed as input even when the + // value has a higher precision or scale than the service supports, and + // **should** round the value to fit the supported scale. Alternatively, the + // service **may** error with `400 Bad Request` (`INVALID_ARGUMENT` in gRPC) + // if precision would be lost. + // + // Services **should** error with `400 Bad Request` (`INVALID_ARGUMENT` in + // gRPC) if the service receives a value outside of the supported range. + string value = 1; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/expr.proto b/social-media-service/build/extracted-include-protos/main/google/type/expr.proto new file mode 100644 index 0000000..af0778c --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/expr.proto @@ -0,0 +1,73 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/expr;expr"; +option java_multiple_files = true; +option java_outer_classname = "ExprProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a textual expression in the Common Expression Language (CEL) +// syntax. CEL is a C-like expression language. The syntax and semantics of CEL +// are documented at https://github.com/google/cel-spec. +// +// Example (Comparison): +// +// title: "Summary size limit" +// description: "Determines if a summary is less than 100 chars" +// expression: "document.summary.size() < 100" +// +// Example (Equality): +// +// title: "Requestor is owner" +// description: "Determines if requestor is the document owner" +// expression: "document.owner == request.auth.claims.email" +// +// Example (Logic): +// +// title: "Public documents" +// description: "Determine whether the document should be publicly visible" +// expression: "document.type != 'private' && document.type != 'internal'" +// +// Example (Data Manipulation): +// +// title: "Notification string" +// description: "Create a notification string with a timestamp." +// expression: "'New message received at ' + string(document.create_time)" +// +// The exact variables and functions that may be referenced within an expression +// are determined by the service that evaluates it. See the service +// documentation for additional information. +message Expr { + // Textual representation of an expression in Common Expression Language + // syntax. + string expression = 1; + + // Optional. Title for the expression, i.e. a short string describing + // its purpose. This can be used e.g. in UIs which allow to enter the + // expression. + string title = 2; + + // Optional. Description of the expression. This is a longer text which + // describes the expression, e.g. when hovered over it in a UI. + string description = 3; + + // Optional. String indicating the location of the expression for error + // reporting, e.g. a file name and a position in the file. + string location = 4; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/fraction.proto b/social-media-service/build/extracted-include-protos/main/google/type/fraction.proto new file mode 100644 index 0000000..6c5ae6e --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/fraction.proto @@ -0,0 +1,33 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/fraction;fraction"; +option java_multiple_files = true; +option java_outer_classname = "FractionProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a fraction in terms of a numerator divided by a denominator. +message Fraction { + // The numerator in the fraction, e.g. 2 in 2/3. + int64 numerator = 1; + + // The value by which the numerator is divided, e.g. 3 in 2/3. Must be + // positive. + int64 denominator = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/interval.proto b/social-media-service/build/extracted-include-protos/main/google/type/interval.proto new file mode 100644 index 0000000..9702324 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/interval.proto @@ -0,0 +1,46 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +import "google/protobuf/timestamp.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/interval;interval"; +option java_multiple_files = true; +option java_outer_classname = "IntervalProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a time interval, encoded as a Timestamp start (inclusive) and a +// Timestamp end (exclusive). +// +// The start must be less than or equal to the end. +// When the start equals the end, the interval is empty (matches no time). +// When both start and end are unspecified, the interval matches any time. +message Interval { + // Optional. Inclusive start of the interval. + // + // If specified, a Timestamp matching this interval will have to be the same + // or after the start. + google.protobuf.Timestamp start_time = 1; + + // Optional. Exclusive end of the interval. + // + // If specified, a Timestamp matching this interval will have to be before the + // end. + google.protobuf.Timestamp end_time = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/latlng.proto b/social-media-service/build/extracted-include-protos/main/google/type/latlng.proto new file mode 100644 index 0000000..9231456 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/latlng.proto @@ -0,0 +1,37 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/latlng;latlng"; +option java_multiple_files = true; +option java_outer_classname = "LatLngProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// An object that represents a latitude/longitude pair. This is expressed as a +// pair of doubles to represent degrees latitude and degrees longitude. Unless +// specified otherwise, this must conform to the +// WGS84 +// standard. Values must be within normalized ranges. +message LatLng { + // The latitude in degrees. It must be in the range [-90.0, +90.0]. + double latitude = 1; + + // The longitude in degrees. It must be in the range [-180.0, +180.0]. + double longitude = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/localized_text.proto b/social-media-service/build/extracted-include-protos/main/google/type/localized_text.proto new file mode 100644 index 0000000..5c6922b --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/localized_text.proto @@ -0,0 +1,36 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/localized_text;localized_text"; +option java_multiple_files = true; +option java_outer_classname = "LocalizedTextProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Localized variant of a text in a particular language. +message LocalizedText { + // Localized string in the language corresponding to `language_code' below. + string text = 1; + + // The text's BCP-47 language code, such as "en-US" or "sr-Latn". + // + // For more information, see + // http://www.unicode.org/reports/tr35/#Unicode_locale_identifier. + string language_code = 2; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/money.proto b/social-media-service/build/extracted-include-protos/main/google/type/money.proto new file mode 100644 index 0000000..98d6494 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/money.proto @@ -0,0 +1,42 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/money;money"; +option java_multiple_files = true; +option java_outer_classname = "MoneyProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents an amount of money with its currency type. +message Money { + // The three-letter currency code defined in ISO 4217. + string currency_code = 1; + + // The whole units of the amount. + // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. + int64 units = 2; + + // Number of nano (10^-9) units of the amount. + // The value must be between -999,999,999 and +999,999,999 inclusive. + // If `units` is positive, `nanos` must be positive or zero. + // If `units` is zero, `nanos` can be positive, zero, or negative. + // If `units` is negative, `nanos` must be negative or zero. + // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. + int32 nanos = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/month.proto b/social-media-service/build/extracted-include-protos/main/google/type/month.proto new file mode 100644 index 0000000..99e7551 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/month.proto @@ -0,0 +1,65 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/month;month"; +option java_multiple_files = true; +option java_outer_classname = "MonthProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a month in the Gregorian calendar. +enum Month { + // The unspecified month. + MONTH_UNSPECIFIED = 0; + + // The month of January. + JANUARY = 1; + + // The month of February. + FEBRUARY = 2; + + // The month of March. + MARCH = 3; + + // The month of April. + APRIL = 4; + + // The month of May. + MAY = 5; + + // The month of June. + JUNE = 6; + + // The month of July. + JULY = 7; + + // The month of August. + AUGUST = 8; + + // The month of September. + SEPTEMBER = 9; + + // The month of October. + OCTOBER = 10; + + // The month of November. + NOVEMBER = 11; + + // The month of December. + DECEMBER = 12; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/phone_number.proto b/social-media-service/build/extracted-include-protos/main/google/type/phone_number.proto new file mode 100644 index 0000000..7bbb7d8 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/phone_number.proto @@ -0,0 +1,113 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/phone_number;phone_number"; +option java_multiple_files = true; +option java_outer_classname = "PhoneNumberProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// An object representing a phone number, suitable as an API wire format. +// +// This representation: +// +// - should not be used for locale-specific formatting of a phone number, such +// as "+1 (650) 253-0000 ext. 123" +// +// - is not designed for efficient storage +// - may not be suitable for dialing - specialized libraries (see references) +// should be used to parse the number for that purpose +// +// To do something meaningful with this number, such as format it for various +// use-cases, convert it to an `i18n.phonenumbers.PhoneNumber` object first. +// +// For instance, in Java this would be: +// +// com.google.type.PhoneNumber wireProto = +// com.google.type.PhoneNumber.newBuilder().build(); +// com.google.i18n.phonenumbers.Phonenumber.PhoneNumber phoneNumber = +// PhoneNumberUtil.getInstance().parse(wireProto.getE164Number(), "ZZ"); +// if (!wireProto.getExtension().isEmpty()) { +// phoneNumber.setExtension(wireProto.getExtension()); +// } +// +// Reference(s): +// - https://github.com/google/libphonenumber +message PhoneNumber { + // An object representing a short code, which is a phone number that is + // typically much shorter than regular phone numbers and can be used to + // address messages in MMS and SMS systems, as well as for abbreviated dialing + // (e.g. "Text 611 to see how many minutes you have remaining on your plan."). + // + // Short codes are restricted to a region and are not internationally + // dialable, which means the same short code can exist in different regions, + // with different usage and pricing, even if those regions share the same + // country calling code (e.g. US and CA). + message ShortCode { + // Required. The BCP-47 region code of the location where calls to this + // short code can be made, such as "US" and "BB". + // + // Reference(s): + // - http://www.unicode.org/reports/tr35/#unicode_region_subtag + string region_code = 1; + + // Required. The short code digits, without a leading plus ('+') or country + // calling code, e.g. "611". + string number = 2; + } + + // Required. Either a regular number, or a short code. New fields may be + // added to the oneof below in the future, so clients should ignore phone + // numbers for which none of the fields they coded against are set. + oneof kind { + // The phone number, represented as a leading plus sign ('+'), followed by a + // phone number that uses a relaxed ITU E.164 format consisting of the + // country calling code (1 to 3 digits) and the subscriber number, with no + // additional spaces or formatting, e.g.: + // - correct: "+15552220123" + // - incorrect: "+1 (555) 222-01234 x123". + // + // The ITU E.164 format limits the latter to 12 digits, but in practice not + // all countries respect that, so we relax that restriction here. + // National-only numbers are not allowed. + // + // References: + // - https://www.itu.int/rec/T-REC-E.164-201011-I + // - https://en.wikipedia.org/wiki/E.164. + // - https://en.wikipedia.org/wiki/List_of_country_calling_codes + string e164_number = 1; + + // A short code. + // + // Reference(s): + // - https://en.wikipedia.org/wiki/Short_code + ShortCode short_code = 2; + } + + // The phone number's extension. The extension is not standardized in ITU + // recommendations, except for being defined as a series of numbers with a + // maximum length of 40 digits. Other than digits, some other dialing + // characters such as ',' (indicating a wait) or '#' may be stored here. + // + // Note that no regions currently use extensions with short codes, so this + // field is normally only set in conjunction with an E.164 number. It is held + // separately from the E.164 number to allow for short code extensions in the + // future. + string extension = 3; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/postal_address.proto b/social-media-service/build/extracted-include-protos/main/google/type/postal_address.proto new file mode 100644 index 0000000..c57c7c3 --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/postal_address.proto @@ -0,0 +1,134 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/postaladdress;postaladdress"; +option java_multiple_files = true; +option java_outer_classname = "PostalAddressProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a postal address, e.g. for postal delivery or payments addresses. +// Given a postal address, a postal service can deliver items to a premise, P.O. +// Box or similar. +// It is not intended to model geographical locations (roads, towns, +// mountains). +// +// In typical usage an address would be created via user input or from importing +// existing data, depending on the type of process. +// +// Advice on address input / editing: +// - Use an i18n-ready address widget such as +// https://github.com/google/libaddressinput) +// - Users should not be presented with UI elements for input or editing of +// fields outside countries where that field is used. +// +// For more guidance on how to use this schema, please see: +// https://support.google.com/business/answer/6397478 +message PostalAddress { + // The schema revision of the `PostalAddress`. This must be set to 0, which is + // the latest revision. + // + // All new revisions **must** be backward compatible with old revisions. + int32 revision = 1; + + // Required. CLDR region code of the country/region of the address. This + // is never inferred and it is up to the user to ensure the value is + // correct. See http://cldr.unicode.org/ and + // http://www.unicode.org/cldr/charts/30/supplemental/territory_information.html + // for details. Example: "CH" for Switzerland. + string region_code = 2; + + // Optional. BCP-47 language code of the contents of this address (if + // known). This is often the UI language of the input form or is expected + // to match one of the languages used in the address' country/region, or their + // transliterated equivalents. + // This can affect formatting in certain countries, but is not critical + // to the correctness of the data and will never affect any validation or + // other non-formatting related operations. + // + // If this value is not known, it should be omitted (rather than specifying a + // possibly incorrect default). + // + // Examples: "zh-Hant", "ja", "ja-Latn", "en". + string language_code = 3; + + // Optional. Postal code of the address. Not all countries use or require + // postal codes to be present, but where they are used, they may trigger + // additional validation with other parts of the address (e.g. state/zip + // validation in the U.S.A.). + string postal_code = 4; + + // Optional. Additional, country-specific, sorting code. This is not used + // in most regions. Where it is used, the value is either a string like + // "CEDEX", optionally followed by a number (e.g. "CEDEX 7"), or just a number + // alone, representing the "sector code" (Jamaica), "delivery area indicator" + // (Malawi) or "post office indicator" (e.g. Cรดte d'Ivoire). + string sorting_code = 5; + + // Optional. Highest administrative subdivision which is used for postal + // addresses of a country or region. + // For example, this can be a state, a province, an oblast, or a prefecture. + // Specifically, for Spain this is the province and not the autonomous + // community (e.g. "Barcelona" and not "Catalonia"). + // Many countries don't use an administrative area in postal addresses. E.g. + // in Switzerland this should be left unpopulated. + string administrative_area = 6; + + // Optional. Generally refers to the city/town portion of the address. + // Examples: US city, IT comune, UK post town. + // In regions of the world where localities are not well defined or do not fit + // into this structure well, leave locality empty and use address_lines. + string locality = 7; + + // Optional. Sublocality of the address. + // For example, this can be neighborhoods, boroughs, districts. + string sublocality = 8; + + // Unstructured address lines describing the lower levels of an address. + // + // Because values in address_lines do not have type information and may + // sometimes contain multiple values in a single field (e.g. + // "Austin, TX"), it is important that the line order is clear. The order of + // address lines should be "envelope order" for the country/region of the + // address. In places where this can vary (e.g. Japan), address_language is + // used to make it explicit (e.g. "ja" for large-to-small ordering and + // "ja-Latn" or "en" for small-to-large). This way, the most specific line of + // an address can be selected based on the language. + // + // The minimum permitted structural representation of an address consists + // of a region_code with all remaining information placed in the + // address_lines. It would be possible to format such an address very + // approximately without geocoding, but no semantic reasoning could be + // made about any of the address components until it was at least + // partially resolved. + // + // Creating an address only containing a region_code and address_lines, and + // then geocoding is the recommended way to handle completely unstructured + // addresses (as opposed to guessing which parts of the address should be + // localities or administrative areas). + repeated string address_lines = 9; + + // Optional. The recipient at the address. + // This field may, under certain circumstances, contain multiline information. + // For example, it might contain "care of" information. + repeated string recipients = 10; + + // Optional. The name of the organization at the address. + string organization = 11; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/quaternion.proto b/social-media-service/build/extracted-include-protos/main/google/type/quaternion.proto new file mode 100644 index 0000000..dfb822d --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/quaternion.proto @@ -0,0 +1,94 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/quaternion;quaternion"; +option java_multiple_files = true; +option java_outer_classname = "QuaternionProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// A quaternion is defined as the quotient of two directed lines in a +// three-dimensional space or equivalently as the quotient of two Euclidean +// vectors (https://en.wikipedia.org/wiki/Quaternion). +// +// Quaternions are often used in calculations involving three-dimensional +// rotations (https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation), +// as they provide greater mathematical robustness by avoiding the gimbal lock +// problems that can be encountered when using Euler angles +// (https://en.wikipedia.org/wiki/Gimbal_lock). +// +// Quaternions are generally represented in this form: +// +// w + xi + yj + zk +// +// where x, y, z, and w are real numbers, and i, j, and k are three imaginary +// numbers. +// +// Our naming choice `(x, y, z, w)` comes from the desire to avoid confusion for +// those interested in the geometric properties of the quaternion in the 3D +// Cartesian space. Other texts often use alternative names or subscripts, such +// as `(a, b, c, d)`, `(1, i, j, k)`, or `(0, 1, 2, 3)`, which are perhaps +// better suited for mathematical interpretations. +// +// To avoid any confusion, as well as to maintain compatibility with a large +// number of software libraries, the quaternions represented using the protocol +// buffer below *must* follow the Hamilton convention, which defines `ij = k` +// (i.e. a right-handed algebra), and therefore: +// +// i^2 = j^2 = k^2 = ijk = โˆ’1 +// ij = โˆ’ji = k +// jk = โˆ’kj = i +// ki = โˆ’ik = j +// +// Please DO NOT use this to represent quaternions that follow the JPL +// convention, or any of the other quaternion flavors out there. +// +// Definitions: +// +// - Quaternion norm (or magnitude): `sqrt(x^2 + y^2 + z^2 + w^2)`. +// - Unit (or normalized) quaternion: a quaternion whose norm is 1. +// - Pure quaternion: a quaternion whose scalar component (`w`) is 0. +// - Rotation quaternion: a unit quaternion used to represent rotation. +// - Orientation quaternion: a unit quaternion used to represent orientation. +// +// A quaternion can be normalized by dividing it by its norm. The resulting +// quaternion maintains the same direction, but has a norm of 1, i.e. it moves +// on the unit sphere. This is generally necessary for rotation and orientation +// quaternions, to avoid rounding errors: +// https://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions +// +// Note that `(x, y, z, w)` and `(-x, -y, -z, -w)` represent the same rotation, +// but normalization would be even more useful, e.g. for comparison purposes, if +// it would produce a unique representation. It is thus recommended that `w` be +// kept positive, which can be achieved by changing all the signs when `w` is +// negative. +// +message Quaternion { + // The x component. + double x = 1; + + // The y component. + double y = 2; + + // The z component. + double z = 3; + + // The scalar component. + double w = 4; +} diff --git a/social-media-service/build/extracted-include-protos/main/google/type/timeofday.proto b/social-media-service/build/extracted-include-protos/main/google/type/timeofday.proto new file mode 100644 index 0000000..5cb48aa --- /dev/null +++ b/social-media-service/build/extracted-include-protos/main/google/type/timeofday.proto @@ -0,0 +1,44 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/timeofday;timeofday"; +option java_multiple_files = true; +option java_outer_classname = "TimeOfDayProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a time of day. The date and time zone are either not significant +// or are specified elsewhere. An API may choose to allow leap seconds. Related +// types are [google.type.Date][google.type.Date] and +// `google.protobuf.Timestamp`. +message TimeOfDay { + // Hours of day in 24 hour format. Should be from 0 to 23. An API may choose + // to allow the value "24:00:00" for scenarios like business closing time. + int32 hours = 1; + + // Minutes of hour of day. Must be from 0 to 59. + int32 minutes = 2; + + // Seconds of minutes of the time. Must normally be from 0 to 59. An API may + // allow the value 60 if it allows leap-seconds. + int32 seconds = 3; + + // Fractions of seconds in nanoseconds. Must be from 0 to 999,999,999. + int32 nanos = 4; +} diff --git a/social-media-service/build/reports/problems/problems-report.html b/social-media-service/build/reports/problems/problems-report.html new file mode 100644 index 0000000..d87329a --- /dev/null +++ b/social-media-service/build/reports/problems/problems-report.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + + Gradle Configuration Cache + + + +
+ +
+ Loading... +
+ + + + + + diff --git a/social-media-service/build/resources/main/application.properties b/social-media-service/build/resources/main/application.properties new file mode 100644 index 0000000..8a46c0a --- /dev/null +++ b/social-media-service/build/resources/main/application.properties @@ -0,0 +1,20 @@ +spring.application.name=social-media-service + +# Database configuration +#spring.datasource.url=${SPRING_DATASOURCE_URL} +spring.datasource.username=postgres.odffpjvuptssxaaggnsn +spring.datasource.password=Postgres + +#spring.datasource.username=${SPRING_DATASOURCE_USERNAME} +#spring.datasource.password=${SPRING_DATASOURCE_PASSWORD} + +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres?user=postgres.odffpjvuptssxaaggnsn&password=Postgres +#spring.jpa.hibernate.ddl-auto=none + +# JPA & Hibernate Configuration +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.show-sql=true + +logging.level.org.springframework.web.cors=DEBUG diff --git a/social-media-service/build/tmp/compileJava/previous-compilation-data.bin b/social-media-service/build/tmp/compileJava/previous-compilation-data.bin new file mode 100644 index 0000000..400d28c Binary files /dev/null and b/social-media-service/build/tmp/compileJava/previous-compilation-data.bin differ diff --git a/social-media-service/entrypoint.sh b/social-media-service/entrypoint.sh new file mode 100644 index 0000000..b9278dd --- /dev/null +++ b/social-media-service/entrypoint.sh @@ -0,0 +1,12 @@ +#!/bin/sh +echo "Waiting for Keycloak to be ready..." +until curl -sSf http://auth-service:8080/realms/kong/.well-known/openid-configuration; do + echo "Waiting for realm kong..."; + sleep 10; +done +until curl -sSf -k https://gotogetheruom.duckdns.org:8446/realms/kong/.well-known/openid-configuration; do + echo "Waiting for realm kong..."; + sleep 10; +done +echo "Keycloak realm is ready. Starting app..." +exec java -jar /app.jar diff --git a/social-media-service/gradle/wrapper/gradle-wrapper.jar b/social-media-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..a4b76b9 Binary files /dev/null and b/social-media-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/social-media-service/gradle/wrapper/gradle-wrapper.properties b/social-media-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..cea7a79 --- /dev/null +++ b/social-media-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/social-media-service/gradlew b/social-media-service/gradlew new file mode 100755 index 0000000..f3b75f3 --- /dev/null +++ b/social-media-service/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright ยฉ 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป, +# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป; +# * compound commands having a testable exit status, especially ยซcaseยป; +# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/social-media-service/gradlew.bat b/social-media-service/gradlew.bat new file mode 100644 index 0000000..9b42019 --- /dev/null +++ b/social-media-service/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/social-media-service/keycloak-config.md b/social-media-service/keycloak-config.md new file mode 100644 index 0000000..d2b44ee --- /dev/null +++ b/social-media-service/keycloak-config.md @@ -0,0 +1,117 @@ +# Keycloak Configuration for Google Social Login + +This document outlines the steps to configure Google as an identity provider in Keycloak for social login. + +## Prerequisites + +* A running Keycloak instance. +* A Google Cloud Platform (GCP) account. + +## Step 1: Configure Google Cloud Platform OAuth 2.0 Credentials + +1. **Go to Google Cloud Console:** Navigate to [https://console.cloud.google.com/](https://console.cloud.google.com/). +2. **Select or Create Project:** Choose an existing project or create a new one. +3. **Navigate to Credentials:** In the left navigation menu, go to "APIs & Services" > "Credentials". +4. **Create OAuth Client ID:** + * Click on "+ CREATE CREDENTIALS" at the top. + * Select "OAuth client ID". + * For "Application type", choose "Web application". + * Give it a "Name" (e.g., "Keycloak Social Login"). +5. **Configure Authorized Redirect URIs:** + * Under "Authorized redirect URIs", click "+ ADD URI". + * Enter your Keycloak's redirect URI for the Google broker. This typically follows the pattern: + `YOUR_KEYCLOAK_HOST/realms/YOUR_REALM_NAME/broker/google/endpoint` + For example, if Keycloak is running locally on port 8081 and your realm is named `kong`: + `http://localhost:8081/realms/kong/broker/google/endpoint` + * Replace `YOUR_KEYCLOAK_HOST` and `YOUR_REALM_NAME` with your actual Keycloak host and realm name. +6. **Create and Note Credentials:** + * Click "CREATE". + * A dialog will appear showing your "Client ID" and "Client Secret". **Copy these values securely.** You will need them for Keycloak configuration. + +## Step 2: Configure Google as an Identity Provider in Keycloak + +1. **Log in to Keycloak Admin Console:** Access your Keycloak admin console (e.g., `http://localhost:8081/admin`). +2. **Select Your Realm:** From the dropdown in the top-left corner, select the realm you want to configure (e.g., `kong`). +3. **Navigate to Identity Providers:** In the left navigation menu, click on "Identity Providers". +4. **Add Google Provider:** + * In the "Add provider..." dropdown, select "Google". +5. **Configure Google Provider Settings:** + * **Redirect URI:** This field will display the redirect URI that Keycloak expects. Ensure this URI is one of the "Authorized redirect URIs" you configured in the Google Cloud Platform console in Step 1.5. + * **Client ID:** Paste the "Client ID" you obtained from GCP (Step 1.6). + * **Client Secret:** Paste the "Client Secret" you obtained from GCP (Step 1.6). + * **Default Scopes:** `openid profile email` are common defaults. + * **Store Tokens:** Enable if you want Keycloak to store the external Google tokens. + * **Store Tokens Readable:** Enable if you want to allow applications to retrieve and read the stored external Google tokens. + * Adjust other settings like "Sync Mode" as needed for your use case. +6. **Save:** Click "Save". + +## Step 3: Configure Mappers for Google Identity Provider + +Mappers define how user attributes from Google are mapped to Keycloak user attributes upon successful authentication. + +1. **Go to Mappers Tab:** After saving the Google identity provider, click on the "Mappers" tab for that provider. +2. **Create Mappers:** Click "Create" to add new mappers. You'll typically want to map: + * **Email:** + * Name: `Google Email` + * Sync Mode Override: `inherit` (or choose as needed) + * Mapper Type: `Attribute Importer` + * Social Profile JSON Field Path: `email` + * User Attribute Name: `email` (this is the Keycloak user attribute) + * **First Name:** + * Name: `Google First Name` + * Mapper Type: `Attribute Importer` + * Social Profile JSON Field Path: `given_name` + * User Attribute Name: `firstName` + * **Last Name:** + * Name: `Google Last Name` + * Mapper Type: `Attribute Importer` + * Social Profile JSON Field Path: `family_name` + * User Attribute Name: `lastName` + * **Username (Optional, choose one strategy):** + * **Option A: Map from Email:** + * Name: `Google Username from Email` + * Mapper Type: `Attribute Importer` + * Social Profile JSON Field Path: `email` + * User Attribute Name: `username` + * **Option B: Map from Name (e.g., full name or given_name):** + * Name: `Google Username from Name` + * Mapper Type: `Attribute Importer` + * Social Profile JSON Field Path: `name` (or `given_name`) + * User Attribute Name: `username` + * Adjust "User Attribute Name" to match the attribute names used in your Keycloak user model. +3. **Save each mapper.** + +## Step 4: Test the Login + +1. Go to your Keycloak account login page for the configured realm (e.g., `http://localhost:8081/realms/kong/account`). +2. You should now see an option to "Sign in with Google". +3. Clicking it should redirect you to Google for authentication and then back to Keycloak. +4. After successful authentication, Keycloak will either create a new user (if it's the first time for this Google account) or link to an existing one, based on your configuration. + +## Important Notes + +* **HTTPS for Production:** In production environments, always use HTTPS for both your application and Keycloak. Google OAuth2 requires HTTPS for redirect URIs in production. +* **Client Secret Security:** Keep your Google Client Secret confidential. Do not embed it directly in client-side code. +* **Realm Name:** Ensure you are working within the correct Keycloak realm throughout the configuration. +* **Troubleshooting:** Check Keycloak server logs and browser developer tools for errors if you encounter issues. +## Step 5: Configuring for Refresh Tokens (Important for Password Grant) + +When using the Password Grant type for your client in Keycloak (e.g., the `kong-oidc` client if it's used for direct username/password login from your service), you need to ensure Keycloak is configured to issue refresh tokens and that their lifetimes are appropriate. + +1. **Client Configuration in Keycloak:** + * Navigate to your client's settings in the Keycloak Admin Console (e.g., `kong-oidc` under your realm). + * Under the "Advanced" tab (or similar, depending on Keycloak version), ensure that **"Use Refresh Tokens"** is ON. This is often on by default for confidential clients. + * If you want refresh tokens to be available even if the user's session times out (for true "offline" access via password grant), ensure the **"Offline Access"** switch for the *client* is also enabled, or that the client's "Access Token Lifespan" and "Client Session Idle/Max" settings are configured appropriately. For password grants, the `offline_access` scope in the request is also key. + +2. **Realm Token Lifetimes:** + * In your realm settings, under "Tokens", you can configure: + * **Access Token Lifespan:** How long access tokens are valid. + * **Client Session Idle:** How long a session can be idle before refresh tokens associated with it might become invalid if not "offline" tokens. + * **Client Session Max:** Absolute maximum time a session (and potentially its refresh tokens) can last. + * **Offline Session Idle:** For `offline_access` tokens, how long they can be idle. This is critical for long-lived refresh tokens. + * **Offline Session Max Limited:** Whether there's a hard upper limit on offline token lifespan. + +3. **Scope for Password Grant:** + * When your service requests a token using the password grant, include the `offline_access` scope if you intend for the refresh token to outlive the regular user session. The code for `authenticateWithKeycloak` in `UserService.java` has been updated to include this scope. + +By ensuring these settings, the refresh tokens obtained via the password grant flow will behave as expected, allowing clients to maintain longer sessions without requiring users to re-enter their passwords frequently. diff --git a/social-media-service/settings.gradle b/social-media-service/settings.gradle new file mode 100644 index 0000000..b451b0e --- /dev/null +++ b/social-media-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'social-media-service' diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/SocialMediaServiceApplication.java b/social-media-service/src/main/java/com/example/socialmediaservice/SocialMediaServiceApplication.java new file mode 100644 index 0000000..e41511f --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/SocialMediaServiceApplication.java @@ -0,0 +1,13 @@ +package com.example.socialmediaservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SocialMediaServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(SocialMediaServiceApplication.class, args); + } + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/config/CorsConfig.java b/social-media-service/src/main/java/com/example/socialmediaservice/config/CorsConfig.java new file mode 100644 index 0000000..28c0d29 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/config/CorsConfig.java @@ -0,0 +1,24 @@ +// package com.example.socialmediaservice.config; + +// import org.springframework.context.annotation.Bean; +// import org.springframework.context.annotation.Configuration; +// import org.springframework.web.servlet.config.annotation.CorsRegistry; +// import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +// @Configuration +// public class CorsConfig { +// @Bean +// public WebMvcConfigurer corsConfigurer() { +// return new WebMvcConfigurer() { +// @Override +// public void addCorsMappings(CorsRegistry registry) { +// registry.addMapping("/**") +// .allowedOrigins("http://localhost:3000", "https://go-together-uom.vercel.app") +// .allowedMethods("*") +// .allowedHeaders("*") +// .allowCredentials(true); // โœ… Only works with specific origin +// } +// }; +// } +// } + diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/config/SecurityConfig.java b/social-media-service/src/main/java/com/example/socialmediaservice/config/SecurityConfig.java new file mode 100644 index 0000000..a1fceb7 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/config/SecurityConfig.java @@ -0,0 +1,42 @@ +package com.example.socialmediaservice.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.firewall.HttpFirewall; +import org.springframework.security.web.firewall.StrictHttpFirewall; +import org.springframework.security.web.util.matcher.AnyRequestMatcher; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + // Allow semicolons in URLs (for session ids etc.) + @Bean + public HttpFirewall allowSemicolonHttpFirewall() { + StrictHttpFirewall firewall = new StrictHttpFirewall(); + firewall.setAllowSemicolon(true); + return firewall; + } + + // Register custom firewall + @Bean + public WebSecurityCustomizer webSecurityCustomizer(HttpFirewall firewall) { + return web -> web.httpFirewall(firewall); + } + + // Disable all Spring Security checks + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf(csrf -> csrf.disable()) + .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()); + return http.build(); + } +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/controller/AuthController.java b/social-media-service/src/main/java/com/example/socialmediaservice/controller/AuthController.java new file mode 100644 index 0000000..3b2091a --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/controller/AuthController.java @@ -0,0 +1,210 @@ +package com.example.socialmediaservice.controller; + +import com.example.socialmediaservice.service.AuthService; +// import com.example.socialmediaservice.service.UserService; // Only needed if serializeUser were to call userService directly for some reason. +import com.example.socialmediaservice.dto.LoginRequestDTO; +import com.example.socialmediaservice.entity.User; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.web.bind.annotation.*; // For CookieValue + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api/auth") +@RequiredArgsConstructor +@Slf4j +@CrossOrigin(origins = {"http://localhost:3000", "https://go-together-uom.vercel.app"}, allowCredentials = "true") +public class AuthController { + + private final AuthService authService; + + // serializeUser method copied from UserController + public String serializeUser(User user) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + Map minimalUser = new HashMap<>(); + minimalUser.put("userId", user.getUserId()); + minimalUser.put("username", user.getUsername()); + minimalUser.put("firstName", user.getFirstName()); + minimalUser.put("avatarUrl", user.getAvatarUrl()); + + String json = objectMapper.writeValueAsString(minimalUser); + return Base64.getUrlEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8)); + } catch (JsonProcessingException e) { + log.error("Failed to serialize user for cookie", e); + throw new RuntimeException("Failed to serialize user for cookie", e); + } + } + + @PostMapping("/login") // Was /api/users/auth/login + public ResponseEntity login(@RequestBody LoginRequestDTO loginRequest, HttpServletResponse response) { + AuthService.TokenResponse tokenDetails = authService.loginWithPassword(loginRequest.getUsername(), loginRequest.getPassword()); + String accessToken = tokenDetails.getAccessToken(); + String refreshTokenValue = tokenDetails.getRefreshToken(); // Renamed to avoid conflict with method param name + long expiresIn = tokenDetails.getExpiresIn(); + + User user = authService.getUserByEmailFromToken(accessToken); + if (user != null) { + user.setPosts(null); + } else { + // Handle case where user might be null after token validation, though unlikely if token is valid + log.error("User not found for a valid access token: {}", accessToken); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("error", "User details not found after login.")); + } + + + String accessTokenCookieHeader = ResponseCookie.from("access_token", accessToken) + .httpOnly(true) + .secure(false) + .path("/") + .maxAge(expiresIn) + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, accessTokenCookieHeader); + + if (refreshTokenValue != null && !refreshTokenValue.isEmpty()) { + long refreshTokenMaxAge = 2592000; // 30 days + String refreshTokenCookieHeader = ResponseCookie.from("refresh_token", refreshTokenValue) + .httpOnly(true) + .secure(false) + .path("/api/auth/refresh") // Path for refresh token cookie, specific to auth controller + .maxAge(refreshTokenMaxAge) + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, refreshTokenCookieHeader); + log.info("Refresh token cookie set for user {}.", user.getUsername()); + } else { + log.warn("Refresh token was null or empty for user {}. Refresh token cookie not set.", user.getUsername()); + } + + String userCookieHeader = ResponseCookie.from("user", serializeUser(user)) + .httpOnly(false) + .secure(false) + .path("/") + .maxAge(expiresIn) + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, userCookieHeader); + + log.info("User {} login successful", user.getUsername()); + + return ResponseEntity.ok(Map.of( + "accessToken", accessToken, + "expiresIn", expiresIn, + "user", serializeUser(user) + )); + } + + @GetMapping("/login/oauth2/code/google") // Was /api/users/login/oauth2/code/google + public ResponseEntity handleGoogleCallback(@AuthenticationPrincipal OAuth2User principal, HttpServletResponse response) { + if (principal == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Authentication failed: No principal found."); + } + + Map authProcessingResponse = authService.processOAuth2Login(principal); + String token = (String) authProcessingResponse.get("token"); // This is the placeholder token from processOAuth2Login + User user = (User) authProcessingResponse.get("user"); + + if (user == null) { + log.error("User object was null after OAuth2 processing for principal: {}", principal.getName()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("error", "User processing failed after OAuth2 login.")); + } + user.setPosts(null); + + + // TODO: The token from processOAuth2Login is a placeholder. + // In a real OAuth2 setup, this token would be the actual Keycloak session token or ID token. + // For now, using a fixed maxAge as the placeholder token has no real expiry. + long oauthTokenMaxAge = 3600; // Example: 1 hour for OAuth2 login session token + + String accessTokenCookieHeader = ResponseCookie.from("access_token", token) + .httpOnly(true) + .secure(false) + .path("/") + .maxAge(oauthTokenMaxAge) // Placeholder expiry + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, accessTokenCookieHeader); + + String userCookieHeader = ResponseCookie.from("user", serializeUser(user)) + .httpOnly(false) + .secure(false) + .path("/") + .maxAge(oauthTokenMaxAge) // Placeholder expiry + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, userCookieHeader); + + log.info("OAuth2 callback for user {} successful. Placeholder token issued.", user.getEmail()); + return ResponseEntity.ok(Map.of( + "accessToken", token, // Placeholder token + "user", serializeUser(user) + )); + } + + @PostMapping("/refresh") // Was /api/users/auth/refresh + public ResponseEntity refreshToken(@CookieValue(name = "refresh_token", required = false) String refreshTokenValue, HttpServletResponse response) { + if (refreshTokenValue == null || refreshTokenValue.isEmpty()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("error", "Missing refresh token")); + } + + try { + AuthService.TokenResponse tokenDetails = authService.refreshAccessToken(refreshTokenValue); + String newAccessToken = tokenDetails.getAccessToken(); + long newExpiresIn = tokenDetails.getExpiresIn(); + String newRefreshToken = tokenDetails.getRefreshToken(); + + String newAccessTokenCookieHeader = ResponseCookie.from("access_token", newAccessToken) + .httpOnly(true) + .secure(false) + .path("/") + .maxAge(newExpiresIn) + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, newAccessTokenCookieHeader); + + if (newRefreshToken != null && !newRefreshToken.isEmpty() && !newRefreshToken.equals(refreshTokenValue)) { + long refreshTokenMaxAge = 2592000; // 30 days + String newRefreshTokenCookieHeader = ResponseCookie.from("refresh_token", newRefreshToken) + .httpOnly(true) + .secure(false) + .path("/api/auth/refresh") // Consistent path + .maxAge(refreshTokenMaxAge) + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, newRefreshTokenCookieHeader); + log.info("Refresh token was rotated. New refresh_token cookie set."); + } + + User user = authService.getUserByEmailFromToken(newAccessToken); + if (user != null) { + user.setPosts(null); + String userCookieHeader = ResponseCookie.from("user", serializeUser(user)) + .httpOnly(false) + .secure(false) + .path("/") + .maxAge(newExpiresIn) + .build().toString() + "; SameSite=Lax"; + response.addHeader(HttpHeaders.SET_COOKIE, userCookieHeader); + } else { + log.warn("User could not be fetched with new access token during refresh. User cookie not updated."); + } + + log.info("Access token refreshed successfully."); + return ResponseEntity.ok(Map.of( + "accessToken", newAccessToken, + "expiresIn", newExpiresIn + )); + + } catch (RuntimeException e) { + log.error("Error refreshing token: {}", e.getMessage(), e); // Added exception to log + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("error", "Invalid or expired refresh token", "detail", e.getMessage())); + } + } +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/controller/MediaController.java b/social-media-service/src/main/java/com/example/socialmediaservice/controller/MediaController.java new file mode 100644 index 0000000..0733f68 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/controller/MediaController.java @@ -0,0 +1,30 @@ +package com.example.socialmediaservice.controller; + +import com.example.socialmediaservice.dto.MediaCreateRequestDTO; +import com.example.socialmediaservice.dto.MediaDTO; +import com.example.socialmediaservice.entity.Media; +import com.example.socialmediaservice.service.MediaService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/media") +@RequiredArgsConstructor +public class MediaController { + + private final MediaService mediaService; + + @PostMapping + public ResponseEntity createMedia(@RequestBody MediaCreateRequestDTO requestDTO) { + Media media = mediaService.createMedia(requestDTO.getUrl(), requestDTO.getType()); + MediaDTO dto = new MediaDTO(); + dto.setId(media.getId()); + dto.setUrl(media.getUrl()); + dto.setType(media.getType()); + return ResponseEntity.ok(dto); + } +} \ No newline at end of file diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/controller/PostController.java b/social-media-service/src/main/java/com/example/socialmediaservice/controller/PostController.java new file mode 100644 index 0000000..3a812a4 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/controller/PostController.java @@ -0,0 +1,74 @@ +package com.example.socialmediaservice.controller; + +import com.example.socialmediaservice.dto.*; +import com.example.socialmediaservice.service.CommentService; +import com.example.socialmediaservice.service.PostService; +import com.example.socialmediaservice.service.ReactionService; +import lombok.RequiredArgsConstructor; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/api/posts") +@RequiredArgsConstructor +public class PostController { + + private final PostService postService; + private final ReactionService reactionService; + private final CommentService commentService; + + // 1. Create Post + @PostMapping("/create") + public ResponseEntity createPost( +// @PathVariable String userId, + @RequestBody CreatePostRequestDTO createPostRequestDTO) { + log.info("email: {} | caption: {}", createPostRequestDTO.getEmail(), createPostRequestDTO.getCaption()); + return ResponseEntity.ok(postService.createPost(createPostRequestDTO.getEmail(), createPostRequestDTO)); + } + + // 2. Get all posts created by a specific user + @CrossOrigin(origins ={"http://localhost:3000", "https://go-together-uom.vercel.app"}, allowCredentials = "true") + @GetMapping("/user/{userId}") + public ResponseEntity> getPostsByUser(@PathVariable String userId) { + return ResponseEntity.ok(postService.getPostsByUser(userId)); + } + + // 3. Get post by postId + @GetMapping("/{postId}") + public ResponseEntity getPostById(@PathVariable String postId) { + return ResponseEntity.ok(postService.getPostById(postId)); + } + + // 4. Update post content + @PutMapping("/{postId}") + public ResponseEntity updatePost( + @PathVariable String postId, + @RequestBody UpdatePostRequestDTO requestDTO) { + return ResponseEntity.ok(postService.updatePost(postId, requestDTO)); + } + + @CrossOrigin(origins = {"http://localhost:3000", "https://go-together-uom.vercel.app"}, allowCredentials = "true") + @GetMapping("/for-you") + public ResponseEntity getForYouPosts( + @RequestParam(required = false) String cursor, + @RequestParam(defaultValue = "10") int size) { + return ResponseEntity.ok(postService.getForYouFeed(cursor, size)); + // Temporarily bypass the service call + // log.warn("Executing TEMPORARILY SIMPLIFIED getForYouPosts endpoint in PostController for diagnosis."); + + // PostsPageDTO simplifiedPage = new PostsPageDTO(); + + // // Option 1: Empty list of posts + // simplifiedPage.setPosts(new java.util.ArrayList<>()); + // simplifiedPage.setNextCursor(null); + + // return ResponseEntity.ok(simplifiedPage); + } + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/controller/PostInteractionController.java b/social-media-service/src/main/java/com/example/socialmediaservice/controller/PostInteractionController.java new file mode 100644 index 0000000..ab79b5c --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/controller/PostInteractionController.java @@ -0,0 +1,204 @@ +package com.example.socialmediaservice.controller; + +import com.example.socialmediaservice.dto.*; +import com.example.socialmediaservice.entity.Comment; +import com.example.socialmediaservice.entity.Post; +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.enums.ReactionType; +import com.example.socialmediaservice.repository.CommentRepo; +import com.example.socialmediaservice.repository.PostRepo; +import com.example.socialmediaservice.repository.UserRepo; +import com.example.socialmediaservice.service.BookmarkService; +import com.example.socialmediaservice.service.CommentService; +import com.example.socialmediaservice.service.ReactionService; +import lombok.RequiredArgsConstructor; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@CrossOrigin( + origins = {"http://localhost:3000", "https://go-together-uom.vercel.app"}, + allowCredentials = "true" +) +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/posts") +public class PostInteractionController { + + private final PostRepo postRepo; + private final UserRepo userRepo; + private final CommentRepo commentRepo; + private final CommentService commentService; + private final ReactionService reactionService; + private final BookmarkService bookmarkService; + + // 1. Get all comments for a specific post + @GetMapping("/{postId}/comments") + public ResponseEntity> getCommentsForPost( + @PathVariable String postId, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "5") int size + ) { + Post post = postRepo.findByPostId(postId); + if (post == null) { + return ResponseEntity.notFound().build(); + } + + Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending()); + Page commentPage = commentRepo.findByPost(post, pageable); + + List commentDTOs = commentPage.stream().map(comment -> { + CommentDTO dto = new CommentDTO(); + UserDTO userDTO = new UserDTO(); + userDTO.setId(comment.getUser().getUserId()); + userDTO.setUsername(comment.getUser().getUsername()); + userDTO.setDisplayName(comment.getUser().getFirstName()); + userDTO.setAvatarUrl(comment.getUser().getAvatarUrl()); + dto.setCommentId(comment.getCommentId()); + dto.setUser(userDTO); + dto.setContent(comment.getContent()); + dto.setCreatedAt(comment.getCreatedAt()); + return dto; + }).toList(); + + Map response = new HashMap<>(); + response.put("comments", commentDTOs); + response.put("hasNext", commentPage.hasNext()); + response.put("nextPage", page + 1); + + return ResponseEntity.ok(response); + } + + + // 2. Get reaction counts for a specific post + @GetMapping("/{postId}/reactions") + public ResponseEntity> getReactionCounts(@PathVariable String postId) { + Post post = postRepo.findByPostId(postId); + if (post == null) { + return ResponseEntity.notFound().build(); + } + + Map counts = reactionService.getReactionCounts(post); + return ResponseEntity.ok(counts); + } + + // 3. Add reactions for a post + @PostMapping("/{postId}/react") + public ResponseEntity addOrUpdateReaction(@PathVariable String postId, + @RequestParam String userId, + @RequestParam ReactionType type) { + + Post post = postRepo.findByPostId(postId); + if (post == null) return ResponseEntity.notFound().build(); + System.out.println("UserID received: " + userId); + User user = userRepo.findByUserId(userId) + .orElseThrow(() -> new RuntimeException("User not found")); + + reactionService.reactToPost(post, user, type); + return ResponseEntity.ok().build(); + } + + // 4. Add comments to a post + @PostMapping("{postId}/comment") + public ResponseEntity addCommentToPost(@PathVariable String postId, + @RequestBody RequestCommentDTO requestDTO) { + log.info("PostId: {}, User: {}", postId, requestDTO.getUserId()); + Post post = postRepo.findByPostId(postId); + + if (post == null) return ResponseEntity.notFound().build(); + + User user = userRepo.findByUserId(requestDTO.getUserId()) + .orElseThrow(() -> new RuntimeException("User not found")); + + commentService.addComment(post, user, requestDTO.getContent()); + return ResponseEntity.ok().build(); + } + + // 5. Reply to a comment on a post + @PostMapping("/comments/{commentId}/reply") + public ResponseEntity replyToComment(@PathVariable String commentId, + @RequestBody ReplyCommentRequestDTO requestDTO) { + Comment parentComment = commentRepo.findById(commentId) + .orElseThrow(() -> new RuntimeException("Comment not found")); + + User user = userRepo.findByUserId(requestDTO.getUserId()) + .orElseThrow(() -> new RuntimeException("User not found")); + + Post post = parentComment.getPost(); + + commentService.replyToComment(parentComment, post, user, requestDTO.getContent()); + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/comments/{commentId}") + public ResponseEntity deleteComment( + @PathVariable String commentId, + @RequestParam String userId + ) { + log.info("CommentId: {}, UserId: {}", commentId, userId); + Comment comment = commentRepo.findById(commentId) + .orElseThrow(() -> new RuntimeException("Comment not found")); + +// log.info("Comment: {}", comment.toString()); + + if (!comment.getUser().getUserId().equals(userId)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + commentRepo.delete(comment); + return ResponseEntity.ok().build(); + } + + @PostMapping("/{postId}/bookmark") + public ResponseEntity addBookmark(@PathVariable String postId, @RequestParam String userId) { + log.info("PostId: {}, UserId: {}", postId, userId); + Post post = postRepo.findById(postId) + .orElseThrow(() -> new RuntimeException("Post not found with ID: " + postId)); + User user = userRepo.findById(userId) + .orElseThrow(() -> new RuntimeException("User not found with ID: " + userId)); + bookmarkService.toggleBookmark(user, post); + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/{postId}/bookmark") + public ResponseEntity removeBookmark(@PathVariable String postId, @RequestParam String userId) { + return addBookmark(postId, userId); // toggle logic is same + } + + @GetMapping("/{postId}/bookmark") + public ResponseEntity> checkBookmark(@PathVariable String postId, @RequestParam String userId) { + Post post = postRepo.findByPostId(postId); + log.info("Post id {}", postId); + if (post == null) { + throw new RuntimeException("Post not found"); + } + User user = userRepo.findByUserId(userId) + .orElseThrow(() -> new RuntimeException("User not found with ID: " + userId)); + + boolean isBookmarked = bookmarkService.isBookmarkedByUser(user, post); + return ResponseEntity.ok(Map.of("isBookmarkedByUser", isBookmarked)); + } + + @GetMapping("/bookmarked") + public ResponseEntity getBookmarkedPosts( + @RequestParam String userId, + @RequestParam(required = false) String cursor, + @RequestParam(defaultValue = "10") int size) { + + log.info(" Fetch bookmarked posts | UserId: {}, Cursor: {}, Size: {}", userId, cursor, size); + PostsPageDTO result = bookmarkService.getBookmarkedPosts(userId, cursor, size); + return ResponseEntity.ok(result); + } +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/controller/UserController.java b/social-media-service/src/main/java/com/example/socialmediaservice/controller/UserController.java new file mode 100644 index 0000000..ad8a4a3 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/controller/UserController.java @@ -0,0 +1,178 @@ +package com.example.socialmediaservice.controller; + +import com.example.socialmediaservice.dto.FollowerInfo; +import com.example.socialmediaservice.dto.LoginRequestDTO; +import com.example.socialmediaservice.dto.UpdateProfileRequest; +import com.example.socialmediaservice.dto.UpdateProfileResponse; +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.service.UserService; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletResponse; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +@RequestMapping("/api/users") +@RequiredArgsConstructor +@CrossOrigin(origins ={"http://localhost:3000", "https://go-together-uom.vercel.app"}, allowCredentials = "true") +public class UserController { + + private final UserService userService; + + @PostMapping("/auth/login") + public ResponseEntity login(@RequestBody LoginRequestDTO loginRequest, HttpServletResponse response) { + String token = userService.authenticateWithKeycloak(loginRequest.getUsername(), loginRequest.getPassword()); + User user = userService.getUserByEmailFromToken(token); // use Keycloak userinfo + user.setPosts(null); +// Set SameSite manually because Spring doesn't support it directly in ResponseCookie + String accessTokenHeader = ResponseCookie.from("access_token", token) + .httpOnly(true) + .secure(false) // <--- IMPORTANT for localhost! + .path("/") + .maxAge(3600) + .build().toString() + "; SameSite=Lax"; + + String userCookieHeader = ResponseCookie.from("user", serializeUser(user)) + .httpOnly(false) + .secure(false) // <--- Same + .path("/") + .maxAge(3600) + .build().toString() + "; SameSite=Lax"; + + response.addHeader(HttpHeaders.SET_COOKIE, accessTokenHeader); + response.addHeader(HttpHeaders.SET_COOKIE, userCookieHeader); + + log.info("User {} login successful", user.getUsername()); + log.info( serializeUser(user)); + + return ResponseEntity.ok(Map.of( + "accessToken", token, + "user", serializeUser(user) + )); + + } + + + @PostMapping("/register") + public User registerUser(@RequestBody RegisterRequest request) { + return userService.registerUser( + request.getUsername(), + request.getEmail(), + request.getPassword(), + request.getFirstName(), + request.getLastName() + ); + } + + @PutMapping("/{userId}/avatar") + public User updateAvatar(@PathVariable String userId, @RequestBody AvatarUpdateRequest request) { + return userService.updateAvatar(userId, request.getAvatarUrl()); + } + +// @CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true") + @GetMapping("/email/{email}") + public ResponseEntity getUserByEmail(@PathVariable String email) { + if (email == null || email.isBlank()) { + throw new IllegalArgumentException("Email path variable is missing"); + } + User user = userService.getUserByEmail(email); + return ResponseEntity.ok(user); + } + + @GetMapping("/{userId}") + public ResponseEntity getUserById(@PathVariable String userId) { + if (userId == null || userId.isBlank()) { + throw new IllegalArgumentException("UserId path variable is missing"); + } + User user = userService.getUserById(userId); // โœ… now it's consistent + return ResponseEntity.ok(user); + } + + @GetMapping("/username/{username}") + public ResponseEntity getUserByUsername(@PathVariable String username) { + User user = userService.getUserByUsername(username); + return ResponseEntity.ok(user); + } + + @PutMapping("/{userId}/profile") + public ResponseEntity updateUserProfile( + @PathVariable String userId, + @RequestBody UpdateProfileRequest request + ) { + UpdateProfileResponse updated = userService.updateUserProfile(userId, request); + return ResponseEntity.ok(updated); + } + + @Data + static class RegisterRequest { + private String username; + private String email; + private String password; + private String firstName; + private String lastName; + } + + @Data + static class AvatarUpdateRequest { + private String avatarUrl; + } + + @PostMapping("/{targetUserId}/followers") + public ResponseEntity followUser( + @PathVariable String targetUserId, + @RequestParam String followerUserId + ) { + userService.followUser(followerUserId, targetUserId); + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/{targetUserId}/followers") + public ResponseEntity unfollowUser( + @PathVariable String targetUserId, + @RequestParam String followerUserId + ) { + userService.unfollowUser(followerUserId, targetUserId); + return ResponseEntity.ok().build(); + } + + @GetMapping("/{targetUserId}/follower-info") + public ResponseEntity getFollowerInfo( + @PathVariable String targetUserId, + @RequestParam String currentUserId + ) { + FollowerInfo info = userService.getFollowerInfo(currentUserId, targetUserId); + return ResponseEntity.ok(info); + } + public String serializeUser(User user) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + Map minimalUser = new HashMap<>(); + minimalUser.put("userId", user.getUserId()); + minimalUser.put("username", user.getUsername()); + minimalUser.put("firstName", user.getFirstName()); + minimalUser.put("avatarUrl", user.getAvatarUrl()); + + String json = objectMapper.writeValueAsString(minimalUser); + return Base64.getUrlEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8)); + } catch (JsonProcessingException e) { + throw new RuntimeException("Failed to serialize user for cookie", e); + } + } + + } + + + + diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/CommentDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/CommentDTO.java new file mode 100644 index 0000000..b6201de --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/CommentDTO.java @@ -0,0 +1,16 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class CommentDTO { + private String commentId; + private UserDTO user; + private String content; + private LocalDateTime createdAt; + private String parentCommentId; + private List replies; // nested replies +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/CreatePostRequestDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/CreatePostRequestDTO.java new file mode 100644 index 0000000..25c6c82 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/CreatePostRequestDTO.java @@ -0,0 +1,12 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class CreatePostRequestDTO { + private String caption; + private String email; + private List mediaIds; // Optional list of media IDs (UUID strings) +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/CreatePostResponseDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/CreatePostResponseDTO.java new file mode 100644 index 0000000..ce2a5d4 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/CreatePostResponseDTO.java @@ -0,0 +1,20 @@ +package com.example.socialmediaservice.dto; + +import com.example.socialmediaservice.enums.ReactionType; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Data +public class CreatePostResponseDTO { + private String postId; + private String caption; + private String userId; + private String username; + private LocalDateTime createdAt; + private List media; + private List comments; + private Map reactionCounts; +} \ No newline at end of file diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/FollowerInfo.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/FollowerInfo.java new file mode 100644 index 0000000..8c1f008 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/FollowerInfo.java @@ -0,0 +1,13 @@ +package com.example.socialmediaservice.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class FollowerInfo { + private int followers; + private boolean isFollowedByUser; +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/LoginRequestDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/LoginRequestDTO.java new file mode 100644 index 0000000..2407e70 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/LoginRequestDTO.java @@ -0,0 +1,10 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; + +@Data +public class LoginRequestDTO { + private String username; + private String password; +} + diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/MediaCreateRequestDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/MediaCreateRequestDTO.java new file mode 100644 index 0000000..04f761e --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/MediaCreateRequestDTO.java @@ -0,0 +1,10 @@ +package com.example.socialmediaservice.dto; + +import com.example.socialmediaservice.enums.MediaType; +import lombok.Data; + +@Data +public class MediaCreateRequestDTO { + private String url; + private MediaType type; // IMAGE or VIDEO +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/MediaDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/MediaDTO.java new file mode 100644 index 0000000..18682ca --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/MediaDTO.java @@ -0,0 +1,11 @@ +package com.example.socialmediaservice.dto; + +import com.example.socialmediaservice.enums.MediaType; +import lombok.Data; + +@Data +public class MediaDTO { + private String id; + private String url; + private MediaType type; // IMAGE or VIDEO +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/PostDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/PostDTO.java new file mode 100644 index 0000000..c1a3e08 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/PostDTO.java @@ -0,0 +1,42 @@ +package com.example.socialmediaservice.dto; + +import com.example.socialmediaservice.enums.MediaType; +import com.example.socialmediaservice.enums.ReactionType; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Data +public class PostDTO { + private String postId; + private String caption; + private LocalDateTime createdAt; + + private UserDTO user; + private List attachments; + private List comments; + private Map reactionCounts; + private List reactions; + private List bookmarks; + + private CountDTO _count; + + @Data + public static class CountDTO { + private int likes; + private int comments; + } + @Data + public static class UserIdDTO { + private String userId; + } + + @Data + public static class ReactionDTO { + private String userId; + private ReactionType reactionType; + } +} + diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/PostsPageDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/PostsPageDTO.java new file mode 100644 index 0000000..1a7dd0a --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/PostsPageDTO.java @@ -0,0 +1,11 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class PostsPageDTO { + private List posts; + private String nextCursor; +} \ No newline at end of file diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/ReactionDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/ReactionDTO.java new file mode 100644 index 0000000..cc4b0a1 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/ReactionDTO.java @@ -0,0 +1,10 @@ +package com.example.socialmediaservice.dto; + +import com.example.socialmediaservice.enums.ReactionType; +import lombok.Data; + +@Data +public class ReactionDTO { + private String userId; + private ReactionType type; +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.java new file mode 100644 index 0000000..84433ac --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/ReplyCommentRequestDTO.java @@ -0,0 +1,11 @@ +package com.example.socialmediaservice.dto; + + +import lombok.Data; + +@Data +public class ReplyCommentRequestDTO { + private String userId; + private String content; +} + diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/RequestCommentDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/RequestCommentDTO.java new file mode 100644 index 0000000..4eaea86 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/RequestCommentDTO.java @@ -0,0 +1,9 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; + +@Data +public class RequestCommentDTO { + private String userId; + private String content; +} \ No newline at end of file diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdatePostRequestDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdatePostRequestDTO.java new file mode 100644 index 0000000..e9d75c2 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdatePostRequestDTO.java @@ -0,0 +1,13 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@Data +@RequiredArgsConstructor +public class UpdatePostRequestDTO { + private String caption; + private List mediaIds; // Optional updates to media list +} \ No newline at end of file diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdateProfileRequest.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdateProfileRequest.java new file mode 100644 index 0000000..6329b2d --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdateProfileRequest.java @@ -0,0 +1,10 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; + +@Data +public class UpdateProfileRequest { + private String displayName; + private String bio; + private String avatarUrl; // optional +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdateProfileResponse.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdateProfileResponse.java new file mode 100644 index 0000000..242906c --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UpdateProfileResponse.java @@ -0,0 +1,14 @@ +package com.example.socialmediaservice.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class UpdateProfileResponse { + private String userId; + private String username; + private String displayName; + private String avatarUrl; + private String bio; +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/UserDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UserDTO.java new file mode 100644 index 0000000..81fbb4e --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UserDTO.java @@ -0,0 +1,11 @@ +package com.example.socialmediaservice.dto; + +import lombok.Data; + +@Data +public class UserDTO { + private String id; + private String username; + private String displayName; + private String avatarUrl; +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/dto/UserProfileDTO.java b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UserProfileDTO.java new file mode 100644 index 0000000..71edef7 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/dto/UserProfileDTO.java @@ -0,0 +1,4 @@ +package com.example.socialmediaservice.dto; + +public class UserProfileDTO { +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/entity/Bookmark.java b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Bookmark.java new file mode 100644 index 0000000..d66ad18 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Bookmark.java @@ -0,0 +1,39 @@ +package com.example.socialmediaservice.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.CreationTimestamp; + +import java.time.LocalDateTime; + + +@Entity +@Getter +@Setter +@NoArgsConstructor // required by JPA +@AllArgsConstructor +public class Bookmark { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + + @ManyToOne + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + private Post post; + + @CreationTimestamp + @Column(updatable = false) + private LocalDateTime createdAt; + + + // Optional: constructor without ID + public Bookmark(User user, Post post) { + this.user = user; + this.post = post; + } +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/entity/Comment.java b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Comment.java new file mode 100644 index 0000000..e788f3a --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Comment.java @@ -0,0 +1,41 @@ +package com.example.socialmediaservice.entity; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Data +@RequiredArgsConstructor +@Table(name = "comments") +public class Comment { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String commentId; + + @Column(nullable = false, columnDefinition = "TEXT") + private String content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id", nullable = false) + private Post post; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Column(name = "created_at") + private LocalDateTime createdAt = LocalDateTime.now(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_comment_id") + private Comment parentComment; + + @OneToMany(mappedBy = "parentComment", cascade = CascadeType.ALL, orphanRemoval = true) + private List replies = new ArrayList<>(); +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/entity/Media.java b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Media.java new file mode 100644 index 0000000..5208c96 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Media.java @@ -0,0 +1,30 @@ +package com.example.socialmediaservice.entity; + +import com.example.socialmediaservice.enums.MediaType; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Data +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "media") +public class Media { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + + @Column(nullable = false) + private String url; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private MediaType type; // IMAGE or VIDEO + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id") + private Post post; +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/entity/Post.java b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Post.java new file mode 100644 index 0000000..53459c5 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Post.java @@ -0,0 +1,43 @@ +package com.example.socialmediaservice.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Data +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "posts") +public class Post { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String postId; + + @Column(columnDefinition = "TEXT") + private String caption; // โœ… Optional description field + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Column(name = "created_at") + private LocalDateTime createdAt = LocalDateTime.now(); + + @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) + private List reactions = new ArrayList<>(); + + @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) + private List comments = new ArrayList<>(); + + @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) + private List mediaList = new ArrayList<>(); // โœ… List of attached media (images/videos) + + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/entity/Reaction.java b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Reaction.java new file mode 100644 index 0000000..a2a1ec7 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/entity/Reaction.java @@ -0,0 +1,30 @@ +package com.example.socialmediaservice.entity; + +import com.example.socialmediaservice.enums.ReactionType; +import jakarta.persistence.*; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@Entity +@Data +@RequiredArgsConstructor +@Table(name="reactions", uniqueConstraints = { + @UniqueConstraint(columnNames = {"post_id", "user_id"}) }) +public class Reaction { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Column(name = "reaction_id", updatable = false, nullable = false) + private String reactionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id", nullable = false) + private Post post; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private ReactionType type; +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/entity/User.java b/social-media-service/src/main/java/com/example/socialmediaservice/entity/User.java new file mode 100644 index 0000000..401c8f2 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/entity/User.java @@ -0,0 +1,56 @@ +package com.example.socialmediaservice.entity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.persistence.*; +import lombok.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Entity +@Getter +@Setter +@ToString(exclude = {"followers", "following"}) +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@Table(name = "users") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String userId; + + @Column(unique = true, nullable = false) + private String username; + + @Column(unique = true, nullable = true) + private String email; + + @Column(nullable = true) + private String firstName; + + @Column(nullable = true) + private String lastName; + + @Column(nullable = true, columnDefinition = "TEXT") + private String bio; + + @Column(nullable = true) + private String avatarUrl; + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonIgnoreProperties("user") // Prevent recursion during serialization + private List posts = new ArrayList<>(); + + @ElementCollection + @CollectionTable(name = "user_followers", joinColumns = @JoinColumn(name = "user_id")) + @Column(name = "follower_user_id") + private Set followerIds = new HashSet<>(); + + @ElementCollection + @CollectionTable(name = "user_following", joinColumns = @JoinColumn(name = "user_id")) + @Column(name = "following_user_id") + private Set followingIds = new HashSet<>(); + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/enums/MediaType.java b/social-media-service/src/main/java/com/example/socialmediaservice/enums/MediaType.java new file mode 100644 index 0000000..4f92813 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/enums/MediaType.java @@ -0,0 +1,6 @@ +package com.example.socialmediaservice.enums; + +public enum MediaType { + IMAGE, + VIDEO +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/enums/ReactionType.java b/social-media-service/src/main/java/com/example/socialmediaservice/enums/ReactionType.java new file mode 100644 index 0000000..33e36cc --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/enums/ReactionType.java @@ -0,0 +1,10 @@ +package com.example.socialmediaservice.enums; + +public enum ReactionType { + LIKE, + LOVE, + HAHA, + WOW, + SAD, + ANGRY +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/mapper/CommentMapper.java b/social-media-service/src/main/java/com/example/socialmediaservice/mapper/CommentMapper.java new file mode 100644 index 0000000..2ec524d --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/mapper/CommentMapper.java @@ -0,0 +1,28 @@ +package com.example.socialmediaservice.mapper; + + +import com.example.socialmediaservice.dto.CommentDTO; +import com.example.socialmediaservice.dto.UserDTO; +import com.example.socialmediaservice.entity.Comment; + +import java.util.stream.Collectors; + +public class CommentMapper { + + private CommentDTO toDtoWithReplies(Comment comment) { + CommentDTO dto = new CommentDTO(); + UserDTO userDTO = new UserDTO(); + userDTO.setId(comment.getUser().getUserId()); + userDTO.setUsername(comment.getUser().getUsername()); + userDTO.setDisplayName(comment.getUser().getFirstName()); + userDTO.setAvatarUrl(comment.getUser().getAvatarUrl()); + dto.setUser(userDTO); + dto.setContent(comment.getContent()); + dto.setCreatedAt(comment.getCreatedAt()); + dto.setReplies(comment.getReplies().stream() + .map(this::toDtoWithReplies) + .collect(Collectors.toList())); + return dto; + } + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/mapper/PostMapper.java b/social-media-service/src/main/java/com/example/socialmediaservice/mapper/PostMapper.java new file mode 100644 index 0000000..6a884aa --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/mapper/PostMapper.java @@ -0,0 +1,86 @@ +package com.example.socialmediaservice.mapper; + +import com.example.socialmediaservice.dto.CreatePostResponseDTO; +import com.example.socialmediaservice.dto.MediaDTO; +import com.example.socialmediaservice.dto.PostDTO; +import com.example.socialmediaservice.dto.UserDTO; +import com.example.socialmediaservice.entity.Media; +import com.example.socialmediaservice.entity.Post; + +import java.util.List; +import java.util.stream.Collectors; + +public class PostMapper { + public static CreatePostResponseDTO toDto(Post post) { + CreatePostResponseDTO dto = new CreatePostResponseDTO(); + dto.setPostId(post.getPostId()); + dto.setCaption(post.getCaption()); // Updated from content โ†’ caption + dto.setUserId(post.getUser().getUserId()); + dto.setUsername(post.getUser().getUsername()); + dto.setCreatedAt(post.getCreatedAt()); + + // Convert media list + dto.setMedia(post.getMediaList().stream() + .map(PostMapper::toMediaDto) + .collect(Collectors.toList())); + + return dto; + } + + private static MediaDTO toMediaDto(Media media) { + MediaDTO dto = new MediaDTO(); + dto.setId(media.getId()); + dto.setUrl(media.getUrl()); + dto.setType(media.getType()); + return dto; + } + + public static PostDTO toDto2(Post post) { + PostDTO dto = new PostDTO(); + dto.setPostId(post.getPostId()); + dto.setCaption(post.getCaption()); + dto.setCreatedAt(post.getCreatedAt()); + + // โœ… Set nested user + UserDTO userDTO = new UserDTO(); + userDTO.setId(post.getUser().getUserId()); + userDTO.setUsername(post.getUser().getUsername()); + userDTO.setDisplayName(post.getUser().getFirstName()); + userDTO.setAvatarUrl(post.getUser().getAvatarUrl()); + dto.setUser(userDTO); + + // โœ… Set attachments + if (post.getMediaList() != null) { + List attachments = post.getMediaList().stream() + .map(media -> { + MediaDTO mediaDTO = new MediaDTO(); + mediaDTO.setId(media.getId()); + mediaDTO.setUrl(media.getUrl()); + mediaDTO.setType(media.getType()); + return mediaDTO; + }).collect(Collectors.toList()); + dto.setAttachments(attachments); + } + + return dto; + } + + public static PostDTO toDTO(Post post) { + PostDTO dto = new PostDTO(); + dto.setPostId(post.getPostId()); + dto.setCaption(post.getCaption()); + dto.setCreatedAt(post.getCreatedAt()); + + UserDTO userDTO = new UserDTO(); + userDTO.setId(post.getUser().getUserId()); + userDTO.setUsername(post.getUser().getUsername()); + userDTO.setAvatarUrl(post.getUser().getAvatarUrl()); + dto.setUser(userDTO); + + // Optional: populate counts, reactions, attachments, etc. here + + return dto; + } + + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/repository/BookmarkRepository.java b/social-media-service/src/main/java/com/example/socialmediaservice/repository/BookmarkRepository.java new file mode 100644 index 0000000..230bd70 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/repository/BookmarkRepository.java @@ -0,0 +1,32 @@ +package com.example.socialmediaservice.repository; + +import com.example.socialmediaservice.entity.Bookmark; +import com.example.socialmediaservice.entity.Post; +import com.example.socialmediaservice.entity.User; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface BookmarkRepository extends JpaRepository { + Optional findByUserAndPost(User user, Post post); + @Query(""" + SELECT b FROM Bookmark b + WHERE b.user = :user + AND (:cursor IS NULL OR b.createdAt < (SELECT b2.createdAt FROM Bookmark b2 WHERE b2.post.postId = :cursor)) + ORDER BY b.createdAt DESC +""") + List findBookmarksByUser( + @Param("user") User user, + @Param("cursor") String cursor, + Pageable pageable + ); + List findAllByPost(Post post); + boolean existsByUserAndPost(User user, Post post); +} + diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/repository/CommentRepo.java b/social-media-service/src/main/java/com/example/socialmediaservice/repository/CommentRepo.java new file mode 100644 index 0000000..01a0418 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/repository/CommentRepo.java @@ -0,0 +1,16 @@ +package com.example.socialmediaservice.repository; + +import com.example.socialmediaservice.entity.Comment; +import com.example.socialmediaservice.entity.Post; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface CommentRepo extends JpaRepository { + List findByPost(Post post); + List findByPostAndParentCommentIsNull(Post post); + Page findByPost(Post post, Pageable pageable); + List findByParentComment(Comment parentComment); +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/repository/MediaRepo.java b/social-media-service/src/main/java/com/example/socialmediaservice/repository/MediaRepo.java new file mode 100644 index 0000000..c9c7060 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/repository/MediaRepo.java @@ -0,0 +1,7 @@ +package com.example.socialmediaservice.repository; + +import com.example.socialmediaservice.entity.Media; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MediaRepo extends JpaRepository { +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/repository/PostRepo.java b/social-media-service/src/main/java/com/example/socialmediaservice/repository/PostRepo.java new file mode 100644 index 0000000..be9ff03 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/repository/PostRepo.java @@ -0,0 +1,18 @@ +package com.example.socialmediaservice.repository; + +import com.example.socialmediaservice.entity.Post; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.springframework.data.domain.Pageable; + + +import java.util.List; + +@Repository +public interface PostRepo extends JpaRepository { + List findByUser_UserId(String userId); + Post findByPostId(String postId); + List findAllByOrderByCreatedAtDesc(Pageable pageable); + List findByPostIdLessThanOrderByCreatedAtDesc(String postId, Pageable pageable); + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/repository/ReactionRepo.java b/social-media-service/src/main/java/com/example/socialmediaservice/repository/ReactionRepo.java new file mode 100644 index 0000000..913eadb --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/repository/ReactionRepo.java @@ -0,0 +1,14 @@ +package com.example.socialmediaservice.repository; + +import com.example.socialmediaservice.entity.Post; +import com.example.socialmediaservice.entity.Reaction; +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.enums.ReactionType; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface ReactionRepo extends JpaRepository { + Optional findByPostAndUser(Post post, User user); + long countByPostAndType(Post post, ReactionType type); +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/repository/UserRepo.java b/social-media-service/src/main/java/com/example/socialmediaservice/repository/UserRepo.java new file mode 100644 index 0000000..24a50b9 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/repository/UserRepo.java @@ -0,0 +1,17 @@ +package com.example.socialmediaservice.repository; + +import com.example.socialmediaservice.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface UserRepo extends JpaRepository { + + Optional findByUserId(String userId); + Optional findByEmail(String username); + boolean existsByUsername(String username); + Optional findByUsername(String username); +// List findByUserProfile_PostId(String postId); +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/service/AuthService.java b/social-media-service/src/main/java/com/example/socialmediaservice/service/AuthService.java new file mode 100644 index 0000000..b4c365a --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/service/AuthService.java @@ -0,0 +1,187 @@ +package com.example.socialmediaservice.service; + +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.repository.UserRepo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +@Slf4j +public class AuthService { + + @Value("${keycloak.server-url}") + private String keycloakServerUrl; + + @Value("${keycloak.client-secret}") + private String keycloakClientSecret; + + private final UserService userService; // To interact with user data for non-auth specific lookups + private final UserRepo userRepository; // For direct DB access for auth-related user processing + private final WebClient.Builder webClientBuilder; + + // private final String keycloakUrl = "http://localhost:8081"; // Placeholder, ideally from config + + @lombok.Data + public static class TokenResponse { + private String access_token; + private String refresh_token; + private long expires_in; + // private String id_token; // Optional, can be added if needed later + + public String getAccessToken() { + return access_token; + } + + public String getRefreshToken() { + return refresh_token; + } + + public long getExpiresIn() { + return expires_in; + } + } + + public AuthService.TokenResponse loginWithPassword(String username, String password) { + WebClient webClient = webClientBuilder.build(); + + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("grant_type", "password"); + formData.add("client_id", "kong-oidc"); + formData.add("client_secret", keycloakClientSecret); // Move to env or config! + formData.add("username", username); + formData.add("password", password); + formData.add("scope", "openid profile email offline_access"); + + AuthService.TokenResponse tokenResponse = webClient.post() + .uri(keycloakServerUrl + "/protocol/openid-connect/token") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .bodyValue(formData) + .retrieve() + .bodyToMono(AuthService.TokenResponse.class) + .block(); + + if (tokenResponse == null || tokenResponse.getAccessToken() == null) { + throw new RuntimeException("Login failed: Unable to retrieve token details from Keycloak"); + } + + if (tokenResponse.getRefreshToken() == null) { + log.warn("Refresh token was not received from Keycloak for user {}. Check Keycloak client configuration for 'Use Refresh Tokens' and scope 'offline_access'.", username); + } + return tokenResponse; + } + + public AuthService.TokenResponse refreshAccessToken(String refreshToken) { + if (refreshToken == null || refreshToken.isEmpty()) { + throw new IllegalArgumentException("Refresh token cannot be null or empty."); + } + WebClient webClient = webClientBuilder.build(); + + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("grant_type", "refresh_token"); + formData.add("refresh_token", refreshToken); + formData.add("client_id", "kong-oidc"); + formData.add("client_secret", keycloakClientSecret); + + log.info("Attempting to refresh access token using refresh token (first 10 chars): {}", refreshToken.substring(0, Math.min(refreshToken.length(), 10))); + + AuthService.TokenResponse tokenResponse = webClient.post() + .uri(keycloakServerUrl + "/protocol/openid-connect/token") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .bodyValue(formData) + .retrieve() + .onStatus( + status -> status.is4xxClientError() || status.is5xxServerError(), + clientResponse -> clientResponse.bodyToMono(String.class) + .flatMap(errorBody -> { + log.error("Keycloak refresh token request failed with status {}: {}", clientResponse.statusCode(), errorBody); + return Mono.error(new RuntimeException("Failed to refresh token. Status: " + clientResponse.statusCode() + ", Body: " + errorBody)); + }) + ) + .bodyToMono(AuthService.TokenResponse.class) + .doOnError(error -> log.error("Error during token refresh WebClient call: {}", error.getMessage())) + .block(); + + if (tokenResponse == null || tokenResponse.getAccessToken() == null) { + throw new RuntimeException("Token refresh failed: Did not receive a new access token from Keycloak."); + } + + log.info("Access token refreshed successfully. New access token expires in: {}s", tokenResponse.getExpiresIn()); + if (tokenResponse.getRefreshToken() != null) { + log.info("Keycloak returned a new refresh token (rotation might be on)."); + } else { + log.info("Keycloak did not return a new refresh token (existing one should still be valid if not expired)."); + } + return tokenResponse; + } + + public Map processOAuth2Login(OAuth2User oauth2User) { + if (oauth2User == null) { + throw new IllegalArgumentException("OAuth2User cannot be null"); + } + String email = oauth2User.getAttribute("email"); + if (email == null || email.isEmpty()) { + throw new RuntimeException("Email not found in OAuth2 user attributes"); + } + + User user = userRepository.findByEmail(email) + .orElseGet(() -> { + User newUser = new User(); + newUser.setUserId(UUID.randomUUID().toString()); + newUser.setEmail(email); + newUser.setUsername(oauth2User.getAttribute("email")); + newUser.setFirstName(oauth2User.getAttribute("given_name")); + newUser.setLastName(oauth2User.getAttribute("family_name")); + newUser.setAvatarUrl(oauth2User.getAttribute("picture")); +// newUser.setEnabled(true); + return userRepository.save(newUser); + }); + + String token; // Placeholder logic from original method + if (oauth2User instanceof org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken) { + log.warn("Token generation/retrieval in processOAuth2Login is a placeholder. Integrate properly with Spring Security OAuth2 to get the Keycloak token."); + token = "NEEDS-ACTUAL-KEYCLOAK-TOKEN-FOR-" + user.getEmail(); + } else { + log.warn("OAuth2User is not an instance of OAuth2AuthenticationToken. Token retrieval might fail."); + token = "FALLBACK-TOKEN-" + user.getEmail(); + } + + Map authResponse = new HashMap<>(); + authResponse.put("token", token); + authResponse.put("user", user); + + log.info("Processed OAuth2 login for user: {}", user.getEmail()); + return authResponse; + } + + public User getUserByEmailFromToken(String accessToken) { + WebClient webClient = webClientBuilder.build(); + Map userInfo = webClient.get() + .uri(keycloakServerUrl + "/protocol/openid-connect/userinfo") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken) + .retrieve() + .bodyToMono(new ParameterizedTypeReference>() {}) + .block(); + + if (userInfo == null || !userInfo.containsKey("email")) { + throw new RuntimeException("Failed to fetch user info from Keycloak"); + } + String email = userInfo.get("email").toString(); + // Call UserService for the actual lookup, as getUserByEmail is a general user service method + return userService.getUserByEmail(email); + } +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/service/BookmarkService.java b/social-media-service/src/main/java/com/example/socialmediaservice/service/BookmarkService.java new file mode 100644 index 0000000..ed7ac86 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/service/BookmarkService.java @@ -0,0 +1,110 @@ +package com.example.socialmediaservice.service; + +import com.example.socialmediaservice.dto.CommentDTO; +import com.example.socialmediaservice.dto.PostDTO; +import com.example.socialmediaservice.dto.PostsPageDTO; +import com.example.socialmediaservice.dto.UserDTO; +import com.example.socialmediaservice.entity.Bookmark; +import com.example.socialmediaservice.entity.Post; +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.mapper.PostMapper; +import com.example.socialmediaservice.repository.BookmarkRepository; +import com.example.socialmediaservice.repository.UserRepo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class BookmarkService { + private final BookmarkRepository bookmarkRepository; + private final UserRepo userRepo; + private final CommentService commentService; + private final ReactionService reactionService; + + public void toggleBookmark(User user, Post post) { + bookmarkRepository.findByUserAndPost(user, post).ifPresentOrElse( + bookmark -> bookmarkRepository.delete(bookmark), + () -> bookmarkRepository.save(new Bookmark( user, post)) + ); + } + + public boolean isBookmarkedByUser(User user, Post post) { + log.info("User: {} | Post: {}", user.getUserId(), post.getPostId()); + boolean isBookmarked = bookmarkRepository.existsByUserAndPost(user, post); + log.info("Is bookmarked: {}", isBookmarked); + return isBookmarked; + } + + public PostsPageDTO getBookmarkedPosts(String userId, String cursor, int size) { + User user = userRepo.findByUserId(userId) + .orElseThrow(() -> new RuntimeException("User not found")); + + Pageable pageable = PageRequest.of(0, size + 1); // fetch one extra to check hasNext + List bookmarks = bookmarkRepository.findBookmarksByUser(user, cursor, pageable); + + List posts = bookmarks.stream() + .map(Bookmark::getPost) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + boolean hasNext = posts.size() > size; + if (hasNext) { + posts = posts.subList(0, size); + } + + List postDTOs = posts.stream().map(post -> { + PostDTO dto = PostMapper.toDto2(post); // Assuming similar to toDTO + + dto.setComments(commentService.getCommentsByPost(post).stream().map(comment -> { + UserDTO userDTO = new UserDTO(); + userDTO.setId(comment.getUser().getUserId()); + userDTO.setUsername(comment.getUser().getUsername()); + userDTO.setDisplayName(comment.getUser().getFirstName()); + userDTO.setAvatarUrl(comment.getUser().getAvatarUrl()); + + CommentDTO c = new CommentDTO(); + c.setUser(userDTO); + c.setContent(comment.getContent()); + c.setCreatedAt(comment.getCreatedAt()); + return c; + }).collect(Collectors.toList())); + + dto.setReactionCounts(reactionService.getReactionCounts(post)); + + PostDTO.CountDTO count = new PostDTO.CountDTO(); + count.setLikes(0); // You can replace with actual counts if available + count.setComments(0); + dto.set_count(count); + + dto.setReactions(post.getReactions() != null ? + post.getReactions().stream().map(reaction -> { + PostDTO.ReactionDTO r = new PostDTO.ReactionDTO(); + r.setUserId(reaction.getUser().getUserId()); + r.setReactionType(reaction.getType()); // Assuming Reaction entity has getType() + return r; + }).collect(Collectors.toList()) + : List.of() + ); + + return dto; + }).collect(Collectors.toList()); + + PostsPageDTO page = new PostsPageDTO(); + page.setPosts(postDTOs); + page.setNextCursor(hasNext ? postDTOs.get(postDTOs.size() - 1).getPostId() : null); + + return page; + } + + public List getBookmarksByPost(Post post) { + return bookmarkRepository.findAllByPost(post); // or a custom query + } +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/service/CommentService.java b/social-media-service/src/main/java/com/example/socialmediaservice/service/CommentService.java new file mode 100644 index 0000000..38c9587 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/service/CommentService.java @@ -0,0 +1,49 @@ +package com.example.socialmediaservice.service; + +import com.example.socialmediaservice.entity.Comment; +import com.example.socialmediaservice.entity.Post; +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.repository.CommentRepo; +import lombok.RequiredArgsConstructor; + +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class CommentService { + + private final CommentRepo commentRepo; + + public Comment addComment(Post post, User user, String content, Comment parentComment) { + Comment comment = new Comment(); + comment.setPost(post); + comment.setUser(user); + comment.setContent(content); + comment.setParentComment(parentComment); + return commentRepo.save(comment); + } + + public Comment addComment(Post post, User user, String content) { + return addComment(post, user, content, null); + } + + public List getCommentsByPost(Post post) { + return commentRepo.findByPost(post); + } + + public List getRepliesByParentComment(Comment parentComment) { + return commentRepo.findByParentComment(parentComment); + } + + public Comment replyToComment(Comment parentComment, Post post, User user, String content) { + Comment reply = new Comment(); + reply.setParentComment(parentComment); + reply.setPost(post); + reply.setUser(user); + reply.setContent(content); + return commentRepo.save(reply); + } + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/service/MediaService.java b/social-media-service/src/main/java/com/example/socialmediaservice/service/MediaService.java new file mode 100644 index 0000000..23525aa --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/service/MediaService.java @@ -0,0 +1,27 @@ +package com.example.socialmediaservice.service; + +import com.example.socialmediaservice.entity.Media; +import com.example.socialmediaservice.enums.MediaType; +import com.example.socialmediaservice.repository.MediaRepo; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class MediaService { + + private final MediaRepo mediaRepo; + + public Media createMedia(String url, MediaType type) { + Media media = new Media(); + media.setUrl(url); + media.setType(type); + return mediaRepo.save(media); + } + + public Optional getMediaById(String id) { + return mediaRepo.findById(id); + } +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/service/PostService.java b/social-media-service/src/main/java/com/example/socialmediaservice/service/PostService.java new file mode 100644 index 0000000..55221b1 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/service/PostService.java @@ -0,0 +1,248 @@ +package com.example.socialmediaservice.service; + + +import com.example.socialmediaservice.dto.*; +import com.example.socialmediaservice.entity.*; +import com.example.socialmediaservice.enums.ReactionType; +import com.example.socialmediaservice.mapper.PostMapper; +import com.example.socialmediaservice.repository.PostRepo; +import com.example.socialmediaservice.repository.UserRepo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PostService { + + private final PostRepo postRepo; + private final UserRepo userRepo; + private final ReactionService reactionService; + private final CommentService commentService; + private final BookmarkService bookmarkService; + + + // 1. Create Post + public CreatePostResponseDTO createPost(String email, CreatePostRequestDTO createPostRequestDTO) { + log.info("email: {} | caption: {}", email, createPostRequestDTO.getCaption()); + + User user = userRepo.findByEmail(email) + .orElseThrow(() -> new RuntimeException("User not found")); + + Post post = new Post(); + post.setCaption(createPostRequestDTO.getCaption()); + post.setUser(user); + + // Link media if provided + if (createPostRequestDTO.getMediaIds() != null && !createPostRequestDTO.getMediaIds().isEmpty()) { + List mediaList = createPostRequestDTO.getMediaIds().stream() + .map(id -> { + Media media = new Media(); + media.setId(id); + media.setPost(post); // Set the back-reference + return media; + }) + .collect(Collectors.toList()); + post.setMediaList(mediaList); + } + + postRepo.save(post); + + return PostMapper.toDto(post); + } + + + public List getPostsByUser(String userId) { + return postRepo.findByUser_UserId(userId).stream() + .map(post -> { + PostDTO dto = PostMapper.toDto2(post); + + UserDTO user = new UserDTO(); + user.setId(post.getUser().getUserId()); + user.setUsername(post.getUser().getUsername()); + user.setDisplayName(post.getUser().getFirstName()); + user.setAvatarUrl(post.getUser().getAvatarUrl()); + + // Add comments + dto.setComments(commentService.getCommentsByPost(post).stream().map(comment -> { + CommentDTO c = new CommentDTO(); + c.setUser(user); + c.setContent(comment.getContent()); + c.setCreatedAt(comment.getCreatedAt()); + return c; + }).collect(Collectors.toList())); + + // Add reaction counts + dto.setReactionCounts(reactionService.getReactionCounts(post)); + + return dto; + }) + .collect(Collectors.toList()); + } + + + public PostDTO getPostById(String postId) { + Post post = postRepo.findByPostId(postId); + if (post == null) throw new RuntimeException("Post not found"); + + PostDTO postDTO = PostMapper.toDto2(post); + + // Fetch all comments for the post + List allComments = commentService.getCommentsByPost(post); + + // Group comments by parent + Map> repliesGroupedByParentId = allComments.stream() + .filter(c -> c.getParentComment() != null) + .collect(Collectors.groupingBy(c -> c.getParentComment().getCommentId())); + + // Filter top-level comments + List topLevelComments = allComments.stream() + .filter(c -> c.getParentComment() == null) + .collect(Collectors.toList()); + + // Map top-level comments and recursively add replies + List commentDTOs = topLevelComments.stream() + .map(comment -> mapCommentWithReplies(comment, repliesGroupedByParentId)) + .collect(Collectors.toList()); + + postDTO.setComments(commentDTOs); + + // Set reaction counts + Map reactionCounts = reactionService.getReactionCounts(post); + postDTO.setReactionCounts(reactionCounts); + + return postDTO; + } + + private CommentDTO mapCommentWithReplies(Comment comment, Map> repliesGroupedByParentId) { + UserDTO userDTO = new UserDTO(); + userDTO.setId(comment.getUser().getUserId()); + userDTO.setUsername(comment.getUser().getUsername()); + userDTO.setDisplayName(comment.getUser().getFirstName()); + userDTO.setAvatarUrl(comment.getUser().getAvatarUrl()); + CommentDTO dto = new CommentDTO(); + dto.setUser(userDTO); + dto.setContent(comment.getContent()); + dto.setCreatedAt(comment.getCreatedAt()); + dto.setParentCommentId(comment.getParentComment() != null ? comment.getParentComment().getCommentId() : null); + + List replies = repliesGroupedByParentId.get(comment.getCommentId()); + if (replies != null && !replies.isEmpty()) { + List replyDTOs = replies.stream() + .map(reply -> mapCommentWithReplies(reply, repliesGroupedByParentId)) // Recursive + .collect(Collectors.toList()); + dto.setReplies(replyDTOs); + } + + return dto; + } + + + + //4. Update post content + public PostDTO updatePost(String postId, UpdatePostRequestDTO requestDTO) { + Post post = postRepo.findByPostId(postId); + if (post == null) throw new RuntimeException("Post not found"); + + post.setCaption(requestDTO.getCaption()); + + // Replace media list if provided + if (requestDTO.getMediaIds() != null) { + List updatedMediaList = requestDTO.getMediaIds().stream() + .map(id -> { + Media media = new Media(); + media.setId(id); + media.setPost(post); + return media; + }) + .collect(Collectors.toList()); + post.setMediaList(updatedMediaList); + } + + Post updatedPost = postRepo.save(post); + return PostMapper.toDto2(updatedPost); + } + + + public PostsPageDTO getForYouFeed(String cursor, int size) { + // Assuming cursor = postId of the last post from previous page + List posts; + + if (cursor != null && !cursor.isBlank()) { + posts = postRepo.findByPostIdLessThanOrderByCreatedAtDesc(cursor, PageRequest.of(0, size + 1)); + } else { + posts = postRepo.findAllByOrderByCreatedAtDesc(PageRequest.of(0, size + 1)); + } + + boolean hasNext = posts.size() > size; + if (hasNext) { + posts = posts.subList(0, size); + } + + List postDTOs = posts.stream().map(post -> { + PostDTO dto = PostMapper.toDto2(post); + + // Get comments + List commentDTOs = commentService.getCommentsByPost(post).stream().map(comment -> { + UserDTO userDTO = new UserDTO(); + userDTO.setId(comment.getUser().getUserId()); + userDTO.setUsername(comment.getUser().getUsername()); + userDTO.setDisplayName(comment.getUser().getFirstName()); + userDTO.setAvatarUrl(comment.getUser().getAvatarUrl()); + + CommentDTO commentDTO = new CommentDTO(); + commentDTO.setUser(userDTO); + commentDTO.setContent(comment.getContent()); + commentDTO.setCreatedAt(comment.getCreatedAt()); + return commentDTO; + }).collect(Collectors.toList()); + dto.setComments(commentDTOs); + + // Reactions + Map reactionCounts = reactionService.getReactionCounts(post); + dto.setReactionCounts(reactionCounts); + + // Set flat list of users who reacted + dto.setReactions(post.getReactions() != null ? + post.getReactions().stream().map(reaction -> { + PostDTO.ReactionDTO r = new PostDTO.ReactionDTO(); + r.setUserId(reaction.getUser().getUserId()); + r.setReactionType(reaction.getType()); // Assuming Reaction entity has getType() + return r; + }).collect(Collectors.toList()) + : List.of() + ); + + // Bookmarks (from bookmarkService, since Post doesn't have them) + List bookmarks = bookmarkService.getBookmarksByPost(post); // โ† you must implement this + dto.setBookmarks(bookmarks != null ? + bookmarks.stream().map(bookmark -> { + PostDTO.UserIdDTO b = new PostDTO.UserIdDTO(); + b.setUserId(bookmark.getUser().getUserId()); + return b; + }).collect(Collectors.toList()) + : List.of() + ); + + PostDTO.CountDTO count = new PostDTO.CountDTO(); + count.setLikes(0); + count.setComments(commentDTOs.size()); + dto.set_count(count); + + return dto; + }).collect(Collectors.toList()); + + PostsPageDTO page = new PostsPageDTO(); + page.setPosts(postDTOs); + page.setNextCursor(hasNext ? postDTOs.get(postDTOs.size() - 1).getPostId() : null); + + return page; + } + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/service/ReactionService.java b/social-media-service/src/main/java/com/example/socialmediaservice/service/ReactionService.java new file mode 100644 index 0000000..0041128 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/service/ReactionService.java @@ -0,0 +1,47 @@ +package com.example.socialmediaservice.service; + +import com.example.socialmediaservice.entity.Post; +import com.example.socialmediaservice.entity.Reaction; +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.enums.ReactionType; +import com.example.socialmediaservice.repository.ReactionRepo; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.EnumMap; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class ReactionService { + + private final ReactionRepo reactionRepo; + + public void reactToPost(Post post, User user, ReactionType type) { + Reaction existing = reactionRepo.findByPostAndUser(post, user).orElse(null); + + if (existing != null) { + if (existing.getType() == type) { + reactionRepo.delete(existing); // toggle + } else { + existing.setType(type); // change reaction + reactionRepo.save(existing); + } + } else { + Reaction reaction = new Reaction(); + reaction.setPost(post); + reaction.setUser(user); + reaction.setType(type); + reactionRepo.save(reaction); + } + } + + public Map getReactionCounts(Post post) { + Map map = new EnumMap<>(ReactionType.class); + for (ReactionType type : ReactionType.values()) { + map.put(type, reactionRepo.countByPostAndType(post, type)); + } + return map; + } + +} diff --git a/social-media-service/src/main/java/com/example/socialmediaservice/service/UserService.java b/social-media-service/src/main/java/com/example/socialmediaservice/service/UserService.java new file mode 100644 index 0000000..b9483d2 --- /dev/null +++ b/social-media-service/src/main/java/com/example/socialmediaservice/service/UserService.java @@ -0,0 +1,283 @@ +package com.example.socialmediaservice.service; + +import com.example.socialmediaservice.dto.FollowerInfo; +import com.example.socialmediaservice.dto.UpdateProfileRequest; +import com.example.socialmediaservice.dto.UpdateProfileResponse; +import com.example.socialmediaservice.entity.User; +import com.example.socialmediaservice.repository.UserRepo; +import jakarta.persistence.EntityNotFoundException; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.MediaType; +import org.springframework.http.HttpHeaders; +import reactor.core.publisher.Mono; + +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepo userRepository; + private final WebClient.Builder webClientBuilder; + + private final String keycloakUrl = "http://auth-service:8080"; + private final String adminUsername = "admin"; + private final String adminPassword = "admin"; + + public User getUserByEmailFromToken(String accessToken) { + WebClient webClient = webClientBuilder.build(); + + Map userInfo = webClient.get() + .uri(keycloakUrl + "/realms/kong/protocol/openid-connect/userinfo") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken) + .retrieve() + .bodyToMono(new ParameterizedTypeReference>() {}) + .block(); + + if (userInfo == null || !userInfo.containsKey("email")) { + throw new RuntimeException("Failed to fetch user info from Keycloak"); + } + + String email = userInfo.get("email").toString(); + return getUserByEmail(email); + } + + public String authenticateWithKeycloak(String username, String password) { + WebClient webClient = webClientBuilder.build(); + + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("grant_type", "password"); + formData.add("client_id", "kong-oidc"); + formData.add("client_secret", "fBHJFdikM0ERtTXnvebguHRz6iPUfJfV"); // Move to env or config! + formData.add("username", username); + formData.add("password", password); + formData.add("scope", "openid profile email"); + + TokenResponse tokenResponse = webClient.post() + .uri(keycloakUrl + "/realms/kong/protocol/openid-connect/token") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .bodyValue(formData) + .retrieve() + .bodyToMono(TokenResponse.class) + .block(); + + if (tokenResponse == null || tokenResponse.getAccessToken() == null) { + throw new RuntimeException("Login failed: Unable to retrieve access token from Keycloak"); + } + + return tokenResponse.getAccessToken(); + } + + + @Transactional + public User registerUser(String username, String email, String password,String firstName,String lastName) { + if (userRepository.existsByUsername(username)) { + throw new RuntimeException("Username already exists"); + } + + User user = new User(); + user.setUsername(username); + user.setFirstName(firstName); + user.setLastName(lastName); + user.setEmail(email); + + userRepository.save(user); + + createUserInKeycloak(username, email, password,firstName,lastName); + + return user; + } + + private void createUserInKeycloak(String username, String email, String password, String firstName, String lastName) { + String adminToken = getAdminAccessToken(); + + WebClient webClient = webClientBuilder.build(); + + var response = webClient.post() + .uri(keycloakUrl + "/admin/realms/kong/users") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(new KeycloakUserRequest(username, email, password, firstName, lastName)) + .retrieve() + .toBodilessEntity() + .block(); + + if (response == null || !response.getStatusCode().is2xxSuccessful()) { + throw new RuntimeException("Failed to create user in Keycloak"); + } + } + + public User updateAvatar(String userId, String avatarUrl) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException("User not found with ID: " + userId)); + user.setAvatarUrl(avatarUrl); + return userRepository.save(user); + } + + private String getAdminAccessToken() { + WebClient webClient = webClientBuilder.build(); + + var tokenResponse = webClient.post() + .uri(keycloakUrl + "/realms/master/protocol/openid-connect/token") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .bodyValue("grant_type=password&client_id=admin-cli&username=" + adminUsername + "&password=" + adminPassword) + .retrieve() + .bodyToMono(TokenResponse.class) + .block(); + + if (tokenResponse == null || tokenResponse.getAccessToken() == null) { + throw new RuntimeException("Failed to authenticate with Keycloak"); + } + + return tokenResponse.getAccessToken(); + } + + @lombok.Data + static class TokenResponse { + private String access_token; + public String getAccessToken() { + return access_token; + } + } + + @lombok.Data + static class KeycloakUserRequest { + private String username; + private String email; + private String firstName; + private String lastName; + private boolean enabled = true; + private boolean emailVerified = true; + private Credential[] credentials; + + public KeycloakUserRequest(String username, String email, String password,String firstName,String lastName) { + this.username = username; + this.email = email; + this.firstName = firstName; + this.lastName = lastName; + this.credentials = new Credential[] { new Credential(password) }; + } + + @lombok.Data + static class Credential { + private String type = "password"; + private String value; + private boolean temporary = false; + + public Credential(String value) { + this.value = value; + } + } + } + + public User getUserByEmail(String email) { + User user = userRepository.findByEmail(email) + .orElseThrow(() -> new EntityNotFoundException("User not found with email: " + email)); + user.setPosts(null); + return user; + } + public User getUserById(String userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException("User not found with ID: " + userId)); + user.setPosts(null); + return user; + } + + + public UpdateProfileResponse updateUserProfile(String userId, UpdateProfileRequest request) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException("User not found")); + + if (request.getDisplayName() != null) { + user.setFirstName(request.getDisplayName()); // โœ… assuming 'firstName' is your displayName + } + if (request.getBio() != null) { + user.setBio(request.getBio()); + } + if (request.getAvatarUrl() != null) { + user.setAvatarUrl(request.getAvatarUrl()); + } + + User saved = userRepository.save(user); + return new UpdateProfileResponse( + saved.getUserId(), + saved.getUsername(), + saved.getFirstName(), + saved.getAvatarUrl(), + saved.getBio() + ); + } + + + public User getUserByUsername(String username) { + return userRepository.findByUsername(username) + .orElseThrow(() -> new EntityNotFoundException("User not found with username: " + username)); + } + + @Transactional + public void followUser(String followerId, String targetUserId) { + if (followerId.equals(targetUserId)) { + throw new IllegalArgumentException("You cannot follow yourself."); + } + + User follower = userRepository.findByUserId(followerId) + .orElseThrow(() -> new RuntimeException("Follower not found")); + User target = userRepository.findByUserId(targetUserId) + .orElseThrow(() -> new RuntimeException("Target user not found")); + + boolean added = follower.getFollowingIds().add(targetUserId); + target.getFollowerIds().add(followerId); + + log.info("Added: {} | Target: {}", added, targetUserId); + log.info("Follower: {} | Target: {}", followerId, targetUserId); + log.info("Follower: {} | Target: {}", follower.getFollowingIds().toString(), target.getFollowerIds().toString() ); + + if (added) { + userRepository.save(follower); + userRepository.save(target); + } + } + + @Transactional + public void unfollowUser(String followerId, String targetUserId) { + if (followerId.equals(targetUserId)) { + throw new IllegalArgumentException("You cannot unfollow yourself."); + } + + User follower = userRepository.findByUserId(followerId) + .orElseThrow(() -> new RuntimeException("Follower not found")); + User target = userRepository.findByUserId(targetUserId) + .orElseThrow(() -> new RuntimeException("Target user not found")); + + boolean removedFromFollowing = follower.getFollowingIds().remove(targetUserId); + boolean removedFromFollowers = target.getFollowerIds().remove(followerId); + log.info("RemovedFromFollowing: {} | RemovedFromFollowers: {}", removedFromFollowing, removedFromFollowers); + log.info("Follower: {} | Target: {}", followerId, targetUserId); + log.info("Follower: {} | Target: {}", follower.getFollowingIds().toString(), target.getFollowerIds().toString() ); + + if (removedFromFollowing || removedFromFollowers) { + userRepository.save(follower); + userRepository.save(target); + } + } + + + public FollowerInfo getFollowerInfo(String currentUserId, String targetUserId) { + User target = userRepository.findByUserId(targetUserId) + .orElseThrow(() -> new RuntimeException("Target user not found")); + + boolean isFollowing = target.getFollowerIds().contains(currentUserId); + int count = target.getFollowerIds().size(); + + return new FollowerInfo(count, isFollowing); + } + +} diff --git a/social-media-service/src/main/resources/application.properties b/social-media-service/src/main/resources/application.properties new file mode 100644 index 0000000..da01b36 --- /dev/null +++ b/social-media-service/src/main/resources/application.properties @@ -0,0 +1,63 @@ +spring.application.name=social-media-service + +# Database configuration +#spring.datasource.url=${SPRING_DATASOURCE_URL} +spring.datasource.username=postgres.odffpjvuptssxaaggnsn +spring.datasource.password=Postgres + +#spring.datasource.username=${SPRING_DATASOURCE_USERNAME} +#spring.datasource.password=${SPRING_DATASOURCE_PASSWORD} + +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres?user=postgres.odffpjvuptssxaaggnsn&password=Postgres +#spring.jpa.hibernate.ddl-auto=none + +# JPA & Hibernate Configuration +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.show-sql=true + +logging.level.org.springframework.web.cors=DEBUG + +# Spring Security OAuth2 Client Configuration +# Assuming 'keycloak' is the registration ID for your Keycloak provider +# and Google is an identity provider within that Keycloak realm. + +# Provider details for Keycloak itself (acting as the OIDC provider to your app) +# spring.security.oauth2.client.provider.keycloak.issuer-uri=http://auth-service:8080/realms/kong +#spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8084/realms/kong +spring.security.oauth2.client.provider.keycloak.issuer-uri=https://gotogetheruom.duckdns.org:8446/realms/kong + + +# spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username # Adjust if needed based on Keycloak token claims + +# Client registration details for your application registered in Keycloak +spring.security.oauth2.client.registration.google.provider=keycloak +spring.security.oauth2.client.registration.google.client-id=${CLIENT_ID} +spring.security.oauth2.client.registration.google.client-secret=${CLIENT_SECRET} +spring.security.oauth2.client.registration.google.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.google.redirect-uri=https://gotogetheruom.duckdns.org/login/oauth2/code/keycloak +# spring.security.oauth2.client.registration.google.redirect-uri=http://localhost:8080/login/oauth2/code/google # Or be explicit if {baseUrl} is not set up +spring.security.oauth2.client.registration.google.scope=openid,profile,email +# The client-name is what might appear on a default login page if Spring generates one. +spring.security.oauth2.client.registration.google.client-name=Keycloa + +# Keycloak as the OIDC Provider +#spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8081/realms/kong + +# Your app registered in Keycloak (NOT Google) +# spring.security.oauth2.client.registration.keycloak.client-id=kong-oidc +# spring.security.oauth2.client.registration.keycloak.client-secret=fBHJFdikM0ERtTXnvebguHRz6iPUfJfV +# spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code +# spring.security.oauth2.client.registration.keycloak.redirect-uri=http://localhost:8080/login/oauth2/code/keycloak +# spring.security.oauth2.client.registration.keycloak.scope=openid,profile,email +# spring.security.oauth2.client.registration.keycloak.client-name=Keycloak + + +# Keycloak settings for AuthService +keycloak.server-url=http://auth-service:8080/realms/kong +#keycloak.server-url=http://localhost:8084/realms/kong +keycloak.client-secret=fBHJFdikM0ERtTXnvebguHRz6iPUfJfV + +logging.level.org.springframework.security=DEBUG +logging.level.org.springframework.security.oauth2=DEBUG diff --git a/social-media-service/src/test/java/com/example/socialmediaservice/SocialMediaServiceApplicationTests.java b/social-media-service/src/test/java/com/example/socialmediaservice/SocialMediaServiceApplicationTests.java new file mode 100644 index 0000000..0ebf651 --- /dev/null +++ b/social-media-service/src/test/java/com/example/socialmediaservice/SocialMediaServiceApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.socialmediaservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SocialMediaServiceApplicationTests { + + @Test + void contextLoads() { + } + +}