diff --git a/hiptershop-ecommerce/.gitignore b/hiptershop-ecommerce/.gitignore
new file mode 100644
index 000000000..601a6958a
--- /dev/null
+++ b/hiptershop-ecommerce/.gitignore
@@ -0,0 +1,11 @@
+bin/
+pkg/
+.DS_Store
+*.pyc
+*.swp
+*~
+.vscode/
+.vs/
+.idea
+.skaffold-*.yaml
+.kubernetes-manifests-*/
\ No newline at end of file
diff --git a/hiptershop-ecommerce/.travis.yml b/hiptershop-ecommerce/.travis.yml
new file mode 100644
index 000000000..124f5dd80
--- /dev/null
+++ b/hiptershop-ecommerce/.travis.yml
@@ -0,0 +1,12 @@
+sudo: required
+
+services:
+- docker
+
+install:
+- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.20.0/skaffold-linux-amd64
+- chmod +x skaffold
+- sudo mv skaffold /usr/local/bin
+
+script:
+- skaffold build --profile travis-ci
diff --git a/hiptershop-ecommerce/CONTRIBUTING.md b/hiptershop-ecommerce/CONTRIBUTING.md
new file mode 100644
index 000000000..1dce6116d
--- /dev/null
+++ b/hiptershop-ecommerce/CONTRIBUTING.md
@@ -0,0 +1,34 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Development Principles (for Googlers)
+
+There are a few principles for developing or refactoring the service
+implementations. Read the [Development Principles
+Guide](./docs/development-principles.md).
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
+
+## Community Guidelines
+
+This project follows [Google's Open Source Community
+Guidelines](https://opensource.google.com/conduct/).
diff --git a/hiptershop-ecommerce/LICENSE b/hiptershop-ecommerce/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/hiptershop-ecommerce/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/hiptershop-ecommerce/README.md b/hiptershop-ecommerce/README.md
new file mode 100644
index 000000000..05093c149
--- /dev/null
+++ b/hiptershop-ecommerce/README.md
@@ -0,0 +1,291 @@
+# Hipster Shop: Cloud-Native Microservices Demo Application
+
+This project contains a 10-tier microservices application. The application is a
+web-based e-commerce app called **“Hipster Shop”** where users can browse items,
+add them to the cart, and purchase them.
+
+**Google uses this application to demonstrate use of technologies like
+Kubernetes/GKE, Istio, Stackdriver, gRPC and OpenCensus**. This application
+works on any Kubernetes cluster (such as a local one), as well as Google
+Kubernetes Engine. It’s **easy to deploy with little to no configuration**.
+
+If you’re using this demo, please **★Star** this repository to show your interest!
+
+> 👓**Note to Googlers:** Please fill out the form at
+> [go/microservices-demo](http://go/microservices-demo) if you are using this
+> application.
+
+## Screenshots
+
+| Home Page | Checkout Screen |
+| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
+| [![Screenshot of store homepage](./docs/img/hipster-shop-frontend-1.png)](./docs/img/hipster-shop-frontend-1.png) | [![Screenshot of checkout screen](./docs/img/hipster-shop-frontend-2.png)](./docs/img/hipster-shop-frontend-2.png) |
+
+## Service Architecture
+
+**Hipster Shop** is composed of many microservices written in different
+languages that talk to each other over gRPC.
+
+[![Architecture of
+microservices](./docs/img/architecture-diagram.png)](./docs/img/architecture-diagram.png)
+
+Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb).
+
+| Service | Language | Description |
+| ---------------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
+| [frontend](./src/frontend) | Go | Exposes an HTTP server to serve the website. Does not require signup/login and generates session IDs for all users automatically. |
+| [cartservice](./src/cartservice) | C# | Stores the items in the user's shopping cart in Redis and retrieves it. |
+| [productcatalogservice](./src/productcatalogservice) | Go | Provides the list of products from a JSON file and ability to search products and get individual products. |
+| [currencyservice](./src/currencyservice) | Node.js | Converts one money amount to another currency. Uses real values fetched from European Central Bank. It's the highest QPS service. |
+| [paymentservice](./src/paymentservice) | Node.js | Charges the given credit card info (mock) with the given amount and returns a transaction ID. |
+| [shippingservice](./src/shippingservice) | Go | Gives shipping cost estimates based on the shopping cart. Ships items to the given address (mock) |
+| [emailservice](./src/emailservice) | Python | Sends users an order confirmation email (mock). |
+| [checkoutservice](./src/checkoutservice) | Go | Retrieves user cart, prepares order and orchestrates the payment, shipping and the email notification. |
+| [recommendationservice](./src/recommendationservice) | Python | Recommends other products based on what's given in the cart. |
+| [adservice](./src/adservice) | Java | Provides text ads based on given context words. |
+| [loadgenerator](./src/loadgenerator) | Python/Locust | Continuously sends requests imitating realistic user shopping flows to the frontend. |
+
+## Features
+
+- **[Kubernetes](https://kubernetes.io)/[GKE](https://cloud.google.com/kubernetes-engine/):**
+ The app is designed to run on Kubernetes (both locally on "Docker for
+ Desktop", as well as on the cloud with GKE).
+- **[gRPC](https://grpc.io):** Microservices use a high volume of gRPC calls to
+ communicate to each other.
+- **[Istio](https://istio.io):** Application works on Istio service mesh.
+- **[OpenCensus](https://opencensus.io/) Tracing:** Most services are
+ instrumented using OpenCensus trace interceptors for gRPC/HTTP.
+- **[Stackdriver APM](https://cloud.google.com/stackdriver/):** Many services
+ are instrumented with **Profiling**, **Tracing** and **Debugging**. In
+ addition to these, using Istio enables features like Request/Response
+ **Metrics** and **Context Graph** out of the box. When it is running out of
+ Google Cloud, this code path remains inactive.
+- **[Skaffold](https://skaffold.dev):** Application
+ is deployed to Kubernetes with a single command using Skaffold.
+- **Synthetic Load Generation:** The application demo comes with a background
+ job that creates realistic usage patterns on the website using
+ [Locust](https://locust.io/) load generator.
+
+## Installation
+
+We offer the following installation methods:
+
+1. **Running locally** (~20 minutes) You will build
+ and deploy microservices images to a single-node Kubernetes cluster running
+ on your development machine. There are two options to run a Kubernetes
+ cluster locally for this demo:
+ - [Minikube](https://github.com/kubernetes/minikube). Recommended for the
+ Linux hosts (also supports Mac/Windows).
+ - [Docker for Desktop](https://www.docker.com/products/docker-desktop).
+ Recommended for Mac/Windows.
+
+1. **Running on Google Kubernetes Engine (GKE)”** (~30 minutes) You will build,
+ upload and deploy the container images to a Kubernetes cluster on Google
+ Cloud.
+
+1. **Using pre-built container images:** (~10 minutes, you will still need to
+ follow one of the steps above up until `skaffold run` command). With this
+ option, you will use pre-built container images that are available publicly,
+ instead of building them yourself, which takes a long time).
+
+### Option 1: Running locally
+
+> 💡 Recommended if you're planning to develop the application or giving it a
+> try on your local cluster.
+
+1. Install tools to run a Kubernetes cluster locally:
+
+ - kubectl (can be installed via `gcloud components install kubectl`)
+ - Local Kubernetes cluster deployment tool:
+ - [Minikube (recommended for
+ Linux)](https://kubernetes.io/docs/setup/minikube/).
+ - Docker for Desktop (recommended for Mac/Windows): It provides Kubernetes support as [noted
+ here](https://docs.docker.com/docker-for-mac/kubernetes/).
+ - [skaffold]( https://skaffold.dev/docs/install/) (ensure version ≥v0.20)
+
+1. Launch the local Kubernetes cluster with one of the following tools:
+
+ - Launch Minikube (tested with Ubuntu Linux). Please, ensure that the
+ local Kubernetes cluster has at least:
+ - 4 CPU's
+ - 4.0 GiB memory
+
+ To run a Kubernetes cluster with Minikube using the described configuration, please run:
+
+ ```shell
+ minikube start --cpus=4 --memory 4096
+ ```
+
+ - Launch “Docker for Desktop” (tested with Mac/Windows). Go to Preferences:
+ - choose “Enable Kubernetes”,
+ - set CPUs to at least 3, and Memory to at least 6.0 GiB
+ - on the "Disk" tab, set at least 32 GB disk space
+
+1. Run `kubectl get nodes` to verify you're connected to “Kubernetes on Docker”.
+
+1. Run `skaffold run` (first time will be slow, it can take ~20 minutes).
+ This will build and deploy the application. If you need to rebuild the images
+ automatically as you refactor the code, run `skaffold dev` command.
+
+1. Run `kubectl get pods` to verify the Pods are ready and running. The
+ application frontend should be available at http://localhost:80 on your
+ machine.
+
+### Option 2: Running on Google Kubernetes Engine (GKE)
+
+> 💡 Recommended if you're using Google Cloud Platform and want to try it on
+> a realistic cluster.
+
+1. Install tools specified in the previous section (Docker, kubectl, skaffold)
+
+1. Create a Google Kubernetes Engine cluster and make sure `kubectl` is pointing
+ to the cluster.
+
+ ```sh
+ gcloud services enable container.googleapis.com
+ ```
+
+ ```sh
+ gcloud container clusters create demo --enable-autoupgrade \
+ --enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5 --zone=us-central1-a
+ ```
+
+ ```
+ kubectl get nodes
+ ```
+
+1. Enable Google Container Registry (GCR) on your GCP project and configure the
+ `docker` CLI to authenticate to GCR:
+
+ ```sh
+ gcloud services enable containerregistry.googleapis.com
+ ```
+
+ ```sh
+ gcloud auth configure-docker -q
+ ```
+
+1. In the root of this repository, run `skaffold run --default-repo=gcr.io/[PROJECT_ID]`,
+ where [PROJECT_ID] is your GCP project ID.
+
+ This command:
+
+ - builds the container images
+ - pushes them to GCR
+ - applies the `./kubernetes-manifests` deploying the application to
+ Kubernetes.
+
+ **Troubleshooting:** If you get "No space left on device" error on Google
+ Cloud Shell, you can build the images on Google Cloud Build: [Enable the
+ Cloud Build
+ API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com),
+ then run `skaffold run -p gcb --default-repo=gcr.io/[PROJECT_ID]` instead.
+
+1. Find the IP address of your application, then visit the application on your
+ browser to confirm installation.
+
+ kubectl get service frontend-external
+
+ **Troubleshooting:** A Kubernetes bug (will be fixed in 1.12) combined with
+ a Skaffold [bug](https://github.com/GoogleContainerTools/skaffold/issues/887)
+ causes load balancer to not to work even after getting an IP address. If you
+ are seeing this, run `kubectl get service frontend-external -o=yaml | kubectl apply -f-`
+ to trigger load balancer reconfiguration.
+
+### Option 3: Using Pre-Built Container Images
+
+> 💡 Recommended if you want to deploy the app faster in fewer steps to an
+> existing cluster.
+
+**NOTE:** If you need to create a Kubernetes cluster locally or on the cloud,
+follow "Option 1" or "Option 2" until you reach the `skaffold run` step.
+
+This option offers you pre-built public container images that are easy to deploy
+by deploying the [release manifest](./release) directly to an existing cluster.
+
+**Prerequisite**: a running Kubernetes cluster (either local or on cloud).
+
+1. Clone this repository, and go to the repository directory
+1. Run `kubectl apply -f ./release/kubernetes-manifests.yaml` to deploy the app.
+1. Run `kubectl get pods` to see pods are in a Ready state.
+1. Find the IP address of your application, then visit the application on your
+ browser to confirm installation.
+
+ ```sh
+ kubectl get service/frontend-external
+ ```
+
+### (Optional) Deploying on a Istio-installed GKE cluster
+
+> **Note:** you followed GKE deployment steps above, run `skaffold delete` first
+> to delete what's deployed.
+
+1. Create a GKE cluster (described in "Option 2").
+
+1. Use [Istio on GKE add-on](https://cloud.google.com/istio/docs/istio-on-gke/installing)
+ to install Istio to your existing GKE cluster.
+
+ ```sh
+ gcloud beta container clusters update demo \
+ --zone=us-central1-a \
+ --update-addons=Istio=ENABLED \
+ --istio-config=auth=MTLS_PERMISSIVE
+ ```
+
+2. (Optional) Enable Stackdriver Tracing/Logging with Istio Stackdriver Adapter
+ by [following this guide](https://cloud.google.com/istio/docs/istio-on-gke/installing#enabling_tracing_and_logging).
+
+3. Install the automatic sidecar injection (annotate the `default` namespace
+ with the label):
+
+ ```sh
+ kubectl label namespace default istio-injection=enabled
+ ```
+
+4. Apply the manifests in [`./istio-manifests`](./istio-manifests) directory.
+ (This is required only once.)
+
+ ```sh
+ kubectl apply -f ./istio-manifests
+ ```
+
+5. Deploy the application with `skaffold run --default-repo=gcr.io/[PROJECT_ID]`.
+
+6. Run `kubectl get pods` to see pods are in a healthy and ready state.
+
+7. Find the IP address of your Istio gateway Ingress or Service, and visit the
+ application.
+
+ ```sh
+ INGRESS_HOST="$(kubectl -n istio-system get service istio-ingressgateway \
+ -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"
+ echo "$INGRESS_HOST"
+ ```
+
+ ```sh
+ curl -v "http://$INGRESS_HOST"
+ ```
+
+### Cleanup
+
+If you've deployed the application with `skaffold run` command, you can run
+`skaffold delete` to clean up the deployed resources.
+
+If you've deployed the application with `kubectl apply -f [...]`, you can
+run `kubectl delete -f [...]` with the same argument to clean up the deployed
+resources.
+
+## Conferences featuring Hipster Shop
+
+- [Google Cloud Next'18 London – Keynote](https://youtu.be/nIq2pkNcfEI?t=3071)
+ showing Stackdriver Incident Response Management
+- Google Cloud Next'18 SF
+ - [Day 1 Keynote](https://youtu.be/vJ9OaAqfxo4?t=2416) showing GKE On-Prem
+ - [Day 3 – Keynote](https://youtu.be/JQPOPV_VH5w?t=815) showing Stackdriver
+ APM (Tracing, Code Search, Profiler, Google Cloud Build)
+ - [Introduction to Service Management with Istio](https://www.youtube.com/watch?v=wCJrdKdD6UM&feature=youtu.be&t=586)
+- [KubeCon EU 2019 - Reinventing Networking: A Deep Dive into Istio's Multicluster Gateways - Steve Dake, Independent](https://youtu.be/-t2BfT59zJA?t=982)
+
+---
+
+This is not an official Google project.
diff --git a/hiptershop-ecommerce/cloudbuild.yaml b/hiptershop-ecommerce/cloudbuild.yaml
new file mode 100644
index 000000000..2d031ce2b
--- /dev/null
+++ b/hiptershop-ecommerce/cloudbuild.yaml
@@ -0,0 +1,25 @@
+# This configuration file is used to build and deploy the app into a
+# GKE cluster using Google Cloud Build.
+#
+# PREREQUISITES:
+# - Cloud Build service account must have role: "Kubernetes Engine Developer"
+
+# USAGE:
+# GCP zone and GKE target cluster must be specified as substitutions
+# Example invocation:
+# `gcloud builds submit --config=cloudbuild.yaml --substitutions=_ZONE=us-central1-b,_CLUSTER=demo-app-staging .`
+
+steps:
+- id: 'Deploy application to cluster'
+ name: 'gcr.io/k8s-skaffold/skaffold:v0.20.0'
+ entrypoint: 'bash'
+ args:
+ - '-c'
+ - >
+ gcloud container clusters get-credentials --zone=$_ZONE $_CLUSTER;
+ skaffold run -f=skaffold.yaml --default-repo=gcr.io/$PROJECT_ID;
+
+# Add more power, and more time, for heavy Skaffold build
+timeout: '3600s'
+options:
+ machineType: 'N1_HIGHCPU_8'
\ No newline at end of file
diff --git a/hiptershop-ecommerce/docs/development-principles.md b/hiptershop-ecommerce/docs/development-principles.md
new file mode 100644
index 000000000..2e840f244
--- /dev/null
+++ b/hiptershop-ecommerce/docs/development-principles.md
@@ -0,0 +1,44 @@
+# Development Principles
+
+> **Note:** This document outlines guidances behind some development decisions
+> behind the Hipster Shop demo application.
+
+### Minimal configuration
+
+Running the demo locally or on GCP should require minimal to no
+configuration unless absolutely necessary to run critical parts of the demo.
+
+Configuration that takes multiple steps, especially such as creating service
+accounts should be avoided.
+
+### App must work well outside GCP
+
+Demo application should work reasonably well when it is not deployed to GCP
+services. The experience of running the application locally or on GCP should
+be close.
+
+For example:
+- OpenCensus prints the traces to stdout when it cannot connect to GCP.
+- Stackdriver Debugging tries connecting to GCP multiple times, eventually gives
+ up.
+
+### Running on GCP must not reduce functionality
+
+Running the demo on the GCP must not reduce/lose any of the capabilities
+developers have when running locally.
+
+For example: Logs should still be printed to stdout/stderr even though logs are
+uploaded to Stackdriver Logging when on GCP, so that developers can use "kubectl
+logs" to diagnose each container.
+
+### Microservice implementations should not be complex
+
+Each service should provide a minimal implementation and try to avoid
+unnecessary code and logic that's not executed.
+
+Keep in mind that any service implementation is a decent example of “a GRPC
+application that runs on Kubernetes”. Keeping the source code short and
+navigable will serve this purpose.
+
+It is okay to have intentional inefficiencies in the code as they help
+illustrate the capabilities of profiling and diagnostics offerings.
diff --git a/hiptershop-ecommerce/docs/img/architecture-diagram.png b/hiptershop-ecommerce/docs/img/architecture-diagram.png
new file mode 100644
index 000000000..c95d84b3c
Binary files /dev/null and b/hiptershop-ecommerce/docs/img/architecture-diagram.png differ
diff --git a/hiptershop-ecommerce/docs/img/hipster-shop-frontend-1.png b/hiptershop-ecommerce/docs/img/hipster-shop-frontend-1.png
new file mode 100644
index 000000000..8084e2309
Binary files /dev/null and b/hiptershop-ecommerce/docs/img/hipster-shop-frontend-1.png differ
diff --git a/hiptershop-ecommerce/docs/img/hipster-shop-frontend-2.png b/hiptershop-ecommerce/docs/img/hipster-shop-frontend-2.png
new file mode 100644
index 000000000..c5a686f8b
Binary files /dev/null and b/hiptershop-ecommerce/docs/img/hipster-shop-frontend-2.png differ
diff --git a/hiptershop-ecommerce/hack/README.md b/hiptershop-ecommerce/hack/README.md
new file mode 100755
index 000000000..41d89df0c
--- /dev/null
+++ b/hiptershop-ecommerce/hack/README.md
@@ -0,0 +1,18 @@
+## `hack/`
+
+This directory provides scripts for building and pushing Docker images, and tagging new demo
+releases.
+
+### env variables
+
+- `TAG` - git release tag / Docker tag.
+- `REPO_PREFIX` - Docker repo prefix to push images. Format: `$user/$project`. Resulting images will be of the
+ format `$user/$project/$svcname:$tag` (where `svcname` = `adservice`, `cartservice`,
+ etc.)
+
+### scripts
+
+1. `./make-docker-images.sh`: builds and pushes images to the specified Docker repository.
+2. `./make-release-artifacts.sh`: generates a combined YAML file with image $TAG at:
+ `./release/kubernetes-manifests/demo.yaml`.
+3. `./make-release.sh`: runs scripts 1 and 2, then runs `git tag` / pushes updated manifests to master.
diff --git a/hiptershop-ecommerce/hack/license_header.txt b/hiptershop-ecommerce/hack/license_header.txt
new file mode 100644
index 000000000..2e94f3e55
--- /dev/null
+++ b/hiptershop-ecommerce/hack/license_header.txt
@@ -0,0 +1,13 @@
+# 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.
diff --git a/hiptershop-ecommerce/hack/make-docker-images.sh b/hiptershop-ecommerce/hack/make-docker-images.sh
new file mode 100755
index 000000000..69afd0f57
--- /dev/null
+++ b/hiptershop-ecommerce/hack/make-docker-images.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+# 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.
+
+# Builds and pushes docker image for each demo microservice.
+
+set -euo pipefail
+SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+log() { echo "$1" >&2; }
+
+TAG="${TAG:?TAG env variable must be specified}"
+REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified}"
+
+while IFS= read -d $'\0' -r dir; do
+ # build image
+ svcname="$(basename "${dir}")"
+ image="${REPO_PREFIX}/$svcname:$TAG"
+ (
+ cd "${dir}"
+ log "Building: ${image}"
+ docker build -t "${image}" .
+
+ log "Pushing: ${image}"
+ docker push "${image}"
+ )
+done < <(find "${SCRIPTDIR}/../src" -mindepth 1 -maxdepth 1 -type d -print0)
+
+log "Successfully built and pushed all images."
diff --git a/hiptershop-ecommerce/hack/make-release-artifacts.sh b/hiptershop-ecommerce/hack/make-release-artifacts.sh
new file mode 100755
index 000000000..10fcb25c8
--- /dev/null
+++ b/hiptershop-ecommerce/hack/make-release-artifacts.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+
+# 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.
+
+# This script compiles manifest files with the image tags and places them in
+# /release/...
+
+set -euo pipefail
+SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+[[ -n "${DEBUG:-}" ]] && set -x
+
+log() { echo "$1" >&2; }
+
+TAG="${TAG:?TAG env variable must be specified}"
+REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified}"
+OUT_DIR="${OUT_DIR:-${SCRIPTDIR}/../release}"
+
+print_license_header() {
+ cat "${SCRIPTDIR}/license_header.txt"
+ echo
+}
+
+print_autogenerated_warning() {
+ cat< "${k8s_manifests_file}"
+ log "Written ${k8s_manifests_file}"
+
+ istio_manifests_file="${OUT_DIR}/istio-manifests.yaml"
+ mk_istio_manifests > "${istio_manifests_file}"
+ log "Written ${istio_manifests_file}"
+}
+
+main
diff --git a/hiptershop-ecommerce/hack/make-release.sh b/hiptershop-ecommerce/hack/make-release.sh
new file mode 100755
index 000000000..04fb27620
--- /dev/null
+++ b/hiptershop-ecommerce/hack/make-release.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+
+# 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.
+
+# This script creates a new release by:
+# - 1. building/pushing images
+# - 2. injecting tags into YAML manifests
+# - 3. creating a new git tag
+# - 4. pushing the tag/commit to master.
+
+set -euo pipefail
+SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+[[ -n "${DEBUG:-}" ]] && set -x
+
+log() { echo "$1" >&2; }
+fail() { log "$1"; exit 1; }
+
+TAG="${TAG:?TAG env variable must be specified}"
+REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified e.g. gcr.io\/google-samples\/microservices-demo}"
+
+if [[ "$TAG" != v* ]]; then
+ fail "\$TAG must start with 'v', e.g. v0.1.0 (got: $TAG)"
+fi
+
+# build and push images
+"${SCRIPTDIR}"/make-docker-images.sh
+
+# update yaml
+"${SCRIPTDIR}"/make-release-artifacts.sh
+
+# create git release / push to master
+git add "${SCRIPTDIR}/../release/"
+git commit --allow-empty -m "Release $TAG"
+log "Pushing k8s manifests to master..."
+git tag "$TAG"
+git push --tags
+git push origin master
+
+log "Successfully tagged release $TAG."
diff --git a/hiptershop-ecommerce/istio-manifests/frontend-gateway.yaml b/hiptershop-ecommerce/istio-manifests/frontend-gateway.yaml
new file mode 100644
index 000000000..b3a1a6473
--- /dev/null
+++ b/hiptershop-ecommerce/istio-manifests/frontend-gateway.yaml
@@ -0,0 +1,44 @@
+# 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.
+
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+ name: frontend-gateway
+spec:
+ selector:
+ istio: ingressgateway # use Istio default gateway implementation
+ servers:
+ - port:
+ number: 80
+ name: http
+ protocol: HTTP
+ hosts:
+ - "*"
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: frontend-ingress
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - frontend-gateway
+ http:
+ - route:
+ - destination:
+ host: frontend
+ port:
+ number: 80
diff --git a/hiptershop-ecommerce/istio-manifests/frontend.yaml b/hiptershop-ecommerce/istio-manifests/frontend.yaml
new file mode 100644
index 000000000..23cd64832
--- /dev/null
+++ b/hiptershop-ecommerce/istio-manifests/frontend.yaml
@@ -0,0 +1,27 @@
+# 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.
+
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: frontend
+spec:
+ hosts:
+ - "frontend.default.svc.cluster.local"
+ http:
+ - route:
+ - destination:
+ host: frontend
+ port:
+ number: 80
diff --git a/hiptershop-ecommerce/istio-manifests/whitelist-egress-googleapis.yaml b/hiptershop-ecommerce/istio-manifests/whitelist-egress-googleapis.yaml
new file mode 100644
index 000000000..60e02212f
--- /dev/null
+++ b/hiptershop-ecommerce/istio-manifests/whitelist-egress-googleapis.yaml
@@ -0,0 +1,46 @@
+# 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.
+
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: whitelist-egress-googleapis
+spec:
+ hosts:
+ - "accounts.google.com" # Used to get token
+ - "*.googleapis.com"
+ ports:
+ - number: 80
+ protocol: HTTP
+ name: http
+ - number: 443
+ protocol: HTTPS
+ name: https
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: whitelist-egress-google-metadata
+spec:
+ hosts:
+ - metadata.google.internal
+ addresses:
+ - 169.254.169.254 # GCE metadata server
+ ports:
+ - number: 80
+ name: http
+ protocol: HTTP
+ - number: 443
+ name: https
+ protocol: HTTPS
diff --git a/hiptershop-ecommerce/kubernetes-manifests/README.md b/hiptershop-ecommerce/kubernetes-manifests/README.md
new file mode 100644
index 000000000..ed852b720
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/README.md
@@ -0,0 +1,8 @@
+# ./kubernetes-manifests
+
+:warning: Kubernetes manifests provided in this directory are not directly
+deployable to a cluster. They are meant to be used with `skaffold` command to
+insert the correct `image:` tags.
+
+Use the manifests in [/release](/release) directory which are configured with
+pre-built public images.
diff --git a/hiptershop-ecommerce/kubernetes-manifests/adservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/adservice.yaml
new file mode 100644
index 000000000..713ebcd93
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/adservice.yaml
@@ -0,0 +1,68 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: adservice
+spec:
+ selector:
+ matchLabels:
+ app: adservice
+ template:
+ metadata:
+ labels:
+ app: adservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: adservice
+ ports:
+ - containerPort: 9555
+ env:
+ - name: PORT
+ value: "9555"
+ #- name: JAEGER_SERVICE_ADDR
+ # value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 200m
+ memory: 180Mi
+ limits:
+ cpu: 300m
+ memory: 300Mi
+ readinessProbe:
+ initialDelaySeconds: 20
+ periodSeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:9555"]
+ livenessProbe:
+ initialDelaySeconds: 20
+ periodSeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:9555"]
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: adservice
+spec:
+ type: ClusterIP
+ selector:
+ app: adservice
+ ports:
+ - name: grpc
+ port: 9555
+ targetPort: 9555
diff --git a/hiptershop-ecommerce/kubernetes-manifests/cartservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/cartservice.yaml
new file mode 100644
index 000000000..31175da63
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/cartservice.yaml
@@ -0,0 +1,69 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: cartservice
+spec:
+ selector:
+ matchLabels:
+ app: cartservice
+ template:
+ metadata:
+ labels:
+ app: cartservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: cartservice
+ ports:
+ - containerPort: 7070
+ env:
+ - name: REDIS_ADDR
+ value: "redis-cart:6379"
+ - name: PORT
+ value: "7070"
+ - name: LISTEN_ADDR
+ value: "0.0.0.0"
+ resources:
+ requests:
+ cpu: 200m
+ memory: 64Mi
+ limits:
+ cpu: 300m
+ memory: 128Mi
+ readinessProbe:
+ initialDelaySeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
+ livenessProbe:
+ initialDelaySeconds: 15
+ periodSeconds: 10
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: cartservice
+spec:
+ type: ClusterIP
+ selector:
+ app: cartservice
+ ports:
+ - name: grpc
+ port: 7070
+ targetPort: 7070
diff --git a/hiptershop-ecommerce/kubernetes-manifests/checkoutservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/checkoutservice.yaml
new file mode 100644
index 000000000..501210ada
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/checkoutservice.yaml
@@ -0,0 +1,75 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: checkoutservice
+spec:
+ selector:
+ matchLabels:
+ app: checkoutservice
+ template:
+ metadata:
+ labels:
+ app: checkoutservice
+ spec:
+ containers:
+ - name: server
+ image: checkoutservice
+ ports:
+ - containerPort: 5050
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:5050"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:5050"]
+ env:
+ - name: PORT
+ value: "5050"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: SHIPPING_SERVICE_ADDR
+ value: "shippingservice:50051"
+ - name: PAYMENT_SERVICE_ADDR
+ value: "paymentservice:50051"
+ - name: EMAIL_SERVICE_ADDR
+ value: "emailservice:5000"
+ - name: CURRENCY_SERVICE_ADDR
+ value: "currencyservice:7000"
+ - name: CART_SERVICE_ADDR
+ value: "cartservice:7070"
+ # - name: JAEGER_SERVICE_ADDR
+ # value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: checkoutservice
+spec:
+ type: ClusterIP
+ selector:
+ app: checkoutservice
+ ports:
+ - name: grpc
+ port: 5050
+ targetPort: 5050
diff --git a/hiptershop-ecommerce/kubernetes-manifests/currencyservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/currencyservice.yaml
new file mode 100644
index 000000000..6d1b21a73
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/currencyservice.yaml
@@ -0,0 +1,63 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: currencyservice
+spec:
+ selector:
+ matchLabels:
+ app: currencyservice
+ template:
+ metadata:
+ labels:
+ app: currencyservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: currencyservice
+ ports:
+ - name: grpc
+ containerPort: 7000
+ env:
+ - name: PORT
+ value: "7000"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7000"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7000"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: currencyservice
+spec:
+ type: ClusterIP
+ selector:
+ app: currencyservice
+ ports:
+ - name: grpc
+ port: 7000
+ targetPort: 7000
diff --git a/hiptershop-ecommerce/kubernetes-manifests/emailservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/emailservice.yaml
new file mode 100644
index 000000000..14d293b8f
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/emailservice.yaml
@@ -0,0 +1,66 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: emailservice
+spec:
+ selector:
+ matchLabels:
+ app: emailservice
+ template:
+ metadata:
+ labels:
+ app: emailservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: emailservice
+ ports:
+ - containerPort: 8080
+ env:
+ - name: PORT
+ value: "8080"
+ - name: ENABLE_PROFILER
+ value: "0"
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ livenessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: emailservice
+spec:
+ type: ClusterIP
+ selector:
+ app: emailservice
+ ports:
+ - name: grpc
+ port: 5000
+ targetPort: 8080
diff --git a/hiptershop-ecommerce/kubernetes-manifests/frontend.yaml b/hiptershop-ecommerce/kubernetes-manifests/frontend.yaml
new file mode 100644
index 000000000..e6a0607e0
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/frontend.yaml
@@ -0,0 +1,102 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: frontend
+spec:
+ selector:
+ matchLabels:
+ app: frontend
+ template:
+ metadata:
+ labels:
+ app: frontend
+ annotations:
+ sidecar.istio.io/rewriteAppHTTPProbers: "true"
+ spec:
+ containers:
+ - name: server
+ image: frontend
+ ports:
+ - containerPort: 8080
+ readinessProbe:
+ initialDelaySeconds: 10
+ httpGet:
+ path: "/_healthz"
+ port: 8080
+ httpHeaders:
+ - name: "Cookie"
+ value: "shop_session-id=x-readiness-probe"
+ livenessProbe:
+ initialDelaySeconds: 10
+ httpGet:
+ path: "/_healthz"
+ port: 8080
+ httpHeaders:
+ - name: "Cookie"
+ value: "shop_session-id=x-liveness-probe"
+ env:
+ - name: PORT
+ value: "8080"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: CURRENCY_SERVICE_ADDR
+ value: "currencyservice:7000"
+ - name: CART_SERVICE_ADDR
+ value: "cartservice:7070"
+ - name: RECOMMENDATION_SERVICE_ADDR
+ value: "recommendationservice:8080"
+ - name: SHIPPING_SERVICE_ADDR
+ value: "shippingservice:50051"
+ - name: CHECKOUT_SERVICE_ADDR
+ value: "checkoutservice:5050"
+ - name: AD_SERVICE_ADDR
+ value: "adservice:9555"
+ # - name: JAEGER_SERVICE_ADDR
+ # value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: frontend
+spec:
+ type: ClusterIP
+ selector:
+ app: frontend
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: frontend-external
+spec:
+ type: LoadBalancer
+ selector:
+ app: frontend
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
diff --git a/hiptershop-ecommerce/kubernetes-manifests/loadgenerator.yaml b/hiptershop-ecommerce/kubernetes-manifests/loadgenerator.yaml
new file mode 100644
index 000000000..53e947e47
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/loadgenerator.yaml
@@ -0,0 +1,46 @@
+# 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.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: loadgenerator
+spec:
+ selector:
+ matchLabels:
+ app: loadgenerator
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: loadgenerator
+ annotations:
+ sidecar.istio.io/rewriteAppHTTPProbers: "true"
+ spec:
+ terminationGracePeriodSeconds: 5
+ restartPolicy: Always
+ containers:
+ - name: main
+ image: loadgenerator
+ env:
+ - name: FRONTEND_ADDR
+ value: "frontend:80"
+ - name: USERS
+ value: "10"
+ resources:
+ requests:
+ cpu: 300m
+ memory: 256Mi
+ limits:
+ cpu: 500m
+ memory: 512Mi
\ No newline at end of file
diff --git a/hiptershop-ecommerce/kubernetes-manifests/paymentservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/paymentservice.yaml
new file mode 100644
index 000000000..fa62c0880
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/paymentservice.yaml
@@ -0,0 +1,62 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: paymentservice
+spec:
+ selector:
+ matchLabels:
+ app: paymentservice
+ template:
+ metadata:
+ labels:
+ app: paymentservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: paymentservice
+ ports:
+ - containerPort: 50051
+ env:
+ - name: PORT
+ value: "50051"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: paymentservice
+spec:
+ type: ClusterIP
+ selector:
+ app: paymentservice
+ ports:
+ - name: grpc
+ port: 50051
+ targetPort: 50051
diff --git a/hiptershop-ecommerce/kubernetes-manifests/productcatalogservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/productcatalogservice.yaml
new file mode 100644
index 000000000..b17585698
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/productcatalogservice.yaml
@@ -0,0 +1,65 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: productcatalogservice
+spec:
+ selector:
+ matchLabels:
+ app: productcatalogservice
+ template:
+ metadata:
+ labels:
+ app: productcatalogservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: productcatalogservice
+ ports:
+ - containerPort: 3550
+ env:
+ - name: PORT
+ value: "3550"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:3550"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:3550"]
+# env:
+# - name: JAEGER_SERVICE_ADDR
+# value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: productcatalogservice
+spec:
+ type: ClusterIP
+ selector:
+ app: productcatalogservice
+ ports:
+ - name: grpc
+ port: 3550
+ targetPort: 3550
diff --git a/hiptershop-ecommerce/kubernetes-manifests/recommendationservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/recommendationservice.yaml
new file mode 100644
index 000000000..1ccc4ab41
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/recommendationservice.yaml
@@ -0,0 +1,68 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: recommendationservice
+spec:
+ selector:
+ matchLabels:
+ app: recommendationservice
+ template:
+ metadata:
+ labels:
+ app: recommendationservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: recommendationservice
+ ports:
+ - containerPort: 8080
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ livenessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ env:
+ - name: PORT
+ value: "8080"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: ENABLE_PROFILER
+ value: "0"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 220Mi
+ limits:
+ cpu: 200m
+ memory: 450Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: recommendationservice
+spec:
+ type: ClusterIP
+ selector:
+ app: recommendationservice
+ ports:
+ - name: grpc
+ port: 8080
+ targetPort: 8080
diff --git a/hiptershop-ecommerce/kubernetes-manifests/redis.yaml b/hiptershop-ecommerce/kubernetes-manifests/redis.yaml
new file mode 100644
index 000000000..b67649b93
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/redis.yaml
@@ -0,0 +1,66 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis-cart
+spec:
+ selector:
+ matchLabels:
+ app: redis-cart
+ template:
+ metadata:
+ labels:
+ app: redis-cart
+ spec:
+ containers:
+ - name: redis
+ image: redis:alpine
+ ports:
+ - containerPort: 6379
+ readinessProbe:
+ periodSeconds: 5
+ tcpSocket:
+ port: 6379
+ livenessProbe:
+ periodSeconds: 5
+ tcpSocket:
+ port: 6379
+ volumeMounts:
+ - mountPath: /data
+ name: redis-data
+ resources:
+ limits:
+ memory: 256Mi
+ cpu: 125m
+ requests:
+ cpu: 70m
+ memory: 200Mi
+ volumes:
+ - name: redis-data
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis-cart
+spec:
+ type: ClusterIP
+ selector:
+ app: redis-cart
+ ports:
+ - name: redis
+ port: 6379
+ targetPort: 6379
diff --git a/hiptershop-ecommerce/kubernetes-manifests/shippingservice.yaml b/hiptershop-ecommerce/kubernetes-manifests/shippingservice.yaml
new file mode 100644
index 000000000..d4049ad31
--- /dev/null
+++ b/hiptershop-ecommerce/kubernetes-manifests/shippingservice.yaml
@@ -0,0 +1,65 @@
+# 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: shippingservice
+spec:
+ selector:
+ matchLabels:
+ app: shippingservice
+ template:
+ metadata:
+ labels:
+ app: shippingservice
+ spec:
+ containers:
+ - name: server
+ image: shippingservice
+ ports:
+ - containerPort: 50051
+ env:
+ - name: PORT
+ value: "50051"
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+# env:
+# - name: JAEGER_SERVICE_ADDR
+# value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: shippingservice
+spec:
+ type: ClusterIP
+ selector:
+ app: shippingservice
+ ports:
+ - name: grpc
+ port: 50051
+ targetPort: 50051
diff --git a/hiptershop-ecommerce/pb/demo.proto b/hiptershop-ecommerce/pb/demo.proto
new file mode 100644
index 000000000..46e6b7ced
--- /dev/null
+++ b/hiptershop-ecommerce/pb/demo.proto
@@ -0,0 +1,246 @@
+syntax = "proto3";
+
+package hipstershop;
+
+// -----------------Cart service-----------------
+
+service CartService {
+ rpc AddItem(AddItemRequest) returns (Empty) {}
+ rpc GetCart(GetCartRequest) returns (Cart) {}
+ rpc EmptyCart(EmptyCartRequest) returns (Empty) {}
+}
+
+message CartItem {
+ string product_id = 1;
+ int32 quantity = 2;
+}
+
+message AddItemRequest {
+ string user_id = 1;
+ CartItem item = 2;
+}
+
+message EmptyCartRequest {
+ string user_id = 1;
+}
+
+message GetCartRequest {
+ string user_id = 1;
+}
+
+message Cart {
+ string user_id = 1;
+ repeated CartItem items = 2;
+}
+
+message Empty {}
+
+// ---------------Recommendation service----------
+
+service RecommendationService {
+ rpc ListRecommendations(ListRecommendationsRequest) returns (ListRecommendationsResponse){}
+}
+
+message ListRecommendationsRequest {
+ string user_id = 1;
+ repeated string product_ids = 2;
+}
+
+message ListRecommendationsResponse {
+ repeated string product_ids = 1;
+}
+
+// ---------------Product Catalog----------------
+
+service ProductCatalogService {
+ rpc ListProducts(Empty) returns (ListProductsResponse) {}
+ rpc GetProduct(GetProductRequest) returns (Product) {}
+ rpc SearchProducts(SearchProductsRequest) returns (SearchProductsResponse) {}
+}
+
+message Product {
+ string id = 1;
+ string name = 2;
+ string description = 3;
+ string picture = 4;
+ Money price_usd = 5;
+
+ // Categories such as "vintage" or "gardening" that can be used to look up
+ // other related products.
+ repeated string categories = 6;
+}
+
+message ListProductsResponse {
+ repeated Product products = 1;
+}
+
+message GetProductRequest {
+ string id = 1;
+}
+
+message SearchProductsRequest {
+ string query = 1;
+}
+
+message SearchProductsResponse {
+ repeated Product results = 1;
+}
+
+// ---------------Shipping Service----------
+
+service ShippingService {
+ rpc GetQuote(GetQuoteRequest) returns (GetQuoteResponse) {}
+ rpc ShipOrder(ShipOrderRequest) returns (ShipOrderResponse) {}
+}
+
+message GetQuoteRequest {
+ Address address = 1;
+ repeated CartItem items = 2;
+}
+
+message GetQuoteResponse {
+ Money cost_usd = 1;
+}
+
+message ShipOrderRequest {
+ Address address = 1;
+ repeated CartItem items = 2;
+}
+
+message ShipOrderResponse {
+ string tracking_id = 1;
+}
+
+message Address {
+ string street_address = 1;
+ string city = 2;
+ string state = 3;
+ string country = 4;
+ int32 zip_code = 5;
+}
+
+// -----------------Currency service-----------------
+
+service CurrencyService {
+ rpc GetSupportedCurrencies(Empty) returns (GetSupportedCurrenciesResponse) {}
+ rpc Convert(CurrencyConversionRequest) returns (Money) {}
+}
+
+// Represents an amount of money with its currency type.
+message Money {
+ // The 3-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;
+}
+
+message GetSupportedCurrenciesResponse {
+ // The 3-letter currency code defined in ISO 4217.
+ repeated string currency_codes = 1;
+}
+
+message CurrencyConversionRequest {
+ Money from = 1;
+
+ // The 3-letter currency code defined in ISO 4217.
+ string to_code = 2;
+}
+
+// -------------Payment service-----------------
+
+service PaymentService {
+ rpc Charge(ChargeRequest) returns (ChargeResponse) {}
+}
+
+message CreditCardInfo {
+ string credit_card_number = 1;
+ int32 credit_card_cvv = 2;
+ int32 credit_card_expiration_year = 3;
+ int32 credit_card_expiration_month = 4;
+}
+
+message ChargeRequest {
+ Money amount = 1;
+ CreditCardInfo credit_card = 2;
+}
+
+message ChargeResponse {
+ string transaction_id = 1;
+}
+
+// -------------Email service-----------------
+
+service EmailService {
+ rpc SendOrderConfirmation(SendOrderConfirmationRequest) returns (Empty) {}
+}
+
+message OrderItem {
+ CartItem item = 1;
+ Money cost = 2;
+}
+
+message OrderResult {
+ string order_id = 1;
+ string shipping_tracking_id = 2;
+ Money shipping_cost = 3;
+ Address shipping_address = 4;
+ repeated OrderItem items = 5;
+}
+
+message SendOrderConfirmationRequest {
+ string email = 1;
+ OrderResult order = 2;
+}
+
+
+// -------------Checkout service-----------------
+
+service CheckoutService {
+ rpc PlaceOrder(PlaceOrderRequest) returns (PlaceOrderResponse) {}
+}
+
+message PlaceOrderRequest {
+ string user_id = 1;
+ string user_currency = 2;
+
+ Address address = 3;
+ string email = 5;
+ CreditCardInfo credit_card = 6;
+}
+
+message PlaceOrderResponse {
+ OrderResult order = 1;
+}
+
+// ------------Ad service------------------
+
+service AdService {
+ rpc GetAds(AdRequest) returns (AdResponse) {}
+}
+
+message AdRequest {
+ // List of important key words from the current page describing the context.
+ repeated string context_keys = 1;
+}
+
+message AdResponse {
+ repeated Ad ads = 1;
+}
+
+message Ad {
+ // url to redirect to when an ad is clicked.
+ string redirect_url = 1;
+
+ // short advertisement text to display.
+ string text = 2;
+}
diff --git a/hiptershop-ecommerce/pb/grpc/health/v1/health.proto b/hiptershop-ecommerce/pb/grpc/health/v1/health.proto
new file mode 100644
index 000000000..4b4677b8a
--- /dev/null
+++ b/hiptershop-ecommerce/pb/grpc/health/v1/health.proto
@@ -0,0 +1,43 @@
+// Copyright 2015 The gRPC 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
+//
+// 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.
+
+// The canonical version of this proto can be found at
+// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto
+
+syntax = "proto3";
+
+package grpc.health.v1;
+
+option csharp_namespace = "Grpc.Health.V1";
+option go_package = "google.golang.org/grpc/health/grpc_health_v1";
+option java_multiple_files = true;
+option java_outer_classname = "HealthProto";
+option java_package = "io.grpc.health.v1";
+
+message HealthCheckRequest {
+ string service = 1;
+}
+
+message HealthCheckResponse {
+ enum ServingStatus {
+ UNKNOWN = 0;
+ SERVING = 1;
+ NOT_SERVING = 2;
+ }
+ ServingStatus status = 1;
+}
+
+service Health {
+ rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
diff --git a/hiptershop-ecommerce/release/istio-manifests.yaml b/hiptershop-ecommerce/release/istio-manifests.yaml
new file mode 100644
index 000000000..57d669d5f
--- /dev/null
+++ b/hiptershop-ecommerce/release/istio-manifests.yaml
@@ -0,0 +1,96 @@
+# 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.
+
+# ----------------------------------------------------------
+# WARNING: This file is autogenerated. Do not manually edit.
+# ----------------------------------------------------------
+
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+ name: frontend-gateway
+spec:
+ selector:
+ istio: ingressgateway # use Istio default gateway implementation
+ servers:
+ - port:
+ number: 80
+ name: http
+ protocol: HTTP
+ hosts:
+ - "*"
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: frontend-ingress
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - frontend-gateway
+ http:
+ - route:
+ - destination:
+ host: frontend
+ port:
+ number: 80
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: frontend
+spec:
+ hosts:
+ - "frontend.default.svc.cluster.local"
+ http:
+ - route:
+ - destination:
+ host: frontend
+ port:
+ number: 80
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: whitelist-egress-googleapis
+spec:
+ hosts:
+ - "accounts.google.com" # Used to get token
+ - "*.googleapis.com"
+ ports:
+ - number: 80
+ protocol: HTTP
+ name: http
+ - number: 443
+ protocol: HTTPS
+ name: https
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: whitelist-egress-google-metadata
+spec:
+ hosts:
+ - metadata.google.internal
+ addresses:
+ - 169.254.169.254 # GCE metadata server
+ ports:
+ - number: 80
+ name: http
+ protocol: HTTP
+ - number: 443
+ name: https
+ protocol: HTTPS
+---
diff --git a/hiptershop-ecommerce/release/kubernetes-manifests.yaml b/hiptershop-ecommerce/release/kubernetes-manifests.yaml
new file mode 100644
index 000000000..8eb7b777c
--- /dev/null
+++ b/hiptershop-ecommerce/release/kubernetes-manifests.yaml
@@ -0,0 +1,678 @@
+# 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.
+
+# ----------------------------------------------------------
+# WARNING: This file is autogenerated. Do not manually edit.
+# ----------------------------------------------------------
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: emailservice
+spec:
+ selector:
+ matchLabels:
+ app: emailservice
+ template:
+ metadata:
+ labels:
+ app: emailservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/emailservice:v0.1.3
+ ports:
+ - containerPort: 8080
+ env:
+ - name: PORT
+ value: "8080"
+ - name: ENABLE_PROFILER
+ value: "0"
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ livenessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: emailservice
+spec:
+ type: ClusterIP
+ selector:
+ app: emailservice
+ ports:
+ - name: grpc
+ port: 5000
+ targetPort: 8080
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: checkoutservice
+spec:
+ selector:
+ matchLabels:
+ app: checkoutservice
+ template:
+ metadata:
+ labels:
+ app: checkoutservice
+ spec:
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/checkoutservice:v0.1.3
+ ports:
+ - containerPort: 5050
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:5050"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:5050"]
+ env:
+ - name: PORT
+ value: "5050"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: SHIPPING_SERVICE_ADDR
+ value: "shippingservice:50051"
+ - name: PAYMENT_SERVICE_ADDR
+ value: "paymentservice:50051"
+ - name: EMAIL_SERVICE_ADDR
+ value: "emailservice:5000"
+ - name: CURRENCY_SERVICE_ADDR
+ value: "currencyservice:7000"
+ - name: CART_SERVICE_ADDR
+ value: "cartservice:7070"
+ # - name: JAEGER_SERVICE_ADDR
+ # value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: checkoutservice
+spec:
+ type: ClusterIP
+ selector:
+ app: checkoutservice
+ ports:
+ - name: grpc
+ port: 5050
+ targetPort: 5050
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: recommendationservice
+spec:
+ selector:
+ matchLabels:
+ app: recommendationservice
+ template:
+ metadata:
+ labels:
+ app: recommendationservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/recommendationservice:v0.1.3
+ ports:
+ - containerPort: 8080
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ livenessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ env:
+ - name: PORT
+ value: "8080"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: ENABLE_PROFILER
+ value: "0"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 220Mi
+ limits:
+ cpu: 200m
+ memory: 450Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: recommendationservice
+spec:
+ type: ClusterIP
+ selector:
+ app: recommendationservice
+ ports:
+ - name: grpc
+ port: 8080
+ targetPort: 8080
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: frontend
+spec:
+ selector:
+ matchLabels:
+ app: frontend
+ template:
+ metadata:
+ labels:
+ app: frontend
+ annotations:
+ sidecar.istio.io/rewriteAppHTTPProbers: "true"
+ spec:
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/frontend:v0.1.3
+ ports:
+ - containerPort: 8080
+ readinessProbe:
+ initialDelaySeconds: 10
+ httpGet:
+ path: "/_healthz"
+ port: 8080
+ httpHeaders:
+ - name: "Cookie"
+ value: "shop_session-id=x-readiness-probe"
+ livenessProbe:
+ initialDelaySeconds: 10
+ httpGet:
+ path: "/_healthz"
+ port: 8080
+ httpHeaders:
+ - name: "Cookie"
+ value: "shop_session-id=x-liveness-probe"
+ env:
+ - name: PORT
+ value: "8080"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: CURRENCY_SERVICE_ADDR
+ value: "currencyservice:7000"
+ - name: CART_SERVICE_ADDR
+ value: "cartservice:7070"
+ - name: RECOMMENDATION_SERVICE_ADDR
+ value: "recommendationservice:8080"
+ - name: SHIPPING_SERVICE_ADDR
+ value: "shippingservice:50051"
+ - name: CHECKOUT_SERVICE_ADDR
+ value: "checkoutservice:5050"
+ - name: AD_SERVICE_ADDR
+ value: "adservice:9555"
+ # - name: JAEGER_SERVICE_ADDR
+ # value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: frontend
+spec:
+ type: ClusterIP
+ selector:
+ app: frontend
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: frontend-external
+spec:
+ type: LoadBalancer
+ selector:
+ app: frontend
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: paymentservice
+spec:
+ selector:
+ matchLabels:
+ app: paymentservice
+ template:
+ metadata:
+ labels:
+ app: paymentservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/paymentservice:v0.1.3
+ ports:
+ - containerPort: 50051
+ env:
+ - name: PORT
+ value: "50051"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: paymentservice
+spec:
+ type: ClusterIP
+ selector:
+ app: paymentservice
+ ports:
+ - name: grpc
+ port: 50051
+ targetPort: 50051
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: productcatalogservice
+spec:
+ selector:
+ matchLabels:
+ app: productcatalogservice
+ template:
+ metadata:
+ labels:
+ app: productcatalogservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.1.3
+ ports:
+ - containerPort: 3550
+ env:
+ - name: PORT
+ value: "3550"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:3550"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:3550"]
+# env:
+# - name: JAEGER_SERVICE_ADDR
+# value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: productcatalogservice
+spec:
+ type: ClusterIP
+ selector:
+ app: productcatalogservice
+ ports:
+ - name: grpc
+ port: 3550
+ targetPort: 3550
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: cartservice
+spec:
+ selector:
+ matchLabels:
+ app: cartservice
+ template:
+ metadata:
+ labels:
+ app: cartservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/cartservice:v0.1.3
+ ports:
+ - containerPort: 7070
+ env:
+ - name: REDIS_ADDR
+ value: "redis-cart:6379"
+ - name: PORT
+ value: "7070"
+ - name: LISTEN_ADDR
+ value: "0.0.0.0"
+ resources:
+ requests:
+ cpu: 200m
+ memory: 64Mi
+ limits:
+ cpu: 300m
+ memory: 128Mi
+ readinessProbe:
+ initialDelaySeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
+ livenessProbe:
+ initialDelaySeconds: 15
+ periodSeconds: 10
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: cartservice
+spec:
+ type: ClusterIP
+ selector:
+ app: cartservice
+ ports:
+ - name: grpc
+ port: 7070
+ targetPort: 7070
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: loadgenerator
+spec:
+ selector:
+ matchLabels:
+ app: loadgenerator
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: loadgenerator
+ annotations:
+ sidecar.istio.io/rewriteAppHTTPProbers: "true"
+ spec:
+ terminationGracePeriodSeconds: 5
+ restartPolicy: Always
+ containers:
+ - name: main
+ image: gcr.io/google-samples/microservices-demo/loadgenerator:v0.1.3
+ env:
+ - name: FRONTEND_ADDR
+ value: "frontend:80"
+ - name: USERS
+ value: "10"
+ resources:
+ requests:
+ cpu: 300m
+ memory: 256Mi
+ limits:
+ cpu: 500m
+ memory: 512Mi
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: currencyservice
+spec:
+ selector:
+ matchLabels:
+ app: currencyservice
+ template:
+ metadata:
+ labels:
+ app: currencyservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/currencyservice:v0.1.3
+ ports:
+ - name: grpc
+ containerPort: 7000
+ env:
+ - name: PORT
+ value: "7000"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7000"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7000"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: currencyservice
+spec:
+ type: ClusterIP
+ selector:
+ app: currencyservice
+ ports:
+ - name: grpc
+ port: 7000
+ targetPort: 7000
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: shippingservice
+spec:
+ selector:
+ matchLabels:
+ app: shippingservice
+ template:
+ metadata:
+ labels:
+ app: shippingservice
+ spec:
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/shippingservice:v0.1.3
+ ports:
+ - containerPort: 50051
+ env:
+ - name: PORT
+ value: "50051"
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+# env:
+# - name: JAEGER_SERVICE_ADDR
+# value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: shippingservice
+spec:
+ type: ClusterIP
+ selector:
+ app: shippingservice
+ ports:
+ - name: grpc
+ port: 50051
+ targetPort: 50051
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis-cart
+spec:
+ selector:
+ matchLabels:
+ app: redis-cart
+ template:
+ metadata:
+ labels:
+ app: redis-cart
+ spec:
+ containers:
+ - name: redis
+ image: redis:alpine
+ ports:
+ - containerPort: 6379
+ readinessProbe:
+ periodSeconds: 5
+ tcpSocket:
+ port: 6379
+ livenessProbe:
+ periodSeconds: 5
+ tcpSocket:
+ port: 6379
+ volumeMounts:
+ - mountPath: /data
+ name: redis-data
+ resources:
+ limits:
+ memory: 256Mi
+ cpu: 125m
+ requests:
+ cpu: 70m
+ memory: 200Mi
+ volumes:
+ - name: redis-data
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis-cart
+spec:
+ type: ClusterIP
+ selector:
+ app: redis-cart
+ ports:
+ - name: redis
+ port: 6379
+ targetPort: 6379
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: adservice
+spec:
+ selector:
+ matchLabels:
+ app: adservice
+ template:
+ metadata:
+ labels:
+ app: adservice
+ spec:
+ terminationGracePeriodSeconds: 5
+ containers:
+ - name: server
+ image: gcr.io/google-samples/microservices-demo/adservice:v0.1.3
+ ports:
+ - containerPort: 9555
+ env:
+ - name: PORT
+ value: "9555"
+ #- name: JAEGER_SERVICE_ADDR
+ # value: "jaeger-collector:14268"
+ resources:
+ requests:
+ cpu: 200m
+ memory: 180Mi
+ limits:
+ cpu: 300m
+ memory: 300Mi
+ readinessProbe:
+ initialDelaySeconds: 20
+ periodSeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:9555"]
+ livenessProbe:
+ initialDelaySeconds: 20
+ periodSeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:9555"]
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: adservice
+spec:
+ type: ClusterIP
+ selector:
+ app: adservice
+ ports:
+ - name: grpc
+ port: 9555
+ targetPort: 9555
+---
diff --git a/hiptershop-ecommerce/skaffold.yaml b/hiptershop-ecommerce/skaffold.yaml
new file mode 100644
index 000000000..665f80a75
--- /dev/null
+++ b/hiptershop-ecommerce/skaffold.yaml
@@ -0,0 +1,71 @@
+# 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.
+
+apiVersion: skaffold/v1beta2
+kind: Config
+build:
+ artifacts:
+ # image tags are relative; to specify an image repo (e.g. GCR), you
+ # must provide a "default repo" using one of the methods described
+ # here:
+ # https://skaffold.dev/docs/concepts/#image-repository-handling
+ - image: emailservice
+ context: src/emailservice
+ - image: productcatalogservice
+ context: src/productcatalogservice
+ - image: recommendationservice
+ context: src/recommendationservice
+ - image: shippingservice
+ context: src/shippingservice
+ - image: checkoutservice
+ context: src/checkoutservice
+ - image: paymentservice
+ context: src/paymentservice
+ - image: currencyservice
+ context: src/currencyservice
+ - image: cartservice
+ context: src/cartservice
+ - image: frontend
+ context: src/frontend
+ - image: loadgenerator
+ context: src/loadgenerator
+ - image: adservice
+ context: src/adservice
+ tagPolicy:
+ gitCommit: {}
+deploy:
+ kubectl:
+ manifests:
+ - ./kubernetes-manifests/**.yaml
+profiles:
+# "travis-ci" profile is used to build the images without
+# pushing them.
+- name: travis-ci
+ build:
+ local:
+ push: false
+# "gcb" profile allows building and pushing the images
+# on Google Container Builder without requiring docker
+# installed on the developer machine. However, note that
+# since GCB does not cache the builds, each build will
+# start from scratch and therefore take a long time.
+#
+# This is not used by default. To use it, run:
+# skaffold run -p gcb
+- name: gcb
+ build:
+ googleCloudBuild:
+ diskSizeGb: 300
+ machineType: N1_HIGHCPU_32
+ timeout: 4000s
diff --git a/hiptershop-ecommerce/src/.gitignore b/hiptershop-ecommerce/src/.gitignore
new file mode 100644
index 000000000..968ce8157
--- /dev/null
+++ b/hiptershop-ecommerce/src/.gitignore
@@ -0,0 +1,5 @@
+# Go: for the time being we are not checking in the vendor/ directories to git
+# to prevent the repo from getting larger forever. In each Go service, you can
+# run "dep ensure --vendor-only" to download the dependencies to vendor/ based
+# on the Gopkg.{toml,lock} files in that directory.
+# vendor/
diff --git a/hiptershop-ecommerce/src/adservice/.gitignore b/hiptershop-ecommerce/src/adservice/.gitignore
new file mode 100644
index 000000000..18097156b
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/.gitignore
@@ -0,0 +1,8 @@
+*.iml
+*.ipr
+*.iws
+.gradle/**
+.idea/**
+build/**
+
+
diff --git a/hiptershop-ecommerce/src/adservice/Dockerfile b/hiptershop-ecommerce/src/adservice/Dockerfile
new file mode 100644
index 000000000..95fb32c73
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/Dockerfile
@@ -0,0 +1,33 @@
+FROM openjdk:8-slim as builder
+
+WORKDIR /app
+
+COPY ["build.gradle", "gradlew", "./"]
+COPY gradle gradle
+RUN chmod +x gradlew
+RUN ./gradlew downloadRepos
+
+COPY . .
+RUN chmod +x gradlew
+RUN ./gradlew installDist
+
+FROM openjdk:8-slim
+
+# Download Stackdriver Profiler Java agent
+RUN apt-get -y update && apt-get install -qqy \
+ wget \
+ && rm -rf /var/lib/apt/lists/*
+RUN mkdir -p /opt/cprof && \
+ wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \
+ | tar xzv -C /opt/cprof && \
+ rm -rf profiler_java_agent.tar.gz
+
+RUN GRPC_HEALTH_PROBE_VERSION=v0.2.1 && \
+ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
+ chmod +x /bin/grpc_health_probe
+
+WORKDIR /app
+COPY --from=builder /app .
+
+EXPOSE 9555
+ENTRYPOINT ["/app/build/install/hipstershop/bin/AdService"]
diff --git a/hiptershop-ecommerce/src/adservice/README.md b/hiptershop-ecommerce/src/adservice/README.md
new file mode 100644
index 000000000..ca1fc73be
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/README.md
@@ -0,0 +1,28 @@
+# Ad Service
+
+The Ad service provides advertisement based on context keys. If no context keys are provided then it returns random ads.
+
+## Building locally
+
+The Ad service uses gradlew to compile/install/distribute. Gradle wrapper is already part of the source code. To build Ad Service, run:
+
+```
+./gradlew installDist
+```
+It will create executable script src/adservice/build/install/hipstershop/bin/AdService
+
+### Upgrading gradle version
+If you need to upgrade the version of gradle then run
+
+```
+./gradlew wrapper --gradle-version
+```
+
+## Building docker image
+
+From the repository root, run:
+
+```
+docker build --file src/adservice/Dockerfile .
+```
+
diff --git a/hiptershop-ecommerce/src/adservice/build.gradle b/hiptershop-ecommerce/src/adservice/build.gradle
new file mode 100644
index 000000000..2341951df
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/build.gradle
@@ -0,0 +1,139 @@
+description = 'Ad Service'
+
+buildscript {
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
+ classpath "gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.7.1"
+ }
+}
+
+apply plugin: 'idea'
+apply plugin: 'java'
+apply plugin: 'com.google.protobuf'
+apply plugin: 'com.github.sherter.google-java-format'
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+group = "adservice"
+version = "0.1.0-SNAPSHOT"
+
+def opencensusVersion = "0.18.0"
+def grpcVersion = "1.17.0"
+def jacksonVersion = "2.9.6"
+
+tasks.withType(JavaCompile) {
+ sourceCompatibility = '1.8'
+ targetCompatibility = '1.8'
+}
+
+ext {
+ speed = project.hasProperty('speed') ? project.getProperty('speed') : false
+ offlineCompile = new File("$buildDir/output/lib")
+}
+
+dependencies {
+ if (speed) {
+ compile fileTree(dir: offlineCompile, include: '*.jar')
+ } else {
+ compile "com.google.api.grpc:proto-google-common-protos:1.12.0",
+ "io.opencensus:opencensus-api:${opencensusVersion}",
+ "io.opencensus:opencensus-contrib-grpc-util:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-trace-jaeger:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-stats-stackdriver:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-trace-stackdriver:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-trace-logging:${opencensusVersion}",
+ "io.grpc:grpc-protobuf:${grpcVersion}",
+ "io.grpc:grpc-stub:${grpcVersion}",
+ "io.grpc:grpc-netty:${grpcVersion}",
+ "io.grpc:grpc-services:${grpcVersion}",
+ "org.apache.logging.log4j:log4j-core:2.11.1"
+
+ runtime "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}",
+ "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}",
+ "io.opencensus:opencensus-contrib-log-correlation-log4j2:${opencensusVersion}",
+ "io.opencensus:opencensus-impl:${opencensusVersion}",
+ "io.netty:netty-tcnative-boringssl-static:2.0.8.Final"
+ }
+}
+
+protobuf {
+ protoc {
+ artifact = 'com.google.protobuf:protoc:3.5.1-1'
+ }
+ plugins {
+ grpc {
+ artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
+ }
+ }
+ generateProtoTasks {
+ all()*.plugins {
+ grpc {}
+ }
+ ofSourceSet('main')
+ }
+}
+
+googleJavaFormat {
+ toolVersion '1.7'
+}
+
+// Inform IDEs like IntelliJ IDEA, Eclipse or NetBeans about the generated code.
+sourceSets {
+ main {
+ java {
+ srcDirs 'hipstershop'
+ srcDirs 'build/generated/source/proto/main/java/hipstershop'
+ srcDirs 'build/generated/source/proto/main/grpc/hipstershop'
+ }
+ }
+}
+
+// Provide convenience executables for trying out the examples.
+apply plugin: 'application'
+
+startScripts.enabled = false
+
+// This to cache dependencies during Docker image building. First build will take time.
+// Subsequent build will be incremental.
+task downloadRepos(type: Copy) {
+ from configurations.compile
+ into offlineCompile
+ from configurations.runtime
+ into offlineCompile
+}
+
+task adService(type: CreateStartScripts) {
+ mainClassName = 'hipstershop.AdService'
+ applicationName = 'AdService'
+ outputDir = new File(project.buildDir, 'tmp')
+ classpath = jar.outputs.files + project.configurations.runtime
+ defaultJvmOpts =
+ ["-Dlog4j2.contextDataInjector=io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector",
+ "-agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=adservice,-cprof_service_version=1.0.0"]
+}
+
+task adServiceClient(type: CreateStartScripts) {
+ mainClassName = 'hipstershop.AdServiceClient'
+ applicationName = 'AdServiceClient'
+ outputDir = new File(project.buildDir, 'tmp')
+ classpath = jar.outputs.files + project.configurations.runtime
+ defaultJvmOpts =
+ ["-Dlog4j2.contextDataInjector=io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector",
+ "-agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=adserviceclient,-cprof_service_version=1.0.0"]
+}
+
+applicationDistribution.into('bin') {
+ from(adService)
+ from(adServiceClient)
+ fileMode = 0755
+}
diff --git a/hiptershop-ecommerce/src/adservice/genproto.sh b/hiptershop-ecommerce/src/adservice/genproto.sh
new file mode 100755
index 000000000..36525e0d5
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/genproto.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -eu
+#
+# 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.
+
+#!/bin/bash -e
+
+# protos are needed in adservice folder for compiling during Docker build.
+
+mkdir -p proto && \
+cp ../../pb/demo.proto src/main/proto
diff --git a/hiptershop-ecommerce/src/adservice/gradle/wrapper/gradle-wrapper.jar b/hiptershop-ecommerce/src/adservice/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..01b8bf6b1
Binary files /dev/null and b/hiptershop-ecommerce/src/adservice/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/hiptershop-ecommerce/src/adservice/gradle/wrapper/gradle-wrapper.properties b/hiptershop-ecommerce/src/adservice/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..933b6473c
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
diff --git a/hiptershop-ecommerce/src/adservice/gradlew b/hiptershop-ecommerce/src/adservice/gradlew
new file mode 100755
index 000000000..cccdd3d51
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# 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
+ ;;
+ 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"
+ which java >/dev/null 2>&1 || 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
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/hiptershop-ecommerce/src/adservice/gradlew.bat b/hiptershop-ecommerce/src/adservice/gradlew.bat
new file mode 100644
index 000000000..e95643d6a
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/gradlew.bat
@@ -0,0 +1,84 @@
+@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=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@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=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+: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 %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="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!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/hiptershop-ecommerce/src/adservice/settings.gradle b/hiptershop-ecommerce/src/adservice/settings.gradle
new file mode 100644
index 000000000..0bbe0117c
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'hipstershop'
diff --git a/hiptershop-ecommerce/src/adservice/src/main/java/hipstershop/AdService.java b/hiptershop-ecommerce/src/adservice/src/main/java/hipstershop/AdService.java
new file mode 100644
index 000000000..4817e1b01
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/src/main/java/hipstershop/AdService.java
@@ -0,0 +1,299 @@
+/*
+ * 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.
+ */
+
+package hipstershop;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import hipstershop.Demo.Ad;
+import hipstershop.Demo.AdRequest;
+import hipstershop.Demo.AdResponse;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.StatusRuntimeException;
+import io.grpc.health.v1.HealthCheckResponse.ServingStatus;
+import io.grpc.services.*;
+import io.grpc.stub.StreamObserver;
+import io.opencensus.common.Duration;
+import io.opencensus.contrib.grpc.metrics.RpcViews;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
+import io.opencensus.exporter.trace.jaeger.JaegerTraceExporter;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter;
+import io.opencensus.trace.AttributeValue;
+import io.opencensus.trace.Span;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public final class AdService {
+
+ private static final Logger logger = LogManager.getLogger(AdService.class);
+ private static final Tracer tracer = Tracing.getTracer();
+
+ private static int MAX_ADS_TO_SERVE = 2;
+ private Server server;
+ private HealthStatusManager healthMgr;
+
+ private static final AdService service = new AdService();
+
+ private void start() throws IOException {
+ int port = Integer.parseInt(System.getenv("PORT"));
+ healthMgr = new HealthStatusManager();
+
+ server =
+ ServerBuilder.forPort(port)
+ .addService(new AdServiceImpl())
+ .addService(healthMgr.getHealthService())
+ .build()
+ .start();
+ logger.info("Ad Service started, listening on " + port);
+ Runtime.getRuntime()
+ .addShutdownHook(
+ new Thread() {
+ @Override
+ public void run() {
+ // Use stderr here since the logger may have been reset by its JVM shutdown hook.
+ System.err.println("*** shutting down gRPC ads server since JVM is shutting down");
+ AdService.this.stop();
+ System.err.println("*** server shut down");
+ }
+ });
+ healthMgr.setStatus("", ServingStatus.SERVING);
+ }
+
+ private void stop() {
+ if (server != null) {
+ healthMgr.clearStatus("");
+ server.shutdown();
+ }
+ }
+
+ private static class AdServiceImpl extends hipstershop.AdServiceGrpc.AdServiceImplBase {
+
+ /**
+ * Retrieves ads based on context provided in the request {@code AdRequest}.
+ *
+ * @param req the request containing context.
+ * @param responseObserver the stream observer which gets notified with the value of {@code
+ * AdResponse}
+ */
+ @Override
+ public void getAds(AdRequest req, StreamObserver responseObserver) {
+ AdService service = AdService.getInstance();
+ Span span = tracer.getCurrentSpan();
+ try {
+ span.putAttribute("method", AttributeValue.stringAttributeValue("getAds"));
+ List allAds = new ArrayList<>();
+ logger.info("received ad request (context_words=" + req.getContextKeysList() + ")");
+ if (req.getContextKeysCount() > 0) {
+ span.addAnnotation(
+ "Constructing Ads using context",
+ ImmutableMap.of(
+ "Context Keys",
+ AttributeValue.stringAttributeValue(req.getContextKeysList().toString()),
+ "Context Keys length",
+ AttributeValue.longAttributeValue(req.getContextKeysCount())));
+ for (int i = 0; i < req.getContextKeysCount(); i++) {
+ Collection ads = service.getAdsByCategory(req.getContextKeys(i));
+ allAds.addAll(ads);
+ }
+ } else {
+ span.addAnnotation("No Context provided. Constructing random Ads.");
+ allAds = service.getRandomAds();
+ }
+ if (allAds.isEmpty()) {
+ // Serve random ads.
+ span.addAnnotation("No Ads found based on context. Constructing random Ads.");
+ allAds = service.getRandomAds();
+ }
+ AdResponse reply = AdResponse.newBuilder().addAllAds(allAds).build();
+ responseObserver.onNext(reply);
+ responseObserver.onCompleted();
+ } catch (StatusRuntimeException e) {
+ logger.log(Level.WARN, "GetAds Failed", e.getStatus());
+ responseObserver.onError(e);
+ }
+ }
+ }
+
+ private static final ImmutableListMultimap adsMap = createAdsMap();
+
+ private Collection getAdsByCategory(String category) {
+ return adsMap.get(category);
+ }
+
+ private static final Random random = new Random();
+
+ private List getRandomAds() {
+ List ads = new ArrayList<>(MAX_ADS_TO_SERVE);
+ Collection allAds = adsMap.values();
+ for (int i = 0; i < MAX_ADS_TO_SERVE; i++) {
+ ads.add(Iterables.get(allAds, random.nextInt(allAds.size())));
+ }
+ return ads;
+ }
+
+ private static AdService getInstance() {
+ return service;
+ }
+
+ /** Await termination on the main thread since the grpc library uses daemon threads. */
+ private void blockUntilShutdown() throws InterruptedException {
+ if (server != null) {
+ server.awaitTermination();
+ }
+ }
+
+ private static ImmutableListMultimap createAdsMap() {
+ Ad camera =
+ Ad.newBuilder()
+ .setRedirectUrl("/product/2ZYFJ3GM2N")
+ .setText("Film camera for sale. 50% off.")
+ .build();
+ Ad lens =
+ Ad.newBuilder()
+ .setRedirectUrl("/product/66VCHSJNUP")
+ .setText("Vintage camera lens for sale. 20% off.")
+ .build();
+ Ad recordPlayer =
+ Ad.newBuilder()
+ .setRedirectUrl("/product/0PUK6V6EV0")
+ .setText("Vintage record player for sale. 30% off.")
+ .build();
+ Ad bike =
+ Ad.newBuilder()
+ .setRedirectUrl("/product/9SIQT8TOJO")
+ .setText("City Bike for sale. 10% off.")
+ .build();
+ Ad baristaKit =
+ Ad.newBuilder()
+ .setRedirectUrl("/product/1YMWWN1N4O")
+ .setText("Home Barista kitchen kit for sale. Buy one, get second kit for free")
+ .build();
+ Ad airPlant =
+ Ad.newBuilder()
+ .setRedirectUrl("/product/6E92ZMYYFZ")
+ .setText("Air plants for sale. Buy two, get third one for free")
+ .build();
+ Ad terrarium =
+ Ad.newBuilder()
+ .setRedirectUrl("/product/L9ECAV7KIM")
+ .setText("Terrarium for sale. Buy one, get second one for free")
+ .build();
+ return ImmutableListMultimap.builder()
+ .putAll("photography", camera, lens)
+ .putAll("vintage", camera, lens, recordPlayer)
+ .put("cycling", bike)
+ .put("cookware", baristaKit)
+ .putAll("gardening", airPlant, terrarium)
+ .build();
+ }
+
+ private static void initStackdriver() {
+ logger.info("Initialize Stackdriver");
+
+ long sleepTime = 10; /* seconds */
+ int maxAttempts = 5;
+ boolean statsExporterRegistered = false;
+ boolean traceExporterRegistered = false;
+
+ for (int i = 0; i < maxAttempts; i++) {
+ try {
+ if (!traceExporterRegistered) {
+ StackdriverTraceExporter.createAndRegister(
+ StackdriverTraceConfiguration.builder().build());
+ traceExporterRegistered = true;
+ }
+ if (!statsExporterRegistered) {
+ StackdriverStatsExporter.createAndRegister(
+ StackdriverStatsConfiguration.builder()
+ .setExportInterval(Duration.create(60, 0))
+ .build());
+ statsExporterRegistered = true;
+ }
+ } catch (Exception e) {
+ if (i == (maxAttempts - 1)) {
+ logger.log(
+ Level.WARN,
+ "Failed to register Stackdriver Exporter."
+ + " Tracing and Stats data will not reported to Stackdriver. Error message: "
+ + e.toString());
+ } else {
+ logger.info("Attempt to register Stackdriver Exporter in " + sleepTime + " seconds ");
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(sleepTime));
+ } catch (Exception se) {
+ logger.log(Level.WARN, "Exception while sleeping" + se.toString());
+ }
+ }
+ }
+ }
+ logger.info("Stackdriver initialization complete.");
+ }
+
+ private static void initJaeger() {
+ String jaegerAddr = System.getenv("JAEGER_SERVICE_ADDR");
+ if (jaegerAddr != null && !jaegerAddr.isEmpty()) {
+ String jaegerUrl = String.format("http://%s/api/traces", jaegerAddr);
+ // Register Jaeger Tracing.
+ JaegerTraceExporter.createAndRegister(jaegerUrl, "adservice");
+ logger.info("Jaeger initialization complete.");
+ } else {
+ logger.info("Jaeger initialization disabled.");
+ }
+ }
+
+ /** Main launches the server from the command line. */
+ public static void main(String[] args) throws IOException, InterruptedException {
+ // Registers all RPC views.
+ /**
+ * [TODO:rghetia] replace registerAllViews with registerAllGrpcViews.
+ * registerAllGrpcViews registers new views using new measures however current grpc version records against
+ * old measures. When new version of grpc (0.19) is release revert back to new. After reverting
+ * back to new the new measure will not provide any tags (like method). This will create
+ * some discrepencies when compared grpc measurements in Go services.
+ */
+ RpcViews.registerAllViews();
+
+ new Thread(
+ new Runnable() {
+ public void run() {
+ initStackdriver();
+ }
+ })
+ .start();
+
+ // Register Jaeger
+ initJaeger();
+
+ // Start the RPC server. You shouldn't see any output from gRPC before this.
+ logger.info("AdService starting.");
+ final AdService service = AdService.getInstance();
+ service.start();
+ service.blockUntilShutdown();
+ }
+}
diff --git a/hiptershop-ecommerce/src/adservice/src/main/java/hipstershop/AdServiceClient.java b/hiptershop-ecommerce/src/adservice/src/main/java/hipstershop/AdServiceClient.java
new file mode 100644
index 000000000..8aca28d8d
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/src/main/java/hipstershop/AdServiceClient.java
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+package hipstershop;
+
+import hipstershop.Demo.Ad;
+import hipstershop.Demo.AdRequest;
+import hipstershop.Demo.AdResponse;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.StatusRuntimeException;
+import io.opencensus.common.Duration;
+import io.opencensus.common.Scope;
+import io.opencensus.contrib.grpc.metrics.RpcViews;
+import io.opencensus.contrib.grpc.util.StatusConverter;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter;
+import io.opencensus.trace.Span;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+import io.opencensus.trace.samplers.Samplers;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Nullable;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/** A simple client that requests ads from the Ads Service. */
+public class AdServiceClient {
+
+ private static final Logger logger = LogManager.getLogger(AdServiceClient.class);
+ private static final Tracer tracer = Tracing.getTracer();
+
+ private final ManagedChannel channel;
+ private final hipstershop.AdServiceGrpc.AdServiceBlockingStub blockingStub;
+
+ /** Construct client connecting to Ad Service at {@code host:port}. */
+ private AdServiceClient(String host, int port) {
+ this(
+ ManagedChannelBuilder.forAddress(host, port)
+ // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
+ // needing certificates.
+ .usePlaintext(true)
+ .build());
+ }
+
+ /** Construct client for accessing RouteGuide server using the existing channel. */
+ private AdServiceClient(ManagedChannel channel) {
+ this.channel = channel;
+ blockingStub = hipstershop.AdServiceGrpc.newBlockingStub(channel);
+ }
+
+ private void shutdown() throws InterruptedException {
+ channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ /** Get Ads from Server. */
+ public void getAds(String contextKey) {
+ logger.info("Get Ads with context " + contextKey + " ...");
+ AdRequest request = AdRequest.newBuilder().addContextKeys(contextKey).build();
+ AdResponse response;
+
+ Span span =
+ tracer
+ .spanBuilder("AdsClient")
+ .setRecordEvents(true)
+ .setSampler(Samplers.alwaysSample())
+ .startSpan();
+ try (Scope scope = tracer.withSpan(span)) {
+ tracer.getCurrentSpan().addAnnotation("Getting Ads");
+ response = blockingStub.getAds(request);
+ tracer.getCurrentSpan().addAnnotation("Received response from Ads Service.");
+ } catch (StatusRuntimeException e) {
+ tracer.getCurrentSpan().setStatus(StatusConverter.fromGrpcStatus(e.getStatus()));
+ logger.log(Level.WARN, "RPC failed: " + e.getStatus());
+ return;
+ } finally {
+ span.end();
+ }
+ for (Ad ads : response.getAdsList()) {
+ logger.info("Ads: " + ads.getText());
+ }
+ }
+
+ private static int getPortOrDefaultFromArgs(String[] args, int index, int defaultPort) {
+ int portNumber = defaultPort;
+ if (index < args.length) {
+ try {
+ portNumber = Integer.parseInt(args[index]);
+ } catch (NumberFormatException e) {
+ logger.warn(
+ String.format("Port %s is invalid, use default port %d.", args[index], defaultPort));
+ }
+ }
+ return portNumber;
+ }
+
+ private static String getStringOrDefaultFromArgs(
+ String[] args, int index, @Nullable String defaultString) {
+ String s = defaultString;
+ if (index < args.length) {
+ s = args[index];
+ }
+ return s;
+ }
+
+ /**
+ * Ads Service Client main. If provided, the first element of {@code args} is the context key to
+ * get the ads from the Ads Service
+ */
+ public static void main(String[] args) throws InterruptedException {
+ // Add final keyword to pass checkStyle.
+ final String contextKeys = getStringOrDefaultFromArgs(args, 0, "camera");
+ final String host = getStringOrDefaultFromArgs(args, 1, "localhost");
+ final int serverPort = getPortOrDefaultFromArgs(args, 2, 9555);
+
+ // Registers all RPC views.
+ RpcViews.registerAllGrpcViews();
+
+ // Registers Stackdriver exporters.
+ long sleepTime = 10; /* seconds */
+ int maxAttempts = 3;
+
+ for (int i = 0; i < maxAttempts; i++) {
+ try {
+ StackdriverTraceExporter.createAndRegister(StackdriverTraceConfiguration.builder().build());
+ StackdriverStatsExporter.createAndRegister(
+ StackdriverStatsConfiguration.builder()
+ .setExportInterval(Duration.create(15, 0))
+ .build());
+ } catch (Exception e) {
+ if (i == (maxAttempts - 1)) {
+ logger.log(
+ Level.WARN,
+ "Failed to register Stackdriver Exporter."
+ + " Tracing and Stats data will not reported to Stackdriver. Error message: "
+ + e.toString());
+ } else {
+ logger.info("Attempt to register Stackdriver Exporter in " + sleepTime + " seconds");
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(sleepTime));
+ } catch (Exception se) {
+ logger.log(Level.WARN, "Exception while sleeping" + e.toString());
+ }
+ }
+ }
+ }
+
+ // Register Prometheus exporters and export metrics to a Prometheus HTTPServer.
+ // PrometheusStatsCollector.createAndRegister();
+
+ AdServiceClient client = new AdServiceClient(host, serverPort);
+ try {
+ client.getAds(contextKeys);
+ } finally {
+ client.shutdown();
+ }
+
+ logger.info("Exiting AdServiceClient...");
+ }
+}
diff --git a/hiptershop-ecommerce/src/adservice/src/main/proto/demo.proto b/hiptershop-ecommerce/src/adservice/src/main/proto/demo.proto
new file mode 100644
index 000000000..46e6b7ced
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/src/main/proto/demo.proto
@@ -0,0 +1,246 @@
+syntax = "proto3";
+
+package hipstershop;
+
+// -----------------Cart service-----------------
+
+service CartService {
+ rpc AddItem(AddItemRequest) returns (Empty) {}
+ rpc GetCart(GetCartRequest) returns (Cart) {}
+ rpc EmptyCart(EmptyCartRequest) returns (Empty) {}
+}
+
+message CartItem {
+ string product_id = 1;
+ int32 quantity = 2;
+}
+
+message AddItemRequest {
+ string user_id = 1;
+ CartItem item = 2;
+}
+
+message EmptyCartRequest {
+ string user_id = 1;
+}
+
+message GetCartRequest {
+ string user_id = 1;
+}
+
+message Cart {
+ string user_id = 1;
+ repeated CartItem items = 2;
+}
+
+message Empty {}
+
+// ---------------Recommendation service----------
+
+service RecommendationService {
+ rpc ListRecommendations(ListRecommendationsRequest) returns (ListRecommendationsResponse){}
+}
+
+message ListRecommendationsRequest {
+ string user_id = 1;
+ repeated string product_ids = 2;
+}
+
+message ListRecommendationsResponse {
+ repeated string product_ids = 1;
+}
+
+// ---------------Product Catalog----------------
+
+service ProductCatalogService {
+ rpc ListProducts(Empty) returns (ListProductsResponse) {}
+ rpc GetProduct(GetProductRequest) returns (Product) {}
+ rpc SearchProducts(SearchProductsRequest) returns (SearchProductsResponse) {}
+}
+
+message Product {
+ string id = 1;
+ string name = 2;
+ string description = 3;
+ string picture = 4;
+ Money price_usd = 5;
+
+ // Categories such as "vintage" or "gardening" that can be used to look up
+ // other related products.
+ repeated string categories = 6;
+}
+
+message ListProductsResponse {
+ repeated Product products = 1;
+}
+
+message GetProductRequest {
+ string id = 1;
+}
+
+message SearchProductsRequest {
+ string query = 1;
+}
+
+message SearchProductsResponse {
+ repeated Product results = 1;
+}
+
+// ---------------Shipping Service----------
+
+service ShippingService {
+ rpc GetQuote(GetQuoteRequest) returns (GetQuoteResponse) {}
+ rpc ShipOrder(ShipOrderRequest) returns (ShipOrderResponse) {}
+}
+
+message GetQuoteRequest {
+ Address address = 1;
+ repeated CartItem items = 2;
+}
+
+message GetQuoteResponse {
+ Money cost_usd = 1;
+}
+
+message ShipOrderRequest {
+ Address address = 1;
+ repeated CartItem items = 2;
+}
+
+message ShipOrderResponse {
+ string tracking_id = 1;
+}
+
+message Address {
+ string street_address = 1;
+ string city = 2;
+ string state = 3;
+ string country = 4;
+ int32 zip_code = 5;
+}
+
+// -----------------Currency service-----------------
+
+service CurrencyService {
+ rpc GetSupportedCurrencies(Empty) returns (GetSupportedCurrenciesResponse) {}
+ rpc Convert(CurrencyConversionRequest) returns (Money) {}
+}
+
+// Represents an amount of money with its currency type.
+message Money {
+ // The 3-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;
+}
+
+message GetSupportedCurrenciesResponse {
+ // The 3-letter currency code defined in ISO 4217.
+ repeated string currency_codes = 1;
+}
+
+message CurrencyConversionRequest {
+ Money from = 1;
+
+ // The 3-letter currency code defined in ISO 4217.
+ string to_code = 2;
+}
+
+// -------------Payment service-----------------
+
+service PaymentService {
+ rpc Charge(ChargeRequest) returns (ChargeResponse) {}
+}
+
+message CreditCardInfo {
+ string credit_card_number = 1;
+ int32 credit_card_cvv = 2;
+ int32 credit_card_expiration_year = 3;
+ int32 credit_card_expiration_month = 4;
+}
+
+message ChargeRequest {
+ Money amount = 1;
+ CreditCardInfo credit_card = 2;
+}
+
+message ChargeResponse {
+ string transaction_id = 1;
+}
+
+// -------------Email service-----------------
+
+service EmailService {
+ rpc SendOrderConfirmation(SendOrderConfirmationRequest) returns (Empty) {}
+}
+
+message OrderItem {
+ CartItem item = 1;
+ Money cost = 2;
+}
+
+message OrderResult {
+ string order_id = 1;
+ string shipping_tracking_id = 2;
+ Money shipping_cost = 3;
+ Address shipping_address = 4;
+ repeated OrderItem items = 5;
+}
+
+message SendOrderConfirmationRequest {
+ string email = 1;
+ OrderResult order = 2;
+}
+
+
+// -------------Checkout service-----------------
+
+service CheckoutService {
+ rpc PlaceOrder(PlaceOrderRequest) returns (PlaceOrderResponse) {}
+}
+
+message PlaceOrderRequest {
+ string user_id = 1;
+ string user_currency = 2;
+
+ Address address = 3;
+ string email = 5;
+ CreditCardInfo credit_card = 6;
+}
+
+message PlaceOrderResponse {
+ OrderResult order = 1;
+}
+
+// ------------Ad service------------------
+
+service AdService {
+ rpc GetAds(AdRequest) returns (AdResponse) {}
+}
+
+message AdRequest {
+ // List of important key words from the current page describing the context.
+ repeated string context_keys = 1;
+}
+
+message AdResponse {
+ repeated Ad ads = 1;
+}
+
+message Ad {
+ // url to redirect to when an ad is clicked.
+ string redirect_url = 1;
+
+ // short advertisement text to display.
+ string text = 2;
+}
diff --git a/hiptershop-ecommerce/src/adservice/src/main/resources/log4j2.xml b/hiptershop-ecommerce/src/adservice/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..dbb8cb11d
--- /dev/null
+++ b/hiptershop-ecommerce/src/adservice/src/main/resources/log4j2.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hiptershop-ecommerce/src/cartservice/.gitignore b/hiptershop-ecommerce/src/cartservice/.gitignore
new file mode 100644
index 000000000..f983350be
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/.gitignore
@@ -0,0 +1,3 @@
+/bin/*
+/obj/*
+.vs/*.*
diff --git a/hiptershop-ecommerce/src/cartservice/CartServiceImpl.cs b/hiptershop-ecommerce/src/cartservice/CartServiceImpl.cs
new file mode 100644
index 000000000..c50dd0bf4
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/CartServiceImpl.cs
@@ -0,0 +1,54 @@
+// 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.
+
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using cartservice.interfaces;
+using Grpc.Core;
+using Hipstershop;
+using static Hipstershop.CartService;
+
+namespace cartservice
+{
+ // Cart wrapper to deal with grpc communication
+ internal class CartServiceImpl : CartServiceBase
+ {
+ private ICartStore cartStore;
+ private readonly static Empty Empty = new Empty();
+
+ public CartServiceImpl(ICartStore cartStore)
+ {
+ this.cartStore = cartStore;
+ }
+
+ public async override Task AddItem(AddItemRequest request, Grpc.Core.ServerCallContext context)
+ {
+ await cartStore.AddItemAsync(request.UserId, request.Item.ProductId, request.Item.Quantity);
+ return Empty;
+ }
+
+ public async override Task EmptyCart(EmptyCartRequest request, ServerCallContext context)
+ {
+ await cartStore.EmptyCartAsync(request.UserId);
+ return Empty;
+ }
+
+ public override Task GetCart(GetCartRequest request, ServerCallContext context)
+ {
+ return cartStore.GetCartAsync(request.UserId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/hiptershop-ecommerce/src/cartservice/Dockerfile b/hiptershop-ecommerce/src/cartservice/Dockerfile
new file mode 100644
index 000000000..ad2b1c343
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/Dockerfile
@@ -0,0 +1,28 @@
+FROM microsoft/dotnet:2.1-sdk-alpine as builder
+WORKDIR /app
+COPY . .
+RUN dotnet restore && \
+ dotnet build && \
+ dotnet publish -c release -r linux-musl-x64 -o /cartservice
+
+# cartservice
+FROM alpine:3.8
+
+RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \
+ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
+ chmod +x /bin/grpc_health_probe
+
+# Dependencies for runtime
+# busybox-extras => telnet
+RUN apk add --no-cache \
+ busybox-extras \
+ libc6-compat \
+ libunwind \
+ libuuid \
+ libgcc \
+ libstdc++ \
+ libintl \
+ icu
+WORKDIR /app
+COPY --from=builder /cartservice .
+ENTRYPOINT ["./cartservice", "start"]
diff --git a/hiptershop-ecommerce/src/cartservice/HealthImpl.cs b/hiptershop-ecommerce/src/cartservice/HealthImpl.cs
new file mode 100644
index 000000000..44290d113
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/HealthImpl.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Threading.Tasks;
+using cartservice.interfaces;
+using Grpc.Core;
+using Grpc.Health.V1;
+using StackExchange.Redis;
+using static Grpc.Health.V1.Health;
+
+namespace cartservice {
+ internal class HealthImpl : HealthBase {
+ private ICartStore dependency { get; }
+ public HealthImpl (ICartStore dependency) {
+ this.dependency = dependency;
+ }
+
+ public override Task Check(HealthCheckRequest request, ServerCallContext context){
+ Console.WriteLine ("Checking CartService Health");
+ return Task.FromResult(new HealthCheckResponse {
+ Status = dependency.Ping() ? HealthCheckResponse.Types.ServingStatus.Serving : HealthCheckResponse.Types.ServingStatus.NotServing
+ });
+ }
+ }
+}
diff --git a/hiptershop-ecommerce/src/cartservice/Program.cs b/hiptershop-ecommerce/src/cartservice/Program.cs
new file mode 100644
index 000000000..cf5269bdc
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/Program.cs
@@ -0,0 +1,183 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using cartservice.cartstore;
+using cartservice.interfaces;
+using CommandLine;
+using Grpc.Core;
+using Microsoft.Extensions.Configuration;
+
+namespace cartservice
+{
+ class Program
+ {
+ const string CART_SERVICE_ADDRESS = "LISTEN_ADDR";
+ const string REDIS_ADDRESS = "REDIS_ADDR";
+ const string CART_SERVICE_PORT = "PORT";
+
+ [Verb("start", HelpText = "Starts the server listening on provided port")]
+ class ServerOptions
+ {
+ [Option('h', "hostname", HelpText = "The ip on which the server is running. If not provided, LISTEN_ADDR environment variable value will be used. If not defined, localhost is used")]
+ public string Host { get; set; }
+
+ [Option('p', "port", HelpText = "The port on for running the server")]
+ public int Port { get; set; }
+
+ [Option('r', "redis", HelpText = "The ip of redis cache")]
+ public string Redis { get; set; }
+ }
+
+ static object StartServer(string host, int port, ICartStore cartStore)
+ {
+ // Run the server in a separate thread and make the main thread busy waiting.
+ // The busy wait is because when we run in a container, we can't use techniques such as waiting on user input (Console.Readline())
+ Task serverTask = Task.Run(async () =>
+ {
+ try
+ {
+ await cartStore.InitializeAsync();
+
+ Console.WriteLine($"Trying to start a grpc server at {host}:{port}");
+ Server server = new Server
+ {
+ Services =
+ {
+ // Cart Service Endpoint
+ Hipstershop.CartService.BindService(new CartServiceImpl(cartStore)),
+
+ // Health Endpoint
+ Grpc.Health.V1.Health.BindService(new HealthImpl(cartStore))
+ },
+ Ports = { new ServerPort(host, port, ServerCredentials.Insecure) }
+ };
+
+ Console.WriteLine($"Cart server is listening at {host}:{port}");
+ server.Start();
+
+ Console.WriteLine("Initialization completed");
+
+ // Keep the server up and running
+ while(true)
+ {
+ Thread.Sleep(TimeSpan.FromMinutes(10));
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+ });
+
+ return Task.WaitAny(new[] { serverTask });
+ }
+
+ static void Main(string[] args)
+ {
+ if (args.Length == 0)
+ {
+ Console.WriteLine("Invalid number of arguments supplied");
+ Environment.Exit(-1);
+ }
+
+ switch (args[0])
+ {
+ case "start":
+ Parser.Default.ParseArguments(args).MapResult(
+ (ServerOptions options) =>
+ {
+ Console.WriteLine($"Started as process with id {System.Diagnostics.Process.GetCurrentProcess().Id}");
+
+ // Set hostname/ip address
+ string hostname = options.Host;
+ if (string.IsNullOrEmpty(hostname))
+ {
+ Console.WriteLine($"Reading host address from {CART_SERVICE_ADDRESS} environment variable");
+ hostname = Environment.GetEnvironmentVariable(CART_SERVICE_ADDRESS);
+ if (string.IsNullOrEmpty(hostname))
+ {
+ Console.WriteLine($"Environment variable {CART_SERVICE_ADDRESS} was not set. Setting the host to 0.0.0.0");
+ hostname = "0.0.0.0";
+ }
+ }
+
+ // Set the port
+ int port = options.Port;
+ if (options.Port <= 0)
+ {
+ Console.WriteLine($"Reading cart service port from {CART_SERVICE_PORT} environment variable");
+ string portStr = Environment.GetEnvironmentVariable(CART_SERVICE_PORT);
+ if (string.IsNullOrEmpty(portStr))
+ {
+ Console.WriteLine($"{CART_SERVICE_PORT} environment variable was not set. Setting the port to 8080");
+ port = 8080;
+ }
+ else
+ {
+ port = int.Parse(portStr);
+ }
+ }
+
+ // Set redis cache host (hostname+port)
+ ICartStore cartStore;
+ string redis = ReadRedisAddress(options.Redis);
+
+ // Redis was specified via command line or environment variable
+ if (!string.IsNullOrEmpty(redis))
+ {
+ // If you want to start cart store using local cache in process, you can replace the following line with this:
+ // cartStore = new LocalCartStore();
+ cartStore = new RedisCartStore(redis);
+
+ return StartServer(hostname, port, cartStore);
+ }
+ else
+ {
+ Console.WriteLine("Redis cache host(hostname+port) was not specified. Starting a cart service using local store");
+ Console.WriteLine("If you wanted to use Redis Cache as a backup store, you should provide its address via command line or REDIS_ADDRESS environment variable.");
+ cartStore = new LocalCartStore();
+ }
+
+ return StartServer(hostname, port, cartStore);
+ },
+ errs => 1);
+ break;
+ default:
+ Console.WriteLine("Invalid command");
+ break;
+ }
+ }
+
+ private static string ReadRedisAddress(string address)
+ {
+ if (!string.IsNullOrEmpty(address))
+ {
+ return address;
+ }
+
+ Console.WriteLine($"Reading redis cache address from environment variable {REDIS_ADDRESS}");
+ string redis = Environment.GetEnvironmentVariable(REDIS_ADDRESS);
+ if (!string.IsNullOrEmpty(redis))
+ {
+ return redis;
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/hiptershop-ecommerce/src/cartservice/cartservice.csproj b/hiptershop-ecommerce/src/cartservice/cartservice.csproj
new file mode 100644
index 000000000..4c1e378d3
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/cartservice.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
diff --git a/hiptershop-ecommerce/src/cartservice/cartstore/LocalCartStore.cs b/hiptershop-ecommerce/src/cartservice/cartstore/LocalCartStore.cs
new file mode 100644
index 000000000..7fd8a5ed2
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/cartstore/LocalCartStore.cs
@@ -0,0 +1,91 @@
+// 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.
+
+using System;
+using System.Collections.Concurrent;
+using System.Threading.Tasks;
+using System.Linq;
+using cartservice.interfaces;
+using Hipstershop;
+
+namespace cartservice.cartstore
+{
+ internal class LocalCartStore : ICartStore
+ {
+ // Maps between user and their cart
+ private ConcurrentDictionary userCartItems = new ConcurrentDictionary();
+ private readonly Hipstershop.Cart emptyCart = new Hipstershop.Cart();
+
+ public Task InitializeAsync()
+ {
+ Console.WriteLine("Local Cart Store was initialized");
+
+ return Task.CompletedTask;
+ }
+
+ public Task AddItemAsync(string userId, string productId, int quantity)
+ {
+ Console.WriteLine($"AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}");
+ var newCart = new Hipstershop.Cart
+ {
+ UserId = userId,
+ Items = { new Hipstershop.CartItem { ProductId = productId, Quantity = quantity } }
+ };
+ userCartItems.AddOrUpdate(userId, newCart,
+ (k, exVal) =>
+ {
+ // If the item exists, we update its quantity
+ var existingItem = exVal.Items.SingleOrDefault(item => item.ProductId == productId);
+ if (existingItem != null)
+ {
+ existingItem.Quantity += quantity;
+ }
+ else
+ {
+ exVal.Items.Add(new Hipstershop.CartItem { ProductId = productId, Quantity = quantity });
+ }
+
+ return exVal;
+ });
+
+ return Task.CompletedTask;
+ }
+
+ public Task EmptyCartAsync(string userId)
+ {
+ Console.WriteLine($"EmptyCartAsync called with userId={userId}");
+ userCartItems[userId] = new Hipstershop.Cart();
+
+ return Task.CompletedTask;
+ }
+
+ public Task GetCartAsync(string userId)
+ {
+ Console.WriteLine($"GetCartAsync called with userId={userId}");
+ Hipstershop.Cart cart = null;
+ if (!userCartItems.TryGetValue(userId, out cart))
+ {
+ Console.WriteLine($"No carts for user {userId}");
+ return Task.FromResult(emptyCart);
+ }
+
+ return Task.FromResult(cart);
+ }
+
+ public bool Ping()
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hiptershop-ecommerce/src/cartservice/cartstore/RedisCartStore.cs b/hiptershop-ecommerce/src/cartservice/cartstore/RedisCartStore.cs
new file mode 100644
index 000000000..30dc95548
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/cartstore/RedisCartStore.cs
@@ -0,0 +1,215 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using cartservice.interfaces;
+using Google.Protobuf;
+using Grpc.Core;
+using Hipstershop;
+using StackExchange.Redis;
+
+namespace cartservice.cartstore
+{
+ public class RedisCartStore : ICartStore
+ {
+ private const string CART_FIELD_NAME = "cart";
+ private const int REDIS_RETRY_NUM = 5;
+
+ private volatile ConnectionMultiplexer redis;
+ private volatile bool isRedisConnectionOpened = false;
+
+ private readonly object locker = new object();
+ private readonly byte[] emptyCartBytes;
+ private readonly string connectionString;
+
+ private readonly ConfigurationOptions redisConnectionOptions;
+
+ public RedisCartStore(string redisAddress)
+ {
+ // Serialize empty cart into byte array.
+ var cart = new Hipstershop.Cart();
+ emptyCartBytes = cart.ToByteArray();
+ connectionString = $"{redisAddress},ssl=false,allowAdmin=true,connectRetry=5";
+
+ redisConnectionOptions = ConfigurationOptions.Parse(connectionString);
+
+ // Try to reconnect if first retry failed (up to 5 times with exponential backoff)
+ redisConnectionOptions.ConnectRetry = REDIS_RETRY_NUM;
+ redisConnectionOptions.ReconnectRetryPolicy = new ExponentialRetry(100);
+
+ redisConnectionOptions.KeepAlive = 180;
+ }
+
+ public Task InitializeAsync()
+ {
+ EnsureRedisConnected();
+ return Task.CompletedTask;
+ }
+
+ private void EnsureRedisConnected()
+ {
+ if (isRedisConnectionOpened)
+ {
+ return;
+ }
+
+ // Connection is closed or failed - open a new one but only at the first thread
+ lock (locker)
+ {
+ if (isRedisConnectionOpened)
+ {
+ return;
+ }
+
+ Console.WriteLine("Connecting to Redis: " + connectionString);
+ redis = ConnectionMultiplexer.Connect(redisConnectionOptions);
+
+ if (redis == null || !redis.IsConnected)
+ {
+ Console.WriteLine("Wasn't able to connect to redis");
+
+ // We weren't able to connect to redis despite 5 retries with exponential backoff
+ throw new ApplicationException("Wasn't able to connect to redis");
+ }
+
+ Console.WriteLine("Successfully connected to Redis");
+ var cache = redis.GetDatabase();
+
+ Console.WriteLine("Performing small test");
+ cache.StringSet("cart", "OK" );
+ object res = cache.StringGet("cart");
+ Console.WriteLine($"Small test result: {res}");
+
+ redis.InternalError += (o, e) => { Console.WriteLine(e.Exception); };
+ redis.ConnectionRestored += (o, e) =>
+ {
+ isRedisConnectionOpened = true;
+ Console.WriteLine("Connection to redis was retored successfully");
+ };
+ redis.ConnectionFailed += (o, e) =>
+ {
+ Console.WriteLine("Connection failed. Disposing the object");
+ isRedisConnectionOpened = false;
+ };
+
+ isRedisConnectionOpened = true;
+ }
+ }
+
+ public async Task AddItemAsync(string userId, string productId, int quantity)
+ {
+ Console.WriteLine($"AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}");
+
+ try
+ {
+ EnsureRedisConnected();
+
+ var db = redis.GetDatabase();
+
+ // Access the cart from the cache
+ var value = await db.HashGetAsync(userId, CART_FIELD_NAME);
+
+ Hipstershop.Cart cart;
+ if (value.IsNull)
+ {
+ cart = new Hipstershop.Cart();
+ cart.UserId = userId;
+ cart.Items.Add(new Hipstershop.CartItem { ProductId = productId, Quantity = quantity });
+ }
+ else
+ {
+ cart = Hipstershop.Cart.Parser.ParseFrom(value);
+ var existingItem = cart.Items.SingleOrDefault(i => i.ProductId == productId);
+ if (existingItem == null)
+ {
+ cart.Items.Add(new Hipstershop.CartItem { ProductId = productId, Quantity = quantity });
+ }
+ else
+ {
+ existingItem.Quantity += quantity;
+ }
+ }
+
+ await db.HashSetAsync(userId, new[]{ new HashEntry(CART_FIELD_NAME, cart.ToByteArray()) });
+ }
+ catch (Exception ex)
+ {
+ throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}"));
+ }
+ }
+
+ public async Task EmptyCartAsync(string userId)
+ {
+ Console.WriteLine($"EmptyCartAsync called with userId={userId}");
+
+ try
+ {
+ EnsureRedisConnected();
+ var db = redis.GetDatabase();
+
+ // Update the cache with empty cart for given user
+ await db.HashSetAsync(userId, new[] { new HashEntry(CART_FIELD_NAME, emptyCartBytes) });
+ }
+ catch (Exception ex)
+ {
+ throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}"));
+ }
+ }
+
+ public async Task GetCartAsync(string userId)
+ {
+ Console.WriteLine($"GetCartAsync called with userId={userId}");
+
+ try
+ {
+ EnsureRedisConnected();
+
+ var db = redis.GetDatabase();
+
+ // Access the cart from the cache
+ var value = await db.HashGetAsync(userId, CART_FIELD_NAME);
+
+ if (!value.IsNull)
+ {
+ return Hipstershop.Cart.Parser.ParseFrom(value);
+ }
+
+ // We decided to return empty cart in cases when user wasn't in the cache before
+ return new Hipstershop.Cart();
+ }
+ catch (Exception ex)
+ {
+ throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}"));
+ }
+ }
+
+ public bool Ping()
+ {
+ try
+ {
+ var cache = redis.GetDatabase();
+ var res = cache.Ping();
+ return res != TimeSpan.Zero;
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/hiptershop-ecommerce/src/cartservice/genproto.bat b/hiptershop-ecommerce/src/cartservice/genproto.bat
new file mode 100644
index 000000000..9f2209733
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/genproto.bat
@@ -0,0 +1,27 @@
+@REM Copyright 2018 Google LLC
+@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 http://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 Generate the C# code for .proto files
+
+setlocal
+
+@rem enter this directory
+cd /d %~dp0
+
+set NUGET_PATH=%UserProfile%\.nuget\packages
+set TOOLS_PATH=%NUGET_PATH%\Grpc.Tools\1.12.0\tools\windows_x64
+
+%TOOLS_PATH%\protoc.exe -I%~dp0/../../pb;%NUGET_PATH%\google.protobuf.tools\3.5.1\tools\ --csharp_out %~dp0\grpc_generated %~dp0\..\..\pb\demo.proto --grpc_out %~dp0\grpc_generated --plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe
+
+endlocal
diff --git a/hiptershop-ecommerce/src/cartservice/genproto.sh b/hiptershop-ecommerce/src/cartservice/genproto.sh
new file mode 100755
index 000000000..f1a858866
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/genproto.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -eu
+#
+# 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.
+
+# Generate the C# code for .proto files
+set -e
+
+PROTODIR=../../pb
+
+# enter this directory
+CWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+
+protoc --csharp_out=$CWD/grpc_generated -I $PROTODIR $PROTODIR/demo.proto
+
diff --git a/hiptershop-ecommerce/src/cartservice/grpc_generated/Demo.cs b/hiptershop-ecommerce/src/cartservice/grpc_generated/Demo.cs
new file mode 100644
index 000000000..f1961315a
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/grpc_generated/Demo.cs
@@ -0,0 +1,5191 @@
+//
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: demo.proto
+//
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Hipstershop {
+
+ /// Holder for reflection information generated from demo.proto
+ public static partial class DemoReflection {
+
+ #region Descriptor
+ /// File descriptor for demo.proto
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static DemoReflection() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CgpkZW1vLnByb3RvEgtoaXBzdGVyc2hvcCIwCghDYXJ0SXRlbRISCgpwcm9k",
+ "dWN0X2lkGAEgASgJEhAKCHF1YW50aXR5GAIgASgFIkYKDkFkZEl0ZW1SZXF1",
+ "ZXN0Eg8KB3VzZXJfaWQYASABKAkSIwoEaXRlbRgCIAEoCzIVLmhpcHN0ZXJz",
+ "aG9wLkNhcnRJdGVtIiMKEEVtcHR5Q2FydFJlcXVlc3QSDwoHdXNlcl9pZBgB",
+ "IAEoCSIhCg5HZXRDYXJ0UmVxdWVzdBIPCgd1c2VyX2lkGAEgASgJIj0KBENh",
+ "cnQSDwoHdXNlcl9pZBgBIAEoCRIkCgVpdGVtcxgCIAMoCzIVLmhpcHN0ZXJz",
+ "aG9wLkNhcnRJdGVtIgcKBUVtcHR5IkIKGkxpc3RSZWNvbW1lbmRhdGlvbnNS",
+ "ZXF1ZXN0Eg8KB3VzZXJfaWQYASABKAkSEwoLcHJvZHVjdF9pZHMYAiADKAki",
+ "MgobTGlzdFJlY29tbWVuZGF0aW9uc1Jlc3BvbnNlEhMKC3Byb2R1Y3RfaWRz",
+ "GAEgAygJInAKB1Byb2R1Y3QSCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRIT",
+ "CgtkZXNjcmlwdGlvbhgDIAEoCRIPCgdwaWN0dXJlGAQgASgJEiUKCXByaWNl",
+ "X3VzZBgFIAEoCzISLmhpcHN0ZXJzaG9wLk1vbmV5Ij4KFExpc3RQcm9kdWN0",
+ "c1Jlc3BvbnNlEiYKCHByb2R1Y3RzGAEgAygLMhQuaGlwc3RlcnNob3AuUHJv",
+ "ZHVjdCIfChFHZXRQcm9kdWN0UmVxdWVzdBIKCgJpZBgBIAEoCSImChVTZWFy",
+ "Y2hQcm9kdWN0c1JlcXVlc3QSDQoFcXVlcnkYASABKAkiPwoWU2VhcmNoUHJv",
+ "ZHVjdHNSZXNwb25zZRIlCgdyZXN1bHRzGAEgAygLMhQuaGlwc3RlcnNob3Au",
+ "UHJvZHVjdCJeCg9HZXRRdW90ZVJlcXVlc3QSJQoHYWRkcmVzcxgBIAEoCzIU",
+ "LmhpcHN0ZXJzaG9wLkFkZHJlc3MSJAoFaXRlbXMYAiADKAsyFS5oaXBzdGVy",
+ "c2hvcC5DYXJ0SXRlbSI4ChBHZXRRdW90ZVJlc3BvbnNlEiQKCGNvc3RfdXNk",
+ "GAEgASgLMhIuaGlwc3RlcnNob3AuTW9uZXkiXwoQU2hpcE9yZGVyUmVxdWVz",
+ "dBIlCgdhZGRyZXNzGAEgASgLMhQuaGlwc3RlcnNob3AuQWRkcmVzcxIkCgVp",
+ "dGVtcxgCIAMoCzIVLmhpcHN0ZXJzaG9wLkNhcnRJdGVtIigKEVNoaXBPcmRl",
+ "clJlc3BvbnNlEhMKC3RyYWNraW5nX2lkGAEgASgJImEKB0FkZHJlc3MSFgoO",
+ "c3RyZWV0X2FkZHJlc3MYASABKAkSDAoEY2l0eRgCIAEoCRINCgVzdGF0ZRgD",
+ "IAEoCRIPCgdjb3VudHJ5GAQgASgJEhAKCHppcF9jb2RlGAUgASgFIjwKBU1v",
+ "bmV5EhUKDWN1cnJlbmN5X2NvZGUYASABKAkSDQoFdW5pdHMYAiABKAMSDQoF",
+ "bmFub3MYAyABKAUiOAoeR2V0U3VwcG9ydGVkQ3VycmVuY2llc1Jlc3BvbnNl",
+ "EhYKDmN1cnJlbmN5X2NvZGVzGAEgAygJIk4KGUN1cnJlbmN5Q29udmVyc2lv",
+ "blJlcXVlc3QSIAoEZnJvbRgBIAEoCzISLmhpcHN0ZXJzaG9wLk1vbmV5Eg8K",
+ "B3RvX2NvZGUYAiABKAkikAEKDkNyZWRpdENhcmRJbmZvEhoKEmNyZWRpdF9j",
+ "YXJkX251bWJlchgBIAEoCRIXCg9jcmVkaXRfY2FyZF9jdnYYAiABKAUSIwob",
+ "Y3JlZGl0X2NhcmRfZXhwaXJhdGlvbl95ZWFyGAMgASgFEiQKHGNyZWRpdF9j",
+ "YXJkX2V4cGlyYXRpb25fbW9udGgYBCABKAUiZQoNQ2hhcmdlUmVxdWVzdBIi",
+ "CgZhbW91bnQYASABKAsyEi5oaXBzdGVyc2hvcC5Nb25leRIwCgtjcmVkaXRf",
+ "Y2FyZBgCIAEoCzIbLmhpcHN0ZXJzaG9wLkNyZWRpdENhcmRJbmZvIigKDkNo",
+ "YXJnZVJlc3BvbnNlEhYKDnRyYW5zYWN0aW9uX2lkGAEgASgJIlIKCU9yZGVy",
+ "SXRlbRIjCgRpdGVtGAEgASgLMhUuaGlwc3RlcnNob3AuQ2FydEl0ZW0SIAoE",
+ "Y29zdBgCIAEoCzISLmhpcHN0ZXJzaG9wLk1vbmV5Ir8BCgtPcmRlclJlc3Vs",
+ "dBIQCghvcmRlcl9pZBgBIAEoCRIcChRzaGlwcGluZ190cmFja2luZ19pZBgC",
+ "IAEoCRIpCg1zaGlwcGluZ19jb3N0GAMgASgLMhIuaGlwc3RlcnNob3AuTW9u",
+ "ZXkSLgoQc2hpcHBpbmdfYWRkcmVzcxgEIAEoCzIULmhpcHN0ZXJzaG9wLkFk",
+ "ZHJlc3MSJQoFaXRlbXMYBSADKAsyFi5oaXBzdGVyc2hvcC5PcmRlckl0ZW0i",
+ "VgocU2VuZE9yZGVyQ29uZmlybWF0aW9uUmVxdWVzdBINCgVlbWFpbBgBIAEo",
+ "CRInCgVvcmRlchgCIAEoCzIYLmhpcHN0ZXJzaG9wLk9yZGVyUmVzdWx0IqMB",
+ "ChFQbGFjZU9yZGVyUmVxdWVzdBIPCgd1c2VyX2lkGAEgASgJEhUKDXVzZXJf",
+ "Y3VycmVuY3kYAiABKAkSJQoHYWRkcmVzcxgDIAEoCzIULmhpcHN0ZXJzaG9w",
+ "LkFkZHJlc3MSDQoFZW1haWwYBSABKAkSMAoLY3JlZGl0X2NhcmQYBiABKAsy",
+ "Gy5oaXBzdGVyc2hvcC5DcmVkaXRDYXJkSW5mbyI9ChJQbGFjZU9yZGVyUmVz",
+ "cG9uc2USJwoFb3JkZXIYASABKAsyGC5oaXBzdGVyc2hvcC5PcmRlclJlc3Vs",
+ "dCIhCglBZFJlcXVlc3QSFAoMY29udGV4dF9rZXlzGAEgAygJIioKCkFkUmVz",
+ "cG9uc2USHAoDYWRzGAEgAygLMg8uaGlwc3RlcnNob3AuQWQiKAoCQWQSFAoM",
+ "cmVkaXJlY3RfdXJsGAEgASgJEgwKBHRleHQYAiABKAkyygEKC0NhcnRTZXJ2",
+ "aWNlEjwKB0FkZEl0ZW0SGy5oaXBzdGVyc2hvcC5BZGRJdGVtUmVxdWVzdBoS",
+ "LmhpcHN0ZXJzaG9wLkVtcHR5IgASOwoHR2V0Q2FydBIbLmhpcHN0ZXJzaG9w",
+ "LkdldENhcnRSZXF1ZXN0GhEuaGlwc3RlcnNob3AuQ2FydCIAEkAKCUVtcHR5",
+ "Q2FydBIdLmhpcHN0ZXJzaG9wLkVtcHR5Q2FydFJlcXVlc3QaEi5oaXBzdGVy",
+ "c2hvcC5FbXB0eSIAMoMBChVSZWNvbW1lbmRhdGlvblNlcnZpY2USagoTTGlz",
+ "dFJlY29tbWVuZGF0aW9ucxInLmhpcHN0ZXJzaG9wLkxpc3RSZWNvbW1lbmRh",
+ "dGlvbnNSZXF1ZXN0GiguaGlwc3RlcnNob3AuTGlzdFJlY29tbWVuZGF0aW9u",
+ "c1Jlc3BvbnNlIgAygwIKFVByb2R1Y3RDYXRhbG9nU2VydmljZRJHCgxMaXN0",
+ "UHJvZHVjdHMSEi5oaXBzdGVyc2hvcC5FbXB0eRohLmhpcHN0ZXJzaG9wLkxp",
+ "c3RQcm9kdWN0c1Jlc3BvbnNlIgASRAoKR2V0UHJvZHVjdBIeLmhpcHN0ZXJz",
+ "aG9wLkdldFByb2R1Y3RSZXF1ZXN0GhQuaGlwc3RlcnNob3AuUHJvZHVjdCIA",
+ "ElsKDlNlYXJjaFByb2R1Y3RzEiIuaGlwc3RlcnNob3AuU2VhcmNoUHJvZHVj",
+ "dHNSZXF1ZXN0GiMuaGlwc3RlcnNob3AuU2VhcmNoUHJvZHVjdHNSZXNwb25z",
+ "ZSIAMqoBCg9TaGlwcGluZ1NlcnZpY2USSQoIR2V0UXVvdGUSHC5oaXBzdGVy",
+ "c2hvcC5HZXRRdW90ZVJlcXVlc3QaHS5oaXBzdGVyc2hvcC5HZXRRdW90ZVJl",
+ "c3BvbnNlIgASTAoJU2hpcE9yZGVyEh0uaGlwc3RlcnNob3AuU2hpcE9yZGVy",
+ "UmVxdWVzdBoeLmhpcHN0ZXJzaG9wLlNoaXBPcmRlclJlc3BvbnNlIgAytwEK",
+ "D0N1cnJlbmN5U2VydmljZRJbChZHZXRTdXBwb3J0ZWRDdXJyZW5jaWVzEhIu",
+ "aGlwc3RlcnNob3AuRW1wdHkaKy5oaXBzdGVyc2hvcC5HZXRTdXBwb3J0ZWRD",
+ "dXJyZW5jaWVzUmVzcG9uc2UiABJHCgdDb252ZXJ0EiYuaGlwc3RlcnNob3Au",
+ "Q3VycmVuY3lDb252ZXJzaW9uUmVxdWVzdBoSLmhpcHN0ZXJzaG9wLk1vbmV5",
+ "IgAyVQoOUGF5bWVudFNlcnZpY2USQwoGQ2hhcmdlEhouaGlwc3RlcnNob3Au",
+ "Q2hhcmdlUmVxdWVzdBobLmhpcHN0ZXJzaG9wLkNoYXJnZVJlc3BvbnNlIgAy",
+ "aAoMRW1haWxTZXJ2aWNlElgKFVNlbmRPcmRlckNvbmZpcm1hdGlvbhIpLmhp",
+ "cHN0ZXJzaG9wLlNlbmRPcmRlckNvbmZpcm1hdGlvblJlcXVlc3QaEi5oaXBz",
+ "dGVyc2hvcC5FbXB0eSIAMmIKD0NoZWNrb3V0U2VydmljZRJPCgpQbGFjZU9y",
+ "ZGVyEh4uaGlwc3RlcnNob3AuUGxhY2VPcmRlclJlcXVlc3QaHy5oaXBzdGVy",
+ "c2hvcC5QbGFjZU9yZGVyUmVzcG9uc2UiADJICglBZFNlcnZpY2USOwoGR2V0",
+ "QWRzEhYuaGlwc3RlcnNob3AuQWRSZXF1ZXN0GhcuaGlwc3RlcnNob3AuQWRS",
+ "ZXNwb25zZSIAYgZwcm90bzM="));
+ descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.CartItem), global::Hipstershop.CartItem.Parser, new[]{ "ProductId", "Quantity" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.AddItemRequest), global::Hipstershop.AddItemRequest.Parser, new[]{ "UserId", "Item" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.EmptyCartRequest), global::Hipstershop.EmptyCartRequest.Parser, new[]{ "UserId" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.GetCartRequest), global::Hipstershop.GetCartRequest.Parser, new[]{ "UserId" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.Cart), global::Hipstershop.Cart.Parser, new[]{ "UserId", "Items" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.Empty), global::Hipstershop.Empty.Parser, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.ListRecommendationsRequest), global::Hipstershop.ListRecommendationsRequest.Parser, new[]{ "UserId", "ProductIds" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.ListRecommendationsResponse), global::Hipstershop.ListRecommendationsResponse.Parser, new[]{ "ProductIds" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.Product), global::Hipstershop.Product.Parser, new[]{ "Id", "Name", "Description", "Picture", "PriceUsd" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.ListProductsResponse), global::Hipstershop.ListProductsResponse.Parser, new[]{ "Products" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.GetProductRequest), global::Hipstershop.GetProductRequest.Parser, new[]{ "Id" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.SearchProductsRequest), global::Hipstershop.SearchProductsRequest.Parser, new[]{ "Query" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.SearchProductsResponse), global::Hipstershop.SearchProductsResponse.Parser, new[]{ "Results" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.GetQuoteRequest), global::Hipstershop.GetQuoteRequest.Parser, new[]{ "Address", "Items" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.GetQuoteResponse), global::Hipstershop.GetQuoteResponse.Parser, new[]{ "CostUsd" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.ShipOrderRequest), global::Hipstershop.ShipOrderRequest.Parser, new[]{ "Address", "Items" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.ShipOrderResponse), global::Hipstershop.ShipOrderResponse.Parser, new[]{ "TrackingId" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.Address), global::Hipstershop.Address.Parser, new[]{ "StreetAddress", "City", "State", "Country", "ZipCode" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.Money), global::Hipstershop.Money.Parser, new[]{ "CurrencyCode", "Units", "Nanos" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.GetSupportedCurrenciesResponse), global::Hipstershop.GetSupportedCurrenciesResponse.Parser, new[]{ "CurrencyCodes" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.CurrencyConversionRequest), global::Hipstershop.CurrencyConversionRequest.Parser, new[]{ "From", "ToCode" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.CreditCardInfo), global::Hipstershop.CreditCardInfo.Parser, new[]{ "CreditCardNumber", "CreditCardCvv", "CreditCardExpirationYear", "CreditCardExpirationMonth" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.ChargeRequest), global::Hipstershop.ChargeRequest.Parser, new[]{ "Amount", "CreditCard" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.ChargeResponse), global::Hipstershop.ChargeResponse.Parser, new[]{ "TransactionId" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.OrderItem), global::Hipstershop.OrderItem.Parser, new[]{ "Item", "Cost" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.OrderResult), global::Hipstershop.OrderResult.Parser, new[]{ "OrderId", "ShippingTrackingId", "ShippingCost", "ShippingAddress", "Items" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.SendOrderConfirmationRequest), global::Hipstershop.SendOrderConfirmationRequest.Parser, new[]{ "Email", "Order" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.PlaceOrderRequest), global::Hipstershop.PlaceOrderRequest.Parser, new[]{ "UserId", "UserCurrency", "Address", "Email", "CreditCard" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.PlaceOrderResponse), global::Hipstershop.PlaceOrderResponse.Parser, new[]{ "Order" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.AdRequest), global::Hipstershop.AdRequest.Parser, new[]{ "ContextKeys" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.AdResponse), global::Hipstershop.AdResponse.Parser, new[]{ "Ads" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Hipstershop.Ad), global::Hipstershop.Ad.Parser, new[]{ "RedirectUrl", "Text" }, null, null, null)
+ }));
+ }
+ #endregion
+
+ }
+ #region Messages
+ public sealed partial class CartItem : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CartItem());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[0]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CartItem() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CartItem(CartItem other) : this() {
+ productId_ = other.productId_;
+ quantity_ = other.quantity_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CartItem Clone() {
+ return new CartItem(this);
+ }
+
+ /// Field number for the "product_id" field.
+ public const int ProductIdFieldNumber = 1;
+ private string productId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string ProductId {
+ get { return productId_; }
+ set {
+ productId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "quantity" field.
+ public const int QuantityFieldNumber = 2;
+ private int quantity_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int Quantity {
+ get { return quantity_; }
+ set {
+ quantity_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as CartItem);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(CartItem other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (ProductId != other.ProductId) return false;
+ if (Quantity != other.Quantity) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ProductId.Length != 0) hash ^= ProductId.GetHashCode();
+ if (Quantity != 0) hash ^= Quantity.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ProductId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(ProductId);
+ }
+ if (Quantity != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(Quantity);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (ProductId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ProductId);
+ }
+ if (Quantity != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Quantity);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(CartItem other) {
+ if (other == null) {
+ return;
+ }
+ if (other.ProductId.Length != 0) {
+ ProductId = other.ProductId;
+ }
+ if (other.Quantity != 0) {
+ Quantity = other.Quantity;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ ProductId = input.ReadString();
+ break;
+ }
+ case 16: {
+ Quantity = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class AddItemRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AddItemRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[1]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AddItemRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AddItemRequest(AddItemRequest other) : this() {
+ userId_ = other.userId_;
+ Item = other.item_ != null ? other.Item.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AddItemRequest Clone() {
+ return new AddItemRequest(this);
+ }
+
+ /// Field number for the "user_id" field.
+ public const int UserIdFieldNumber = 1;
+ private string userId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string UserId {
+ get { return userId_; }
+ set {
+ userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "item" field.
+ public const int ItemFieldNumber = 2;
+ private global::Hipstershop.CartItem item_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.CartItem Item {
+ get { return item_; }
+ set {
+ item_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as AddItemRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(AddItemRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (UserId != other.UserId) return false;
+ if (!object.Equals(Item, other.Item)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (UserId.Length != 0) hash ^= UserId.GetHashCode();
+ if (item_ != null) hash ^= Item.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (UserId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(UserId);
+ }
+ if (item_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Item);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (UserId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId);
+ }
+ if (item_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Item);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(AddItemRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.UserId.Length != 0) {
+ UserId = other.UserId;
+ }
+ if (other.item_ != null) {
+ if (item_ == null) {
+ item_ = new global::Hipstershop.CartItem();
+ }
+ Item.MergeFrom(other.Item);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ UserId = input.ReadString();
+ break;
+ }
+ case 18: {
+ if (item_ == null) {
+ item_ = new global::Hipstershop.CartItem();
+ }
+ input.ReadMessage(item_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class EmptyCartRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EmptyCartRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[2]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public EmptyCartRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public EmptyCartRequest(EmptyCartRequest other) : this() {
+ userId_ = other.userId_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public EmptyCartRequest Clone() {
+ return new EmptyCartRequest(this);
+ }
+
+ /// Field number for the "user_id" field.
+ public const int UserIdFieldNumber = 1;
+ private string userId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string UserId {
+ get { return userId_; }
+ set {
+ userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as EmptyCartRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(EmptyCartRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (UserId != other.UserId) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (UserId.Length != 0) hash ^= UserId.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (UserId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(UserId);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (UserId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(EmptyCartRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.UserId.Length != 0) {
+ UserId = other.UserId;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ UserId = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class GetCartRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetCartRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[3]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetCartRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetCartRequest(GetCartRequest other) : this() {
+ userId_ = other.userId_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetCartRequest Clone() {
+ return new GetCartRequest(this);
+ }
+
+ /// Field number for the "user_id" field.
+ public const int UserIdFieldNumber = 1;
+ private string userId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string UserId {
+ get { return userId_; }
+ set {
+ userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as GetCartRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(GetCartRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (UserId != other.UserId) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (UserId.Length != 0) hash ^= UserId.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (UserId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(UserId);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (UserId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(GetCartRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.UserId.Length != 0) {
+ UserId = other.UserId;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ UserId = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class Cart : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Cart());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[4]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Cart() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Cart(Cart other) : this() {
+ userId_ = other.userId_;
+ items_ = other.items_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Cart Clone() {
+ return new Cart(this);
+ }
+
+ /// Field number for the "user_id" field.
+ public const int UserIdFieldNumber = 1;
+ private string userId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string UserId {
+ get { return userId_; }
+ set {
+ userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "items" field.
+ public const int ItemsFieldNumber = 2;
+ private static readonly pb::FieldCodec _repeated_items_codec
+ = pb::FieldCodec.ForMessage(18, global::Hipstershop.CartItem.Parser);
+ private readonly pbc::RepeatedField items_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField Items {
+ get { return items_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as Cart);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(Cart other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (UserId != other.UserId) return false;
+ if(!items_.Equals(other.items_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (UserId.Length != 0) hash ^= UserId.GetHashCode();
+ hash ^= items_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (UserId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(UserId);
+ }
+ items_.WriteTo(output, _repeated_items_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (UserId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId);
+ }
+ size += items_.CalculateSize(_repeated_items_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(Cart other) {
+ if (other == null) {
+ return;
+ }
+ if (other.UserId.Length != 0) {
+ UserId = other.UserId;
+ }
+ items_.Add(other.items_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ UserId = input.ReadString();
+ break;
+ }
+ case 18: {
+ items_.AddEntriesFrom(input, _repeated_items_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class Empty : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Empty());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[5]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Empty() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Empty(Empty other) : this() {
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Empty Clone() {
+ return new Empty(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as Empty);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(Empty other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(Empty other) {
+ if (other == null) {
+ return;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class ListRecommendationsRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ListRecommendationsRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[6]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListRecommendationsRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListRecommendationsRequest(ListRecommendationsRequest other) : this() {
+ userId_ = other.userId_;
+ productIds_ = other.productIds_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListRecommendationsRequest Clone() {
+ return new ListRecommendationsRequest(this);
+ }
+
+ /// Field number for the "user_id" field.
+ public const int UserIdFieldNumber = 1;
+ private string userId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string UserId {
+ get { return userId_; }
+ set {
+ userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "product_ids" field.
+ public const int ProductIdsFieldNumber = 2;
+ private static readonly pb::FieldCodec _repeated_productIds_codec
+ = pb::FieldCodec.ForString(18);
+ private readonly pbc::RepeatedField productIds_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField ProductIds {
+ get { return productIds_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ListRecommendationsRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ListRecommendationsRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (UserId != other.UserId) return false;
+ if(!productIds_.Equals(other.productIds_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (UserId.Length != 0) hash ^= UserId.GetHashCode();
+ hash ^= productIds_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (UserId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(UserId);
+ }
+ productIds_.WriteTo(output, _repeated_productIds_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (UserId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId);
+ }
+ size += productIds_.CalculateSize(_repeated_productIds_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ListRecommendationsRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.UserId.Length != 0) {
+ UserId = other.UserId;
+ }
+ productIds_.Add(other.productIds_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ UserId = input.ReadString();
+ break;
+ }
+ case 18: {
+ productIds_.AddEntriesFrom(input, _repeated_productIds_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class ListRecommendationsResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ListRecommendationsResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[7]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListRecommendationsResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListRecommendationsResponse(ListRecommendationsResponse other) : this() {
+ productIds_ = other.productIds_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListRecommendationsResponse Clone() {
+ return new ListRecommendationsResponse(this);
+ }
+
+ /// Field number for the "product_ids" field.
+ public const int ProductIdsFieldNumber = 1;
+ private static readonly pb::FieldCodec _repeated_productIds_codec
+ = pb::FieldCodec.ForString(10);
+ private readonly pbc::RepeatedField productIds_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField ProductIds {
+ get { return productIds_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ListRecommendationsResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ListRecommendationsResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!productIds_.Equals(other.productIds_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= productIds_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ productIds_.WriteTo(output, _repeated_productIds_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += productIds_.CalculateSize(_repeated_productIds_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ListRecommendationsResponse other) {
+ if (other == null) {
+ return;
+ }
+ productIds_.Add(other.productIds_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ productIds_.AddEntriesFrom(input, _repeated_productIds_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class Product : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Product());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[8]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Product() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Product(Product other) : this() {
+ id_ = other.id_;
+ name_ = other.name_;
+ description_ = other.description_;
+ picture_ = other.picture_;
+ PriceUsd = other.priceUsd_ != null ? other.PriceUsd.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Product Clone() {
+ return new Product(this);
+ }
+
+ /// Field number for the "id" field.
+ public const int IdFieldNumber = 1;
+ private string id_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Id {
+ get { return id_; }
+ set {
+ id_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "name" field.
+ public const int NameFieldNumber = 2;
+ private string name_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Name {
+ get { return name_; }
+ set {
+ name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "description" field.
+ public const int DescriptionFieldNumber = 3;
+ private string description_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Description {
+ get { return description_; }
+ set {
+ description_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "picture" field.
+ public const int PictureFieldNumber = 4;
+ private string picture_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Picture {
+ get { return picture_; }
+ set {
+ picture_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "price_usd" field.
+ public const int PriceUsdFieldNumber = 5;
+ private global::Hipstershop.Money priceUsd_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Money PriceUsd {
+ get { return priceUsd_; }
+ set {
+ priceUsd_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as Product);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(Product other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Id != other.Id) return false;
+ if (Name != other.Name) return false;
+ if (Description != other.Description) return false;
+ if (Picture != other.Picture) return false;
+ if (!object.Equals(PriceUsd, other.PriceUsd)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Id.Length != 0) hash ^= Id.GetHashCode();
+ if (Name.Length != 0) hash ^= Name.GetHashCode();
+ if (Description.Length != 0) hash ^= Description.GetHashCode();
+ if (Picture.Length != 0) hash ^= Picture.GetHashCode();
+ if (priceUsd_ != null) hash ^= PriceUsd.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Id.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Id);
+ }
+ if (Name.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(Name);
+ }
+ if (Description.Length != 0) {
+ output.WriteRawTag(26);
+ output.WriteString(Description);
+ }
+ if (Picture.Length != 0) {
+ output.WriteRawTag(34);
+ output.WriteString(Picture);
+ }
+ if (priceUsd_ != null) {
+ output.WriteRawTag(42);
+ output.WriteMessage(PriceUsd);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (Id.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Id);
+ }
+ if (Name.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+ }
+ if (Description.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Description);
+ }
+ if (Picture.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Picture);
+ }
+ if (priceUsd_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(PriceUsd);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(Product other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Id.Length != 0) {
+ Id = other.Id;
+ }
+ if (other.Name.Length != 0) {
+ Name = other.Name;
+ }
+ if (other.Description.Length != 0) {
+ Description = other.Description;
+ }
+ if (other.Picture.Length != 0) {
+ Picture = other.Picture;
+ }
+ if (other.priceUsd_ != null) {
+ if (priceUsd_ == null) {
+ priceUsd_ = new global::Hipstershop.Money();
+ }
+ PriceUsd.MergeFrom(other.PriceUsd);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ Id = input.ReadString();
+ break;
+ }
+ case 18: {
+ Name = input.ReadString();
+ break;
+ }
+ case 26: {
+ Description = input.ReadString();
+ break;
+ }
+ case 34: {
+ Picture = input.ReadString();
+ break;
+ }
+ case 42: {
+ if (priceUsd_ == null) {
+ priceUsd_ = new global::Hipstershop.Money();
+ }
+ input.ReadMessage(priceUsd_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class ListProductsResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ListProductsResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[9]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListProductsResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListProductsResponse(ListProductsResponse other) : this() {
+ products_ = other.products_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListProductsResponse Clone() {
+ return new ListProductsResponse(this);
+ }
+
+ /// Field number for the "products" field.
+ public const int ProductsFieldNumber = 1;
+ private static readonly pb::FieldCodec _repeated_products_codec
+ = pb::FieldCodec.ForMessage(10, global::Hipstershop.Product.Parser);
+ private readonly pbc::RepeatedField products_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField Products {
+ get { return products_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ListProductsResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ListProductsResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!products_.Equals(other.products_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= products_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ products_.WriteTo(output, _repeated_products_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += products_.CalculateSize(_repeated_products_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ListProductsResponse other) {
+ if (other == null) {
+ return;
+ }
+ products_.Add(other.products_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ products_.AddEntriesFrom(input, _repeated_products_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class GetProductRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetProductRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[10]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetProductRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetProductRequest(GetProductRequest other) : this() {
+ id_ = other.id_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetProductRequest Clone() {
+ return new GetProductRequest(this);
+ }
+
+ /// Field number for the "id" field.
+ public const int IdFieldNumber = 1;
+ private string id_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Id {
+ get { return id_; }
+ set {
+ id_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as GetProductRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(GetProductRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Id != other.Id) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Id.Length != 0) hash ^= Id.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Id.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Id);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (Id.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Id);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(GetProductRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Id.Length != 0) {
+ Id = other.Id;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ Id = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class SearchProductsRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SearchProductsRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[11]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SearchProductsRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SearchProductsRequest(SearchProductsRequest other) : this() {
+ query_ = other.query_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SearchProductsRequest Clone() {
+ return new SearchProductsRequest(this);
+ }
+
+ /// Field number for the "query" field.
+ public const int QueryFieldNumber = 1;
+ private string query_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Query {
+ get { return query_; }
+ set {
+ query_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as SearchProductsRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(SearchProductsRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Query != other.Query) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Query.Length != 0) hash ^= Query.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Query.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Query);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (Query.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Query);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(SearchProductsRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Query.Length != 0) {
+ Query = other.Query;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ Query = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class SearchProductsResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SearchProductsResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[12]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SearchProductsResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SearchProductsResponse(SearchProductsResponse other) : this() {
+ results_ = other.results_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SearchProductsResponse Clone() {
+ return new SearchProductsResponse(this);
+ }
+
+ /// Field number for the "results" field.
+ public const int ResultsFieldNumber = 1;
+ private static readonly pb::FieldCodec _repeated_results_codec
+ = pb::FieldCodec.ForMessage(10, global::Hipstershop.Product.Parser);
+ private readonly pbc::RepeatedField results_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField Results {
+ get { return results_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as SearchProductsResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(SearchProductsResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!results_.Equals(other.results_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= results_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ results_.WriteTo(output, _repeated_results_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += results_.CalculateSize(_repeated_results_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(SearchProductsResponse other) {
+ if (other == null) {
+ return;
+ }
+ results_.Add(other.results_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ results_.AddEntriesFrom(input, _repeated_results_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class GetQuoteRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetQuoteRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[13]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetQuoteRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetQuoteRequest(GetQuoteRequest other) : this() {
+ Address = other.address_ != null ? other.Address.Clone() : null;
+ items_ = other.items_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetQuoteRequest Clone() {
+ return new GetQuoteRequest(this);
+ }
+
+ /// Field number for the "address" field.
+ public const int AddressFieldNumber = 1;
+ private global::Hipstershop.Address address_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Address Address {
+ get { return address_; }
+ set {
+ address_ = value;
+ }
+ }
+
+ /// Field number for the "items" field.
+ public const int ItemsFieldNumber = 2;
+ private static readonly pb::FieldCodec _repeated_items_codec
+ = pb::FieldCodec.ForMessage(18, global::Hipstershop.CartItem.Parser);
+ private readonly pbc::RepeatedField items_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField Items {
+ get { return items_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as GetQuoteRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(GetQuoteRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Address, other.Address)) return false;
+ if(!items_.Equals(other.items_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (address_ != null) hash ^= Address.GetHashCode();
+ hash ^= items_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (address_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Address);
+ }
+ items_.WriteTo(output, _repeated_items_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (address_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Address);
+ }
+ size += items_.CalculateSize(_repeated_items_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(GetQuoteRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.address_ != null) {
+ if (address_ == null) {
+ address_ = new global::Hipstershop.Address();
+ }
+ Address.MergeFrom(other.Address);
+ }
+ items_.Add(other.items_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ if (address_ == null) {
+ address_ = new global::Hipstershop.Address();
+ }
+ input.ReadMessage(address_);
+ break;
+ }
+ case 18: {
+ items_.AddEntriesFrom(input, _repeated_items_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class GetQuoteResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetQuoteResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[14]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetQuoteResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetQuoteResponse(GetQuoteResponse other) : this() {
+ CostUsd = other.costUsd_ != null ? other.CostUsd.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetQuoteResponse Clone() {
+ return new GetQuoteResponse(this);
+ }
+
+ /// Field number for the "cost_usd" field.
+ public const int CostUsdFieldNumber = 1;
+ private global::Hipstershop.Money costUsd_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Money CostUsd {
+ get { return costUsd_; }
+ set {
+ costUsd_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as GetQuoteResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(GetQuoteResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(CostUsd, other.CostUsd)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (costUsd_ != null) hash ^= CostUsd.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (costUsd_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(CostUsd);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (costUsd_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(CostUsd);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(GetQuoteResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.costUsd_ != null) {
+ if (costUsd_ == null) {
+ costUsd_ = new global::Hipstershop.Money();
+ }
+ CostUsd.MergeFrom(other.CostUsd);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ if (costUsd_ == null) {
+ costUsd_ = new global::Hipstershop.Money();
+ }
+ input.ReadMessage(costUsd_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class ShipOrderRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShipOrderRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[15]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ShipOrderRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ShipOrderRequest(ShipOrderRequest other) : this() {
+ Address = other.address_ != null ? other.Address.Clone() : null;
+ items_ = other.items_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ShipOrderRequest Clone() {
+ return new ShipOrderRequest(this);
+ }
+
+ /// Field number for the "address" field.
+ public const int AddressFieldNumber = 1;
+ private global::Hipstershop.Address address_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Address Address {
+ get { return address_; }
+ set {
+ address_ = value;
+ }
+ }
+
+ /// Field number for the "items" field.
+ public const int ItemsFieldNumber = 2;
+ private static readonly pb::FieldCodec _repeated_items_codec
+ = pb::FieldCodec.ForMessage(18, global::Hipstershop.CartItem.Parser);
+ private readonly pbc::RepeatedField items_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField Items {
+ get { return items_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ShipOrderRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ShipOrderRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Address, other.Address)) return false;
+ if(!items_.Equals(other.items_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (address_ != null) hash ^= Address.GetHashCode();
+ hash ^= items_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (address_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Address);
+ }
+ items_.WriteTo(output, _repeated_items_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (address_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Address);
+ }
+ size += items_.CalculateSize(_repeated_items_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ShipOrderRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.address_ != null) {
+ if (address_ == null) {
+ address_ = new global::Hipstershop.Address();
+ }
+ Address.MergeFrom(other.Address);
+ }
+ items_.Add(other.items_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ if (address_ == null) {
+ address_ = new global::Hipstershop.Address();
+ }
+ input.ReadMessage(address_);
+ break;
+ }
+ case 18: {
+ items_.AddEntriesFrom(input, _repeated_items_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class ShipOrderResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShipOrderResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[16]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ShipOrderResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ShipOrderResponse(ShipOrderResponse other) : this() {
+ trackingId_ = other.trackingId_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ShipOrderResponse Clone() {
+ return new ShipOrderResponse(this);
+ }
+
+ /// Field number for the "tracking_id" field.
+ public const int TrackingIdFieldNumber = 1;
+ private string trackingId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string TrackingId {
+ get { return trackingId_; }
+ set {
+ trackingId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ShipOrderResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ShipOrderResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (TrackingId != other.TrackingId) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (TrackingId.Length != 0) hash ^= TrackingId.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (TrackingId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(TrackingId);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (TrackingId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(TrackingId);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ShipOrderResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.TrackingId.Length != 0) {
+ TrackingId = other.TrackingId;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ TrackingId = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class Address : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Address());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[17]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Address() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Address(Address other) : this() {
+ streetAddress_ = other.streetAddress_;
+ city_ = other.city_;
+ state_ = other.state_;
+ country_ = other.country_;
+ zipCode_ = other.zipCode_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Address Clone() {
+ return new Address(this);
+ }
+
+ /// Field number for the "street_address" field.
+ public const int StreetAddressFieldNumber = 1;
+ private string streetAddress_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string StreetAddress {
+ get { return streetAddress_; }
+ set {
+ streetAddress_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "city" field.
+ public const int CityFieldNumber = 2;
+ private string city_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string City {
+ get { return city_; }
+ set {
+ city_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "state" field.
+ public const int StateFieldNumber = 3;
+ private string state_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string State {
+ get { return state_; }
+ set {
+ state_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "country" field.
+ public const int CountryFieldNumber = 4;
+ private string country_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Country {
+ get { return country_; }
+ set {
+ country_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "zip_code" field.
+ public const int ZipCodeFieldNumber = 5;
+ private int zipCode_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int ZipCode {
+ get { return zipCode_; }
+ set {
+ zipCode_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as Address);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(Address other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (StreetAddress != other.StreetAddress) return false;
+ if (City != other.City) return false;
+ if (State != other.State) return false;
+ if (Country != other.Country) return false;
+ if (ZipCode != other.ZipCode) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (StreetAddress.Length != 0) hash ^= StreetAddress.GetHashCode();
+ if (City.Length != 0) hash ^= City.GetHashCode();
+ if (State.Length != 0) hash ^= State.GetHashCode();
+ if (Country.Length != 0) hash ^= Country.GetHashCode();
+ if (ZipCode != 0) hash ^= ZipCode.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (StreetAddress.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(StreetAddress);
+ }
+ if (City.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(City);
+ }
+ if (State.Length != 0) {
+ output.WriteRawTag(26);
+ output.WriteString(State);
+ }
+ if (Country.Length != 0) {
+ output.WriteRawTag(34);
+ output.WriteString(Country);
+ }
+ if (ZipCode != 0) {
+ output.WriteRawTag(40);
+ output.WriteInt32(ZipCode);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (StreetAddress.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(StreetAddress);
+ }
+ if (City.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(City);
+ }
+ if (State.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(State);
+ }
+ if (Country.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Country);
+ }
+ if (ZipCode != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ZipCode);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(Address other) {
+ if (other == null) {
+ return;
+ }
+ if (other.StreetAddress.Length != 0) {
+ StreetAddress = other.StreetAddress;
+ }
+ if (other.City.Length != 0) {
+ City = other.City;
+ }
+ if (other.State.Length != 0) {
+ State = other.State;
+ }
+ if (other.Country.Length != 0) {
+ Country = other.Country;
+ }
+ if (other.ZipCode != 0) {
+ ZipCode = other.ZipCode;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ StreetAddress = input.ReadString();
+ break;
+ }
+ case 18: {
+ City = input.ReadString();
+ break;
+ }
+ case 26: {
+ State = input.ReadString();
+ break;
+ }
+ case 34: {
+ Country = input.ReadString();
+ break;
+ }
+ case 40: {
+ ZipCode = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ ///
+ /// Represents an amount of money with its currency type.
+ ///
+ public sealed partial class Money : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Money());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[18]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Money() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Money(Money other) : this() {
+ currencyCode_ = other.currencyCode_;
+ units_ = other.units_;
+ nanos_ = other.nanos_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Money Clone() {
+ return new Money(this);
+ }
+
+ /// Field number for the "currency_code" field.
+ public const int CurrencyCodeFieldNumber = 1;
+ private string currencyCode_ = "";
+ ///
+ /// The 3-letter currency code defined in ISO 4217.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string CurrencyCode {
+ get { return currencyCode_; }
+ set {
+ currencyCode_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "units" field.
+ public const int UnitsFieldNumber = 2;
+ private long units_;
+ ///
+ /// The whole units of the amount.
+ /// For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public long Units {
+ get { return units_; }
+ set {
+ units_ = value;
+ }
+ }
+
+ /// Field number for the "nanos" field.
+ public const int NanosFieldNumber = 3;
+ private int nanos_;
+ ///
+ /// 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.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int Nanos {
+ get { return nanos_; }
+ set {
+ nanos_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as Money);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(Money other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (CurrencyCode != other.CurrencyCode) return false;
+ if (Units != other.Units) return false;
+ if (Nanos != other.Nanos) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (CurrencyCode.Length != 0) hash ^= CurrencyCode.GetHashCode();
+ if (Units != 0L) hash ^= Units.GetHashCode();
+ if (Nanos != 0) hash ^= Nanos.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (CurrencyCode.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(CurrencyCode);
+ }
+ if (Units != 0L) {
+ output.WriteRawTag(16);
+ output.WriteInt64(Units);
+ }
+ if (Nanos != 0) {
+ output.WriteRawTag(24);
+ output.WriteInt32(Nanos);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (CurrencyCode.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(CurrencyCode);
+ }
+ if (Units != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Units);
+ }
+ if (Nanos != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(Money other) {
+ if (other == null) {
+ return;
+ }
+ if (other.CurrencyCode.Length != 0) {
+ CurrencyCode = other.CurrencyCode;
+ }
+ if (other.Units != 0L) {
+ Units = other.Units;
+ }
+ if (other.Nanos != 0) {
+ Nanos = other.Nanos;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ CurrencyCode = input.ReadString();
+ break;
+ }
+ case 16: {
+ Units = input.ReadInt64();
+ break;
+ }
+ case 24: {
+ Nanos = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class GetSupportedCurrenciesResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetSupportedCurrenciesResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[19]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetSupportedCurrenciesResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetSupportedCurrenciesResponse(GetSupportedCurrenciesResponse other) : this() {
+ currencyCodes_ = other.currencyCodes_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public GetSupportedCurrenciesResponse Clone() {
+ return new GetSupportedCurrenciesResponse(this);
+ }
+
+ /// Field number for the "currency_codes" field.
+ public const int CurrencyCodesFieldNumber = 1;
+ private static readonly pb::FieldCodec _repeated_currencyCodes_codec
+ = pb::FieldCodec.ForString(10);
+ private readonly pbc::RepeatedField currencyCodes_ = new pbc::RepeatedField();
+ ///
+ /// The 3-letter currency code defined in ISO 4217.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField CurrencyCodes {
+ get { return currencyCodes_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as GetSupportedCurrenciesResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(GetSupportedCurrenciesResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!currencyCodes_.Equals(other.currencyCodes_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= currencyCodes_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ currencyCodes_.WriteTo(output, _repeated_currencyCodes_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += currencyCodes_.CalculateSize(_repeated_currencyCodes_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(GetSupportedCurrenciesResponse other) {
+ if (other == null) {
+ return;
+ }
+ currencyCodes_.Add(other.currencyCodes_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ currencyCodes_.AddEntriesFrom(input, _repeated_currencyCodes_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class CurrencyConversionRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CurrencyConversionRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[20]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CurrencyConversionRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CurrencyConversionRequest(CurrencyConversionRequest other) : this() {
+ From = other.from_ != null ? other.From.Clone() : null;
+ toCode_ = other.toCode_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CurrencyConversionRequest Clone() {
+ return new CurrencyConversionRequest(this);
+ }
+
+ /// Field number for the "from" field.
+ public const int FromFieldNumber = 1;
+ private global::Hipstershop.Money from_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Money From {
+ get { return from_; }
+ set {
+ from_ = value;
+ }
+ }
+
+ /// Field number for the "to_code" field.
+ public const int ToCodeFieldNumber = 2;
+ private string toCode_ = "";
+ ///
+ /// The 3-letter currency code defined in ISO 4217.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string ToCode {
+ get { return toCode_; }
+ set {
+ toCode_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as CurrencyConversionRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(CurrencyConversionRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(From, other.From)) return false;
+ if (ToCode != other.ToCode) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (from_ != null) hash ^= From.GetHashCode();
+ if (ToCode.Length != 0) hash ^= ToCode.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (from_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(From);
+ }
+ if (ToCode.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(ToCode);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (from_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(From);
+ }
+ if (ToCode.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ToCode);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(CurrencyConversionRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.from_ != null) {
+ if (from_ == null) {
+ from_ = new global::Hipstershop.Money();
+ }
+ From.MergeFrom(other.From);
+ }
+ if (other.ToCode.Length != 0) {
+ ToCode = other.ToCode;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ if (from_ == null) {
+ from_ = new global::Hipstershop.Money();
+ }
+ input.ReadMessage(from_);
+ break;
+ }
+ case 18: {
+ ToCode = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class CreditCardInfo : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreditCardInfo());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[21]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CreditCardInfo() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CreditCardInfo(CreditCardInfo other) : this() {
+ creditCardNumber_ = other.creditCardNumber_;
+ creditCardCvv_ = other.creditCardCvv_;
+ creditCardExpirationYear_ = other.creditCardExpirationYear_;
+ creditCardExpirationMonth_ = other.creditCardExpirationMonth_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public CreditCardInfo Clone() {
+ return new CreditCardInfo(this);
+ }
+
+ /// Field number for the "credit_card_number" field.
+ public const int CreditCardNumberFieldNumber = 1;
+ private string creditCardNumber_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string CreditCardNumber {
+ get { return creditCardNumber_; }
+ set {
+ creditCardNumber_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "credit_card_cvv" field.
+ public const int CreditCardCvvFieldNumber = 2;
+ private int creditCardCvv_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CreditCardCvv {
+ get { return creditCardCvv_; }
+ set {
+ creditCardCvv_ = value;
+ }
+ }
+
+ /// Field number for the "credit_card_expiration_year" field.
+ public const int CreditCardExpirationYearFieldNumber = 3;
+ private int creditCardExpirationYear_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CreditCardExpirationYear {
+ get { return creditCardExpirationYear_; }
+ set {
+ creditCardExpirationYear_ = value;
+ }
+ }
+
+ /// Field number for the "credit_card_expiration_month" field.
+ public const int CreditCardExpirationMonthFieldNumber = 4;
+ private int creditCardExpirationMonth_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CreditCardExpirationMonth {
+ get { return creditCardExpirationMonth_; }
+ set {
+ creditCardExpirationMonth_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as CreditCardInfo);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(CreditCardInfo other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (CreditCardNumber != other.CreditCardNumber) return false;
+ if (CreditCardCvv != other.CreditCardCvv) return false;
+ if (CreditCardExpirationYear != other.CreditCardExpirationYear) return false;
+ if (CreditCardExpirationMonth != other.CreditCardExpirationMonth) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (CreditCardNumber.Length != 0) hash ^= CreditCardNumber.GetHashCode();
+ if (CreditCardCvv != 0) hash ^= CreditCardCvv.GetHashCode();
+ if (CreditCardExpirationYear != 0) hash ^= CreditCardExpirationYear.GetHashCode();
+ if (CreditCardExpirationMonth != 0) hash ^= CreditCardExpirationMonth.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (CreditCardNumber.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(CreditCardNumber);
+ }
+ if (CreditCardCvv != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(CreditCardCvv);
+ }
+ if (CreditCardExpirationYear != 0) {
+ output.WriteRawTag(24);
+ output.WriteInt32(CreditCardExpirationYear);
+ }
+ if (CreditCardExpirationMonth != 0) {
+ output.WriteRawTag(32);
+ output.WriteInt32(CreditCardExpirationMonth);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (CreditCardNumber.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(CreditCardNumber);
+ }
+ if (CreditCardCvv != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(CreditCardCvv);
+ }
+ if (CreditCardExpirationYear != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(CreditCardExpirationYear);
+ }
+ if (CreditCardExpirationMonth != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(CreditCardExpirationMonth);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(CreditCardInfo other) {
+ if (other == null) {
+ return;
+ }
+ if (other.CreditCardNumber.Length != 0) {
+ CreditCardNumber = other.CreditCardNumber;
+ }
+ if (other.CreditCardCvv != 0) {
+ CreditCardCvv = other.CreditCardCvv;
+ }
+ if (other.CreditCardExpirationYear != 0) {
+ CreditCardExpirationYear = other.CreditCardExpirationYear;
+ }
+ if (other.CreditCardExpirationMonth != 0) {
+ CreditCardExpirationMonth = other.CreditCardExpirationMonth;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ CreditCardNumber = input.ReadString();
+ break;
+ }
+ case 16: {
+ CreditCardCvv = input.ReadInt32();
+ break;
+ }
+ case 24: {
+ CreditCardExpirationYear = input.ReadInt32();
+ break;
+ }
+ case 32: {
+ CreditCardExpirationMonth = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class ChargeRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ChargeRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[22]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ChargeRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ChargeRequest(ChargeRequest other) : this() {
+ Amount = other.amount_ != null ? other.Amount.Clone() : null;
+ CreditCard = other.creditCard_ != null ? other.CreditCard.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ChargeRequest Clone() {
+ return new ChargeRequest(this);
+ }
+
+ /// Field number for the "amount" field.
+ public const int AmountFieldNumber = 1;
+ private global::Hipstershop.Money amount_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Money Amount {
+ get { return amount_; }
+ set {
+ amount_ = value;
+ }
+ }
+
+ /// Field number for the "credit_card" field.
+ public const int CreditCardFieldNumber = 2;
+ private global::Hipstershop.CreditCardInfo creditCard_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.CreditCardInfo CreditCard {
+ get { return creditCard_; }
+ set {
+ creditCard_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ChargeRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ChargeRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Amount, other.Amount)) return false;
+ if (!object.Equals(CreditCard, other.CreditCard)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (amount_ != null) hash ^= Amount.GetHashCode();
+ if (creditCard_ != null) hash ^= CreditCard.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (amount_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Amount);
+ }
+ if (creditCard_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(CreditCard);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (amount_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Amount);
+ }
+ if (creditCard_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(CreditCard);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ChargeRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.amount_ != null) {
+ if (amount_ == null) {
+ amount_ = new global::Hipstershop.Money();
+ }
+ Amount.MergeFrom(other.Amount);
+ }
+ if (other.creditCard_ != null) {
+ if (creditCard_ == null) {
+ creditCard_ = new global::Hipstershop.CreditCardInfo();
+ }
+ CreditCard.MergeFrom(other.CreditCard);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ if (amount_ == null) {
+ amount_ = new global::Hipstershop.Money();
+ }
+ input.ReadMessage(amount_);
+ break;
+ }
+ case 18: {
+ if (creditCard_ == null) {
+ creditCard_ = new global::Hipstershop.CreditCardInfo();
+ }
+ input.ReadMessage(creditCard_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class ChargeResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ChargeResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[23]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ChargeResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ChargeResponse(ChargeResponse other) : this() {
+ transactionId_ = other.transactionId_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ChargeResponse Clone() {
+ return new ChargeResponse(this);
+ }
+
+ /// Field number for the "transaction_id" field.
+ public const int TransactionIdFieldNumber = 1;
+ private string transactionId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string TransactionId {
+ get { return transactionId_; }
+ set {
+ transactionId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ChargeResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ChargeResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (TransactionId != other.TransactionId) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (TransactionId.Length != 0) hash ^= TransactionId.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (TransactionId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(TransactionId);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (TransactionId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(TransactionId);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ChargeResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.TransactionId.Length != 0) {
+ TransactionId = other.TransactionId;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ TransactionId = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class OrderItem : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OrderItem());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[24]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public OrderItem() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public OrderItem(OrderItem other) : this() {
+ Item = other.item_ != null ? other.Item.Clone() : null;
+ Cost = other.cost_ != null ? other.Cost.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public OrderItem Clone() {
+ return new OrderItem(this);
+ }
+
+ /// Field number for the "item" field.
+ public const int ItemFieldNumber = 1;
+ private global::Hipstershop.CartItem item_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.CartItem Item {
+ get { return item_; }
+ set {
+ item_ = value;
+ }
+ }
+
+ /// Field number for the "cost" field.
+ public const int CostFieldNumber = 2;
+ private global::Hipstershop.Money cost_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Money Cost {
+ get { return cost_; }
+ set {
+ cost_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as OrderItem);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(OrderItem other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Item, other.Item)) return false;
+ if (!object.Equals(Cost, other.Cost)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (item_ != null) hash ^= Item.GetHashCode();
+ if (cost_ != null) hash ^= Cost.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (item_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Item);
+ }
+ if (cost_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Cost);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (item_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Item);
+ }
+ if (cost_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Cost);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(OrderItem other) {
+ if (other == null) {
+ return;
+ }
+ if (other.item_ != null) {
+ if (item_ == null) {
+ item_ = new global::Hipstershop.CartItem();
+ }
+ Item.MergeFrom(other.Item);
+ }
+ if (other.cost_ != null) {
+ if (cost_ == null) {
+ cost_ = new global::Hipstershop.Money();
+ }
+ Cost.MergeFrom(other.Cost);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ if (item_ == null) {
+ item_ = new global::Hipstershop.CartItem();
+ }
+ input.ReadMessage(item_);
+ break;
+ }
+ case 18: {
+ if (cost_ == null) {
+ cost_ = new global::Hipstershop.Money();
+ }
+ input.ReadMessage(cost_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class OrderResult : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OrderResult());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[25]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public OrderResult() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public OrderResult(OrderResult other) : this() {
+ orderId_ = other.orderId_;
+ shippingTrackingId_ = other.shippingTrackingId_;
+ ShippingCost = other.shippingCost_ != null ? other.ShippingCost.Clone() : null;
+ ShippingAddress = other.shippingAddress_ != null ? other.ShippingAddress.Clone() : null;
+ items_ = other.items_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public OrderResult Clone() {
+ return new OrderResult(this);
+ }
+
+ /// Field number for the "order_id" field.
+ public const int OrderIdFieldNumber = 1;
+ private string orderId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string OrderId {
+ get { return orderId_; }
+ set {
+ orderId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "shipping_tracking_id" field.
+ public const int ShippingTrackingIdFieldNumber = 2;
+ private string shippingTrackingId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string ShippingTrackingId {
+ get { return shippingTrackingId_; }
+ set {
+ shippingTrackingId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "shipping_cost" field.
+ public const int ShippingCostFieldNumber = 3;
+ private global::Hipstershop.Money shippingCost_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Money ShippingCost {
+ get { return shippingCost_; }
+ set {
+ shippingCost_ = value;
+ }
+ }
+
+ /// Field number for the "shipping_address" field.
+ public const int ShippingAddressFieldNumber = 4;
+ private global::Hipstershop.Address shippingAddress_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Address ShippingAddress {
+ get { return shippingAddress_; }
+ set {
+ shippingAddress_ = value;
+ }
+ }
+
+ /// Field number for the "items" field.
+ public const int ItemsFieldNumber = 5;
+ private static readonly pb::FieldCodec _repeated_items_codec
+ = pb::FieldCodec.ForMessage(42, global::Hipstershop.OrderItem.Parser);
+ private readonly pbc::RepeatedField items_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField Items {
+ get { return items_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as OrderResult);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(OrderResult other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (OrderId != other.OrderId) return false;
+ if (ShippingTrackingId != other.ShippingTrackingId) return false;
+ if (!object.Equals(ShippingCost, other.ShippingCost)) return false;
+ if (!object.Equals(ShippingAddress, other.ShippingAddress)) return false;
+ if(!items_.Equals(other.items_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (OrderId.Length != 0) hash ^= OrderId.GetHashCode();
+ if (ShippingTrackingId.Length != 0) hash ^= ShippingTrackingId.GetHashCode();
+ if (shippingCost_ != null) hash ^= ShippingCost.GetHashCode();
+ if (shippingAddress_ != null) hash ^= ShippingAddress.GetHashCode();
+ hash ^= items_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (OrderId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(OrderId);
+ }
+ if (ShippingTrackingId.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(ShippingTrackingId);
+ }
+ if (shippingCost_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(ShippingCost);
+ }
+ if (shippingAddress_ != null) {
+ output.WriteRawTag(34);
+ output.WriteMessage(ShippingAddress);
+ }
+ items_.WriteTo(output, _repeated_items_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (OrderId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderId);
+ }
+ if (ShippingTrackingId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ShippingTrackingId);
+ }
+ if (shippingCost_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ShippingCost);
+ }
+ if (shippingAddress_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ShippingAddress);
+ }
+ size += items_.CalculateSize(_repeated_items_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(OrderResult other) {
+ if (other == null) {
+ return;
+ }
+ if (other.OrderId.Length != 0) {
+ OrderId = other.OrderId;
+ }
+ if (other.ShippingTrackingId.Length != 0) {
+ ShippingTrackingId = other.ShippingTrackingId;
+ }
+ if (other.shippingCost_ != null) {
+ if (shippingCost_ == null) {
+ shippingCost_ = new global::Hipstershop.Money();
+ }
+ ShippingCost.MergeFrom(other.ShippingCost);
+ }
+ if (other.shippingAddress_ != null) {
+ if (shippingAddress_ == null) {
+ shippingAddress_ = new global::Hipstershop.Address();
+ }
+ ShippingAddress.MergeFrom(other.ShippingAddress);
+ }
+ items_.Add(other.items_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ OrderId = input.ReadString();
+ break;
+ }
+ case 18: {
+ ShippingTrackingId = input.ReadString();
+ break;
+ }
+ case 26: {
+ if (shippingCost_ == null) {
+ shippingCost_ = new global::Hipstershop.Money();
+ }
+ input.ReadMessage(shippingCost_);
+ break;
+ }
+ case 34: {
+ if (shippingAddress_ == null) {
+ shippingAddress_ = new global::Hipstershop.Address();
+ }
+ input.ReadMessage(shippingAddress_);
+ break;
+ }
+ case 42: {
+ items_.AddEntriesFrom(input, _repeated_items_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class SendOrderConfirmationRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SendOrderConfirmationRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[26]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SendOrderConfirmationRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SendOrderConfirmationRequest(SendOrderConfirmationRequest other) : this() {
+ email_ = other.email_;
+ Order = other.order_ != null ? other.Order.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public SendOrderConfirmationRequest Clone() {
+ return new SendOrderConfirmationRequest(this);
+ }
+
+ /// Field number for the "email" field.
+ public const int EmailFieldNumber = 1;
+ private string email_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Email {
+ get { return email_; }
+ set {
+ email_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "order" field.
+ public const int OrderFieldNumber = 2;
+ private global::Hipstershop.OrderResult order_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.OrderResult Order {
+ get { return order_; }
+ set {
+ order_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as SendOrderConfirmationRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(SendOrderConfirmationRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Email != other.Email) return false;
+ if (!object.Equals(Order, other.Order)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Email.Length != 0) hash ^= Email.GetHashCode();
+ if (order_ != null) hash ^= Order.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Email.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Email);
+ }
+ if (order_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Order);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (Email.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Email);
+ }
+ if (order_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Order);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(SendOrderConfirmationRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Email.Length != 0) {
+ Email = other.Email;
+ }
+ if (other.order_ != null) {
+ if (order_ == null) {
+ order_ = new global::Hipstershop.OrderResult();
+ }
+ Order.MergeFrom(other.Order);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ Email = input.ReadString();
+ break;
+ }
+ case 18: {
+ if (order_ == null) {
+ order_ = new global::Hipstershop.OrderResult();
+ }
+ input.ReadMessage(order_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class PlaceOrderRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlaceOrderRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[27]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public PlaceOrderRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public PlaceOrderRequest(PlaceOrderRequest other) : this() {
+ userId_ = other.userId_;
+ userCurrency_ = other.userCurrency_;
+ Address = other.address_ != null ? other.Address.Clone() : null;
+ email_ = other.email_;
+ CreditCard = other.creditCard_ != null ? other.CreditCard.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public PlaceOrderRequest Clone() {
+ return new PlaceOrderRequest(this);
+ }
+
+ /// Field number for the "user_id" field.
+ public const int UserIdFieldNumber = 1;
+ private string userId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string UserId {
+ get { return userId_; }
+ set {
+ userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "user_currency" field.
+ public const int UserCurrencyFieldNumber = 2;
+ private string userCurrency_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string UserCurrency {
+ get { return userCurrency_; }
+ set {
+ userCurrency_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "address" field.
+ public const int AddressFieldNumber = 3;
+ private global::Hipstershop.Address address_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.Address Address {
+ get { return address_; }
+ set {
+ address_ = value;
+ }
+ }
+
+ /// Field number for the "email" field.
+ public const int EmailFieldNumber = 5;
+ private string email_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Email {
+ get { return email_; }
+ set {
+ email_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "credit_card" field.
+ public const int CreditCardFieldNumber = 6;
+ private global::Hipstershop.CreditCardInfo creditCard_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.CreditCardInfo CreditCard {
+ get { return creditCard_; }
+ set {
+ creditCard_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as PlaceOrderRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(PlaceOrderRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (UserId != other.UserId) return false;
+ if (UserCurrency != other.UserCurrency) return false;
+ if (!object.Equals(Address, other.Address)) return false;
+ if (Email != other.Email) return false;
+ if (!object.Equals(CreditCard, other.CreditCard)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (UserId.Length != 0) hash ^= UserId.GetHashCode();
+ if (UserCurrency.Length != 0) hash ^= UserCurrency.GetHashCode();
+ if (address_ != null) hash ^= Address.GetHashCode();
+ if (Email.Length != 0) hash ^= Email.GetHashCode();
+ if (creditCard_ != null) hash ^= CreditCard.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (UserId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(UserId);
+ }
+ if (UserCurrency.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(UserCurrency);
+ }
+ if (address_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(Address);
+ }
+ if (Email.Length != 0) {
+ output.WriteRawTag(42);
+ output.WriteString(Email);
+ }
+ if (creditCard_ != null) {
+ output.WriteRawTag(50);
+ output.WriteMessage(CreditCard);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (UserId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId);
+ }
+ if (UserCurrency.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(UserCurrency);
+ }
+ if (address_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Address);
+ }
+ if (Email.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Email);
+ }
+ if (creditCard_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(CreditCard);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(PlaceOrderRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.UserId.Length != 0) {
+ UserId = other.UserId;
+ }
+ if (other.UserCurrency.Length != 0) {
+ UserCurrency = other.UserCurrency;
+ }
+ if (other.address_ != null) {
+ if (address_ == null) {
+ address_ = new global::Hipstershop.Address();
+ }
+ Address.MergeFrom(other.Address);
+ }
+ if (other.Email.Length != 0) {
+ Email = other.Email;
+ }
+ if (other.creditCard_ != null) {
+ if (creditCard_ == null) {
+ creditCard_ = new global::Hipstershop.CreditCardInfo();
+ }
+ CreditCard.MergeFrom(other.CreditCard);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ UserId = input.ReadString();
+ break;
+ }
+ case 18: {
+ UserCurrency = input.ReadString();
+ break;
+ }
+ case 26: {
+ if (address_ == null) {
+ address_ = new global::Hipstershop.Address();
+ }
+ input.ReadMessage(address_);
+ break;
+ }
+ case 42: {
+ Email = input.ReadString();
+ break;
+ }
+ case 50: {
+ if (creditCard_ == null) {
+ creditCard_ = new global::Hipstershop.CreditCardInfo();
+ }
+ input.ReadMessage(creditCard_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class PlaceOrderResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlaceOrderResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[28]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public PlaceOrderResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public PlaceOrderResponse(PlaceOrderResponse other) : this() {
+ Order = other.order_ != null ? other.Order.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public PlaceOrderResponse Clone() {
+ return new PlaceOrderResponse(this);
+ }
+
+ /// Field number for the "order" field.
+ public const int OrderFieldNumber = 1;
+ private global::Hipstershop.OrderResult order_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Hipstershop.OrderResult Order {
+ get { return order_; }
+ set {
+ order_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as PlaceOrderResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(PlaceOrderResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Order, other.Order)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (order_ != null) hash ^= Order.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (order_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Order);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (order_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Order);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(PlaceOrderResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.order_ != null) {
+ if (order_ == null) {
+ order_ = new global::Hipstershop.OrderResult();
+ }
+ Order.MergeFrom(other.Order);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ if (order_ == null) {
+ order_ = new global::Hipstershop.OrderResult();
+ }
+ input.ReadMessage(order_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class AdRequest : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AdRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[29]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AdRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AdRequest(AdRequest other) : this() {
+ contextKeys_ = other.contextKeys_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AdRequest Clone() {
+ return new AdRequest(this);
+ }
+
+ /// Field number for the "context_keys" field.
+ public const int ContextKeysFieldNumber = 1;
+ private static readonly pb::FieldCodec _repeated_contextKeys_codec
+ = pb::FieldCodec.ForString(10);
+ private readonly pbc::RepeatedField contextKeys_ = new pbc::RepeatedField();
+ ///
+ /// List of important key words from the current page describing the context.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField ContextKeys {
+ get { return contextKeys_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as AdRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(AdRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!contextKeys_.Equals(other.contextKeys_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= contextKeys_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ contextKeys_.WriteTo(output, _repeated_contextKeys_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += contextKeys_.CalculateSize(_repeated_contextKeys_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(AdRequest other) {
+ if (other == null) {
+ return;
+ }
+ contextKeys_.Add(other.contextKeys_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ contextKeys_.AddEntriesFrom(input, _repeated_contextKeys_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class AdResponse : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AdResponse());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[30]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AdResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AdResponse(AdResponse other) : this() {
+ ads_ = other.ads_.Clone();
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public AdResponse Clone() {
+ return new AdResponse(this);
+ }
+
+ /// Field number for the "ads" field.
+ public const int AdsFieldNumber = 1;
+ private static readonly pb::FieldCodec _repeated_ads_codec
+ = pb::FieldCodec.ForMessage(10, global::Hipstershop.Ad.Parser);
+ private readonly pbc::RepeatedField ads_ = new pbc::RepeatedField();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField Ads {
+ get { return ads_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as AdResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(AdResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!ads_.Equals(other.ads_)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= ads_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ ads_.WriteTo(output, _repeated_ads_codec);
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += ads_.CalculateSize(_repeated_ads_codec);
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(AdResponse other) {
+ if (other == null) {
+ return;
+ }
+ ads_.Add(other.ads_);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ ads_.AddEntriesFrom(input, _repeated_ads_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public sealed partial class Ad : pb::IMessage {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Ad());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Hipstershop.DemoReflection.Descriptor.MessageTypes[31]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Ad() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Ad(Ad other) : this() {
+ redirectUrl_ = other.redirectUrl_;
+ text_ = other.text_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public Ad Clone() {
+ return new Ad(this);
+ }
+
+ /// Field number for the "redirect_url" field.
+ public const int RedirectUrlFieldNumber = 1;
+ private string redirectUrl_ = "";
+ ///
+ /// url to redirect to when an ad is clicked.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string RedirectUrl {
+ get { return redirectUrl_; }
+ set {
+ redirectUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "text" field.
+ public const int TextFieldNumber = 2;
+ private string text_ = "";
+ ///
+ /// short advertisement text to display.
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Text {
+ get { return text_; }
+ set {
+ text_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as Ad);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(Ad other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (RedirectUrl != other.RedirectUrl) return false;
+ if (Text != other.Text) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (RedirectUrl.Length != 0) hash ^= RedirectUrl.GetHashCode();
+ if (Text.Length != 0) hash ^= Text.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (RedirectUrl.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(RedirectUrl);
+ }
+ if (Text.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(Text);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (RedirectUrl.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(RedirectUrl);
+ }
+ if (Text.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Text);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(Ad other) {
+ if (other == null) {
+ return;
+ }
+ if (other.RedirectUrl.Length != 0) {
+ RedirectUrl = other.RedirectUrl;
+ }
+ if (other.Text.Length != 0) {
+ Text = other.Text;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ RedirectUrl = input.ReadString();
+ break;
+ }
+ case 18: {
+ Text = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/hiptershop-ecommerce/src/cartservice/grpc_generated/DemoGrpc.cs b/hiptershop-ecommerce/src/cartservice/grpc_generated/DemoGrpc.cs
new file mode 100644
index 000000000..fa263ae66
--- /dev/null
+++ b/hiptershop-ecommerce/src/cartservice/grpc_generated/DemoGrpc.cs
@@ -0,0 +1,962 @@
+//
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: demo.proto
+//
+#pragma warning disable 1591
+#region Designer generated code
+
+using grpc = global::Grpc.Core;
+
+namespace Hipstershop {
+ public static partial class CartService
+ {
+ static readonly string __ServiceName = "hipstershop.CartService";
+
+ static readonly grpc::Marshaller __Marshaller_AddItemRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.AddItemRequest.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.Empty.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_GetCartRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.GetCartRequest.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_Cart = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.Cart.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_EmptyCartRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.EmptyCartRequest.Parser.ParseFrom);
+
+ static readonly grpc::Method __Method_AddItem = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "AddItem",
+ __Marshaller_AddItemRequest,
+ __Marshaller_Empty);
+
+ static readonly grpc::Method __Method_GetCart = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "GetCart",
+ __Marshaller_GetCartRequest,
+ __Marshaller_Cart);
+
+ static readonly grpc::Method __Method_EmptyCart = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "EmptyCart",
+ __Marshaller_EmptyCartRequest,
+ __Marshaller_Empty);
+
+ /// Service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Hipstershop.DemoReflection.Descriptor.Services[0]; }
+ }
+
+ /// Base class for server-side implementations of CartService
+ public abstract partial class CartServiceBase
+ {
+ public virtual global::System.Threading.Tasks.Task AddItem(global::Hipstershop.AddItemRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ public virtual global::System.Threading.Tasks.Task GetCart(global::Hipstershop.GetCartRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ public virtual global::System.Threading.Tasks.Task EmptyCart(global::Hipstershop.EmptyCartRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// Client for CartService
+ public partial class CartServiceClient : grpc::ClientBase
+ {
+ /// Creates a new client for CartService
+ /// The channel to use to make remote calls.
+ public CartServiceClient(grpc::Channel channel) : base(channel)
+ {
+ }
+ /// Creates a new client for CartService that uses a custom CallInvoker.
+ /// The callInvoker to use to make remote calls.
+ public CartServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ /// Protected parameterless constructor to allow creation of test doubles.
+ protected CartServiceClient() : base()
+ {
+ }
+ /// Protected constructor to allow creation of configured clients.
+ /// The client configuration.
+ protected CartServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ public virtual global::Hipstershop.Empty AddItem(global::Hipstershop.AddItemRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return AddItem(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Hipstershop.Empty AddItem(global::Hipstershop.AddItemRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_AddItem, null, options, request);
+ }
+ public virtual grpc::AsyncUnaryCall AddItemAsync(global::Hipstershop.AddItemRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return AddItemAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual grpc::AsyncUnaryCall AddItemAsync(global::Hipstershop.AddItemRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_AddItem, null, options, request);
+ }
+ public virtual global::Hipstershop.Cart GetCart(global::Hipstershop.GetCartRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return GetCart(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Hipstershop.Cart GetCart(global::Hipstershop.GetCartRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_GetCart, null, options, request);
+ }
+ public virtual grpc::AsyncUnaryCall GetCartAsync(global::Hipstershop.GetCartRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return GetCartAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual grpc::AsyncUnaryCall GetCartAsync(global::Hipstershop.GetCartRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_GetCart, null, options, request);
+ }
+ public virtual global::Hipstershop.Empty EmptyCart(global::Hipstershop.EmptyCartRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return EmptyCart(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Hipstershop.Empty EmptyCart(global::Hipstershop.EmptyCartRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_EmptyCart, null, options, request);
+ }
+ public virtual grpc::AsyncUnaryCall EmptyCartAsync(global::Hipstershop.EmptyCartRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return EmptyCartAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual grpc::AsyncUnaryCall EmptyCartAsync(global::Hipstershop.EmptyCartRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_EmptyCart, null, options, request);
+ }
+ /// Creates a new instance of client from given ClientBaseConfiguration.
+ protected override CartServiceClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new CartServiceClient(configuration);
+ }
+ }
+
+ /// Creates service definition that can be registered with a server
+ /// An object implementing the server-side handling logic.
+ public static grpc::ServerServiceDefinition BindService(CartServiceBase serviceImpl)
+ {
+ return grpc::ServerServiceDefinition.CreateBuilder()
+ .AddMethod(__Method_AddItem, serviceImpl.AddItem)
+ .AddMethod(__Method_GetCart, serviceImpl.GetCart)
+ .AddMethod(__Method_EmptyCart, serviceImpl.EmptyCart).Build();
+ }
+
+ }
+ public static partial class RecommendationService
+ {
+ static readonly string __ServiceName = "hipstershop.RecommendationService";
+
+ static readonly grpc::Marshaller __Marshaller_ListRecommendationsRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.ListRecommendationsRequest.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_ListRecommendationsResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.ListRecommendationsResponse.Parser.ParseFrom);
+
+ static readonly grpc::Method __Method_ListRecommendations = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "ListRecommendations",
+ __Marshaller_ListRecommendationsRequest,
+ __Marshaller_ListRecommendationsResponse);
+
+ /// Service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Hipstershop.DemoReflection.Descriptor.Services[1]; }
+ }
+
+ /// Base class for server-side implementations of RecommendationService
+ public abstract partial class RecommendationServiceBase
+ {
+ public virtual global::System.Threading.Tasks.Task ListRecommendations(global::Hipstershop.ListRecommendationsRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// Client for RecommendationService
+ public partial class RecommendationServiceClient : grpc::ClientBase
+ {
+ /// Creates a new client for RecommendationService
+ /// The channel to use to make remote calls.
+ public RecommendationServiceClient(grpc::Channel channel) : base(channel)
+ {
+ }
+ /// Creates a new client for RecommendationService that uses a custom CallInvoker.
+ /// The callInvoker to use to make remote calls.
+ public RecommendationServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ /// Protected parameterless constructor to allow creation of test doubles.
+ protected RecommendationServiceClient() : base()
+ {
+ }
+ /// Protected constructor to allow creation of configured clients.
+ /// The client configuration.
+ protected RecommendationServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ public virtual global::Hipstershop.ListRecommendationsResponse ListRecommendations(global::Hipstershop.ListRecommendationsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return ListRecommendations(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Hipstershop.ListRecommendationsResponse ListRecommendations(global::Hipstershop.ListRecommendationsRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_ListRecommendations, null, options, request);
+ }
+ public virtual grpc::AsyncUnaryCall ListRecommendationsAsync(global::Hipstershop.ListRecommendationsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return ListRecommendationsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual grpc::AsyncUnaryCall ListRecommendationsAsync(global::Hipstershop.ListRecommendationsRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_ListRecommendations, null, options, request);
+ }
+ /// Creates a new instance of client from given ClientBaseConfiguration.
+ protected override RecommendationServiceClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new RecommendationServiceClient(configuration);
+ }
+ }
+
+ /// Creates service definition that can be registered with a server
+ /// An object implementing the server-side handling logic.
+ public static grpc::ServerServiceDefinition BindService(RecommendationServiceBase serviceImpl)
+ {
+ return grpc::ServerServiceDefinition.CreateBuilder()
+ .AddMethod(__Method_ListRecommendations, serviceImpl.ListRecommendations).Build();
+ }
+
+ }
+ public static partial class ProductCatalogService
+ {
+ static readonly string __ServiceName = "hipstershop.ProductCatalogService";
+
+ static readonly grpc::Marshaller __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.Empty.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_ListProductsResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.ListProductsResponse.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_GetProductRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.GetProductRequest.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_Product = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.Product.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_SearchProductsRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.SearchProductsRequest.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_SearchProductsResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.SearchProductsResponse.Parser.ParseFrom);
+
+ static readonly grpc::Method __Method_ListProducts = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "ListProducts",
+ __Marshaller_Empty,
+ __Marshaller_ListProductsResponse);
+
+ static readonly grpc::Method __Method_GetProduct = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "GetProduct",
+ __Marshaller_GetProductRequest,
+ __Marshaller_Product);
+
+ static readonly grpc::Method __Method_SearchProducts = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "SearchProducts",
+ __Marshaller_SearchProductsRequest,
+ __Marshaller_SearchProductsResponse);
+
+ /// Service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Hipstershop.DemoReflection.Descriptor.Services[2]; }
+ }
+
+ /// Base class for server-side implementations of ProductCatalogService
+ public abstract partial class ProductCatalogServiceBase
+ {
+ public virtual global::System.Threading.Tasks.Task ListProducts(global::Hipstershop.Empty request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ public virtual global::System.Threading.Tasks.Task GetProduct(global::Hipstershop.GetProductRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ public virtual global::System.Threading.Tasks.Task SearchProducts(global::Hipstershop.SearchProductsRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// Client for ProductCatalogService
+ public partial class ProductCatalogServiceClient : grpc::ClientBase
+ {
+ /// Creates a new client for ProductCatalogService
+ /// The channel to use to make remote calls.
+ public ProductCatalogServiceClient(grpc::Channel channel) : base(channel)
+ {
+ }
+ /// Creates a new client for ProductCatalogService that uses a custom CallInvoker.
+ /// The callInvoker to use to make remote calls.
+ public ProductCatalogServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ /// Protected parameterless constructor to allow creation of test doubles.
+ protected ProductCatalogServiceClient() : base()
+ {
+ }
+ /// Protected constructor to allow creation of configured clients.
+ /// The client configuration.
+ protected ProductCatalogServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ public virtual global::Hipstershop.ListProductsResponse ListProducts(global::Hipstershop.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return ListProducts(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Hipstershop.ListProductsResponse ListProducts(global::Hipstershop.Empty request, grpc::CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_ListProducts, null, options, request);
+ }
+ public virtual grpc::AsyncUnaryCall ListProductsAsync(global::Hipstershop.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return ListProductsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual grpc::AsyncUnaryCall ListProductsAsync(global::Hipstershop.Empty request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_ListProducts, null, options, request);
+ }
+ public virtual global::Hipstershop.Product GetProduct(global::Hipstershop.GetProductRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return GetProduct(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Hipstershop.Product GetProduct(global::Hipstershop.GetProductRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_GetProduct, null, options, request);
+ }
+ public virtual grpc::AsyncUnaryCall GetProductAsync(global::Hipstershop.GetProductRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return GetProductAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual grpc::AsyncUnaryCall GetProductAsync(global::Hipstershop.GetProductRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_GetProduct, null, options, request);
+ }
+ public virtual global::Hipstershop.SearchProductsResponse SearchProducts(global::Hipstershop.SearchProductsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return SearchProducts(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Hipstershop.SearchProductsResponse SearchProducts(global::Hipstershop.SearchProductsRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_SearchProducts, null, options, request);
+ }
+ public virtual grpc::AsyncUnaryCall SearchProductsAsync(global::Hipstershop.SearchProductsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return SearchProductsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual grpc::AsyncUnaryCall SearchProductsAsync(global::Hipstershop.SearchProductsRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_SearchProducts, null, options, request);
+ }
+ /// Creates a new instance of client from given ClientBaseConfiguration.
+ protected override ProductCatalogServiceClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new ProductCatalogServiceClient(configuration);
+ }
+ }
+
+ /// Creates service definition that can be registered with a server
+ /// An object implementing the server-side handling logic.
+ public static grpc::ServerServiceDefinition BindService(ProductCatalogServiceBase serviceImpl)
+ {
+ return grpc::ServerServiceDefinition.CreateBuilder()
+ .AddMethod(__Method_ListProducts, serviceImpl.ListProducts)
+ .AddMethod(__Method_GetProduct, serviceImpl.GetProduct)
+ .AddMethod(__Method_SearchProducts, serviceImpl.SearchProducts).Build();
+ }
+
+ }
+ public static partial class ShippingService
+ {
+ static readonly string __ServiceName = "hipstershop.ShippingService";
+
+ static readonly grpc::Marshaller __Marshaller_GetQuoteRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.GetQuoteRequest.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_GetQuoteResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.GetQuoteResponse.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_ShipOrderRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.ShipOrderRequest.Parser.ParseFrom);
+ static readonly grpc::Marshaller __Marshaller_ShipOrderResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Hipstershop.ShipOrderResponse.Parser.ParseFrom);
+
+ static readonly grpc::Method __Method_GetQuote = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "GetQuote",
+ __Marshaller_GetQuoteRequest,
+ __Marshaller_GetQuoteResponse);
+
+ static readonly grpc::Method __Method_ShipOrder = new grpc::Method(
+ grpc::MethodType.Unary,
+ __ServiceName,
+ "ShipOrder",
+ __Marshaller_ShipOrderRequest,
+ __Marshaller_ShipOrderResponse);
+
+ /// Service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Hipstershop.DemoReflection.Descriptor.Services[3]; }
+ }
+
+ /// Base class for server-side implementations of ShippingService
+ public abstract partial class ShippingServiceBase
+ {
+ public virtual global::System.Threading.Tasks.Task GetQuote(global::Hipstershop.GetQuoteRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ public virtual global::System.Threading.Tasks.Task ShipOrder(global::Hipstershop.ShipOrderRequest request, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ ///