Merge pull request #1 from GoogleCloudPlatform/master

Merge from Upstream
This commit is contained in:
Colin Nelson 2018-09-21 08:09:47 -07:00 committed by GitHub
commit e56748f2d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
77 changed files with 2727 additions and 695 deletions

3
.gitignore vendored
View file

@ -7,3 +7,6 @@ pkg/
.vscode/
.vs/slnx.sqlite
.vs/microservices-demo/v15/.suo
.idea
.skaffold-*.yaml
.kubernetes-manifests-*/

12
.travis.yml Normal file
View file

@ -0,0 +1,12 @@
sudo: required
services:
- docker
install:
- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.12.0/skaffold-linux-amd64
- chmod +x skaffold
- sudo mv skaffold /usr/local/bin
script:
- skaffold build --profile travis-ci

134
README.md
View file

@ -1,13 +1,72 @@
# Microservices demo
# 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,
web-based e-commerce app called **“Hipster Shop”** where users can browse items,
add them to the cart, and purchase them.
Google has used this application to demonstrate Kubernetes, GKE, Istio,
Stackdriver, gRPC and similar cloud-native technologies.
**Google uses this application to demonstrate Kubernetes, GKE, Istio,
Stackdriver, gRPC** and similar cloud-native technologies nowadays.
### Running locally
## Screenshots
| Home Page | Checkout Screen |
|-----------|-----------------|
| [![Screenshot of store homepage](./img/hipster-shop-frontend-1.png)](./img/hipster-shop-frontend-1.png) | [![Screenshot of checkout screen](./img/hipster-shop-frontend-2.png)](./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](./img/architecture-diagram.png)](./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 shipping 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 (hypothetically😇) 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 (hypothetically😇) |
| [emailservice](./src/emailservice) | Python | Sends users an order confirmation email (hypothetically😇). |
| [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://github.com/GoogleContainerTools/skaffold):** 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
> **Note:** that the first build can take up to 20-30 minutes. Consequent builds
> will be faster.
### Option 1: Running locally with “Docker for Desktop”
> 💡 Recommended if you're planning to develop the application.
1. Install tools to run a Kubernetes cluster locally:
@ -28,38 +87,54 @@ Stackdriver, gRPC and similar cloud-native technologies.
application frontend should be available at http://localhost:80 on your
machine.
### Setup on GKE
### Option 2: Running on Google Kubernetes Engine (GKE)
> 💡 Recommended for demos and making it available publicly.
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.
1. Enable Google Container Registry (GCR) on your GCP project:
gcloud services enable container.googleapis.com
gcloud container clusters create demo --enable-autoupgrade \
--enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5
kubectl get nodes
2. Enable Google Container Registry (GCR) on your GCP project and configure the
`docker` CLI to authenticate to GCR:
gcloud services enable containerregistry.googleapis.com
1. Configure docker to authenticate to GCR:
gcloud auth configure-docker -q
1. Edit `skaffold.yaml`, prepend your GCR registry host (`gcr.io/YOUR_PROJECT/`)
to all `imageName:` fields (or update the existing project name).
3. Set your project ID on image names:
1. Edit the Deployment manifests at `kubernetes-manifests` directory and update
the `image` fields to match the changes you made in the previous step.
- Edit `skaffold.yaml`, update the `imageName:` fields that look like
`gcr.io/[PROJECT_ID]` with your own GCP project ID.
1. Run `skaffold run`. This builds the container
images, pushes them to GCR, and deploys the application to Kubernetes.
- Similarly, edit all Kubernetes Deployment manifests in the
[`./kubernetes-manifests`](./kubernetes-manifests) directory. Find the
`image:` fields with `gcr.io/[...]` and change them to your own GCP project
ID.
1. Find the IP address of your application:
5. Run `skaffold run` from the root of this repository. This command:
- builds the container images
- pushes them to GCR
- applies the `./kubernetes-manifests` deploying the application to
Kubernetes.
6. Find the IP address of your application, then visit the application on your
browser to confirm installation.
kubectl get service frontend-external
then visit the application on your browser to confirm
installation.
### (Optional) Deploying on a Istio-installed cluster
### Istio Deployment
> **Note:** you followed GKE deployment steps above, run `skaffold delete` first
> to delete what's deployed.
1. Create a GKE cluster.
@ -71,14 +146,29 @@ Stackdriver, gRPC and similar cloud-native technologies.
kubectl label namespace default istio-injection=enabled
4. Deploy the application with.
5. Apply the manifests in [`./istio-manifests`](./istio-manifests) directory.
4. Apply the manifests in [`./istio-manifests`](./istio-manifests) directory.
kubectl apply -f ./istio-manifests
This is required only once.
5. Deploy the application with `skaffold run`.
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.
INGRESS_HOST="$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"
echo "$INGRESS_HOST"
curl -v "http://$INGRESS_HOST"
---
**Note to fellow Googlers:** Please fill out the form at
[go/microservices-demo](http://go/microservices-demo) if you are using this
application.
This is not an official Google project.

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

View file

@ -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: extensions/v1beta1
kind: Deployment
metadata:
name: adservice
spec:
template:
metadata:
labels:
app: adservice
spec:
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/microservices-demo-app/adservice
ports:
- containerPort: 9555
env:
- name: PORT
value: "9555"
resources:
requests:
cpu: 200m
memory: 180Mi
limits:
cpu: 300m
memory: 300Mi
readinessProbe:
initialDelaySeconds: 20
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:9555"]
livenessProbe:
initialDelaySeconds: 20
periodSeconds: 5
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

View file

@ -28,13 +28,11 @@ spec:
ports:
- containerPort: 5050
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 5050
exec:
command: ["/bin/grpc_health_probe", "-addr=:5050"]
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 5050
exec:
command: ["/bin/grpc_health_probe", "-addr=:5050"]
env:
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"

View file

@ -30,13 +30,11 @@ spec:
- name: grpc
containerPort: 7000
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 7000
exec:
command: ["/bin/grpc_health_probe", "-addr=:7000"]
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 7000
exec:
command: ["/bin/grpc_health_probe", "-addr=:7000"]
resources:
requests:
cpu: 100m

View file

@ -30,12 +30,12 @@ spec:
- containerPort: 8080
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 8080
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 8080
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
resources:
requests:
cpu: 100m

View file

@ -30,7 +30,7 @@ spec:
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
@ -56,6 +56,8 @@ spec:
value: "shippingservice:50051"
- name: CHECKOUT_SERVICE_ADDR
value: "checkoutservice:5050"
- name: AD_SERVICE_ADDR
value: "adservice:9555"
resources:
requests:
cpu: 100m

View file

@ -29,13 +29,11 @@ spec:
ports:
- containerPort: 50051
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 50051
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 50051
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
resources:
requests:
cpu: 100m

View file

@ -29,13 +29,11 @@ spec:
ports:
- containerPort: 3550
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 3550
exec:
command: ["/bin/grpc_health_probe", "-addr=:3550"]
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 3550
exec:
command: ["/bin/grpc_health_probe", "-addr=:3550"]
resources:
requests:
cpu: 100m

View file

@ -30,12 +30,12 @@ spec:
- containerPort: 8080
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 8080
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 8080
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
env:
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"

View file

@ -29,12 +29,11 @@ spec:
- containerPort: 50051
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 50051
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 50051
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
resources:
requests:
cpu: 100m

View file

@ -217,3 +217,26 @@ message PlaceOrderRequest {
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;
}

View file

@ -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);
}

View file

@ -38,7 +38,31 @@ build:
workspace: src/frontend
- imageName: gcr.io/microservices-demo-app/loadgenerator
workspace: src/loadgenerator
- imageName: gcr.io/microservices-demo-app/adservice
workspace: src/adservice
deploy:
kubectl:
manifests:
- ./kubernetes-manifests/**.yaml
profiles:
# "travis-ci" profile is used to build the images without
# pushing them.
- name: travis-ci
build:
local:
skipPush: true
# "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"

8
src/adservice/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
*.iml
*.ipr
*.iws
.gradle/**
.idea/**
build/**

16
src/adservice/Dockerfile Normal file
View file

@ -0,0 +1,16 @@
FROM openjdk:8
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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
# Next three steps are for caching dependency downloads
# to improve subsequent docker build.
COPY ["build.gradle", "gradlew", "./"]
COPY gradle gradle
RUN ./gradlew downloadRepos
COPY . .
RUN ./gradlew installDist
EXPOSE 9555
ENTRYPOINT ["/app/build/install/hipstershop/bin/AdService"]

26
src/adservice/README.md Normal file
View file

@ -0,0 +1,26 @@
# Ad Service
The Ad service provides advertisement based on context keys. If no context keys are provided then it returns random ads.
## Local Build
The Ad service uses gradlew to compile/install/distribute. Gradle wrapper is already part of the source code. To build Ad Service, run
```
cd src/adservice; ./gradlew installDist
```
It will create executable script src/adservice/build/install/hipstershop/bin/AdService
### Upgrade gradle version
If you need to upgrade the version of gradle then run
```
cd src/adservice ; ./gradlew wrapper --gradle-version <new-version>
```
## Docker Build
From repository root, run:
```
docker build --file src/adservice/Dockerfile .
```

122
src/adservice/build.gradle Normal file
View file

@ -0,0 +1,122 @@
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'
}
}
apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'com.google.protobuf'
repositories {
mavenCentral()
mavenLocal()
}
group = "adservice"
version = "0.1.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION
def opencensusVersion = "0.15.0" // LATEST_OPENCENSUS_RELEASE_VERSION
def grpcVersion = "1.10.1" // CURRENT_GRPC_VERSION
def prometheusVersion = "0.3.0"
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.11.0",
"io.opencensus:opencensus-exporter-stats-prometheus:${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}",
"io.prometheus:simpleclient_httpserver:${prometheusVersion}"
runtime "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')
}
}
// 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
}
task adServiceClient(type: CreateStartScripts) {
mainClassName = 'hipstershop.AdServiceClient'
applicationName = 'AdServiceClient'
outputDir = new File(project.buildDir, 'tmp')
classpath = jar.outputs.files + project.configurations.runtime
}
applicationDistribution.into('bin') {
from(adService)
from(adServiceClient)
fileMode = 0755
}

22
src/adservice/genproto.sh Executable file
View file

@ -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

Binary file not shown.

View file

@ -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

172
src/adservice/gradlew vendored Executable file
View file

@ -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" "$@"

84
src/adservice/gradlew.bat vendored Normal file
View file

@ -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

View file

@ -0,0 +1 @@
rootProject.name = 'hipstershop'

View file

@ -0,0 +1,242 @@
/*
* 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.ImmutableMap;
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.stub.StreamObserver;
import io.grpc.services.*;
import io.opencensus.common.Duration;
import io.opencensus.common.Scope;
import io.opencensus.contrib.grpc.metrics.RpcViews;
import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector;
import io.opencensus.exporter.trace.logging.LoggingTraceExporter;
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.AttributeValue;
import io.opencensus.trace.Span;
import io.opencensus.trace.SpanBuilder;
import io.opencensus.trace.Tracer;
import io.opencensus.trace.Tracing;
import io.opencensus.trace.samplers.Samplers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AdService {
private static final Logger logger = Logger.getLogger(AdService.class.getName());
private static final Tracer tracer = Tracing.getTracer();
private int MAX_ADS_TO_SERVE = 2;
private Server server;
private HealthStatusManager healthMgr;
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();
}
}
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<AdResponse> responseObserver) {
AdService service = AdService.getInstance();
Span parentSpan = tracer.getCurrentSpan();
SpanBuilder spanBuilder =
tracer
.spanBuilderWithExplicitParent("Retrieve Ads", parentSpan)
.setRecordEvents(true)
.setSampler(Samplers.alwaysSample());
try (Scope scope = spanBuilder.startScopedSpan()) {
Span span = tracer.getCurrentSpan();
span.putAttribute("method", AttributeValue.stringAttributeValue("getAds"));
List<Ad> ads = new ArrayList<>();
logger.info("received ad request (context_words=" + req.getContextKeysCount() + ")");
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++) {
Ad ad = service.getAdsByKey(req.getContextKeys(i));
if (ad != null) {
ads.add(ad);
}
}
} else {
span.addAnnotation("No Context provided. Constructing random Ads.");
ads = service.getDefaultAds();
}
if (ads.isEmpty()) {
// Serve default ads.
span.addAnnotation("No Ads found based on context. Constructing random Ads.");
ads = service.getDefaultAds();
}
AdResponse reply = AdResponse.newBuilder().addAllAds(ads).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
} catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "GetAds Failed", e.getStatus());
return;
}
}
}
static final HashMap<String, Ad> cacheMap = new HashMap<String, Ad>();
Ad getAdsByKey(String key) {
return cacheMap.get(key);
}
public List<Ad> getDefaultAds() {
List<Ad> ads = new ArrayList<>(MAX_ADS_TO_SERVE);
Object[] keys = cacheMap.keySet().toArray();
for (int i=0; i<MAX_ADS_TO_SERVE; i++) {
ads.add(cacheMap.get(keys[new Random().nextInt(keys.length)]));
}
return ads;
}
public 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();
}
}
static void initializeAds() {
cacheMap.put("camera", Ad.newBuilder().setRedirectUrl( "/product/2ZYFJ3GM2N")
.setText("Film camera for sale. 50% off.").build());
cacheMap.put("bike", Ad.newBuilder().setRedirectUrl("/product/9SIQT8TOJO")
.setText("City Bike for sale. 10% off.").build());
cacheMap.put("kitchen", Ad.newBuilder().setRedirectUrl("/product/1YMWWN1N4O")
.setText("Home Barista kitchen kit for sale. Buy one, get second kit for free").build());
logger.info("Default Ads initialized");
}
public static void initStackdriver() {
logger.info("Initialize StackDriver");
// Registers all RPC views.
RpcViews.registerAllViews();
// Registers logging trace exporter.
LoggingTraceExporter.register();
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.WARNING, "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.WARNING, "Exception while sleeping" + se.toString());
}
}
}
}
logger.info("StackDriver initialization complete.");
}
/** Main launches the server from the command line. */
public static void main(String[] args) throws IOException, InterruptedException {
// Add final keyword to pass checkStyle.
initializeAds();
new Thread( new Runnable() {
public void run(){
initStackdriver();
}
}).start();
// Register Prometheus exporters and export metrics to a Prometheus HTTPServer.
PrometheusStatsCollector.createAndRegister();
// 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();
}
}

View file

@ -0,0 +1,186 @@
/*
* 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.exporter.trace.logging.LoggingTraceExporter;
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.SpanBuilder;
import io.opencensus.trace.Status.CanonicalCode;
import io.opencensus.trace.Tracer;
import io.opencensus.trace.Tracing;
import io.opencensus.trace.samplers.Samplers;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
/** A simple client that requests ads from the Ads Service. */
public class AdServiceClient {
private static final Logger logger = Logger.getLogger(AdServiceClient.class.getName());
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}. */
public 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. */
AdServiceClient(ManagedChannel channel) {
this.channel = channel;
blockingStub = hipstershop.AdServiceGrpc.newBlockingStub(channel);
}
public 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;
SpanBuilder spanBuilder =
tracer.spanBuilder("AdsClient").setRecordEvents(true).setSampler(Samplers.alwaysSample());
try (Scope scope = spanBuilder.startScopedSpan()) {
tracer.getCurrentSpan().addAnnotation("Getting Ads");
response = blockingStub.getAds(request);
tracer.getCurrentSpan().addAnnotation("Received response from Ads Service.");
} catch (StatusRuntimeException e) {
tracer
.getCurrentSpan()
.setStatus(
CanonicalCode.valueOf(e.getStatus().getCode().name())
.toStatus()
.withDescription(e.getMessage()));
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
return;
}
for(Ad ads: response.getAdsList()) {
logger.info("Ads: " + ads.getText());
}
}
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.warning(
String.format("Port %s is invalid, use default port %d.", args[index], defaultPort));
}
}
return portNumber;
}
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 IOException, 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);
final String cloudProjectId = getStringOrDefaultFromArgs(args, 3, null);
//final int zPagePort = getPortOrDefaultFromArgs(args, 4, 3001);
// Registers all RPC views.
RpcViews.registerAllViews();
// Registers logging trace exporter.
LoggingTraceExporter.register();
// Registers Stackdriver exporters.
if (cloudProjectId != null) {
long sleepTime = 10; /* seconds */
int maxAttempts = 3;
for (int i=0; i<maxAttempts; i++) {
try {
StackdriverTraceExporter.createAndRegister(
StackdriverTraceConfiguration.builder().setProjectId(cloudProjectId).build());
StackdriverStatsExporter.createAndRegister(
StackdriverStatsConfiguration.builder()
.setProjectId(cloudProjectId)
.setExportInterval(Duration.create(15, 0))
.build());
} catch (Exception e) {
if (i==(maxAttempts-1)) {
logger.log(Level.WARNING, "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.WARNING, "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...");
}
}

View file

@ -0,0 +1,242 @@
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;
}
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;
}

View file

@ -15,6 +15,9 @@ RUN go build -gcflags='-N -l' -o /checkoutservice .
FROM alpine as release
RUN apk add --no-cache ca-certificates
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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
COPY --from=builder /checkoutservice /checkoutservice
EXPOSE 5050
ENTRYPOINT ["/checkoutservice"]

View file

@ -10,8 +10,8 @@
"profiler",
"trace/apiv2"
]
revision = "aad3f485ee528456e0768f20397b4d9dd941e755"
version = "v0.25.0"
revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad"
version = "v0.27.0"
[[projects]]
name = "contrib.go.opencensus.io/exporter/stackdriver"
@ -35,20 +35,20 @@
"ptypes/timestamp",
"ptypes/wrappers"
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/google/pprof"
packages = ["profile"]
revision = "ef437552946f69f7e3bdf1fd81c385c29530944d"
revision = "e027b505a088ac3c68c339a1d7ce7724bf34538b"
[[projects]]
name = "github.com/google/uuid"
packages = ["."]
revision = "064e2069ce9c359c118179501254f67d7d37ba24"
version = "0.2"
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
version = "v1.0.0"
[[projects]]
name = "github.com/googleapis/gax-go"
@ -71,10 +71,11 @@
"tag",
"trace",
"trace/internal",
"trace/propagation"
"trace/propagation",
"trace/tracestate"
]
revision = "e262766cd0d230a1bb7c37281e345e465f19b41b"
version = "v0.14.0"
revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89"
version = "v0.16.0"
[[projects]]
branch = "master"
@ -89,7 +90,7 @@
"internal/timeseries",
"trace"
]
revision = "f4c29de78a2a91c00474a2e689954305c350adf9"
revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
[[projects]]
branch = "master"
@ -101,7 +102,7 @@
"jws",
"jwt"
]
revision = "3d292e4d0cdc3a0113e6d207bb137145ef1de42f"
revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9"
[[projects]]
branch = "master"
@ -113,7 +114,7 @@
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "0ffbfd41fbef8ffcf9b62b0b0aa3a5873ed7a4fe"
revision = "1561086e645b2809fb9f8a1e2a38160bf8d53bf4"
[[projects]]
name = "golang.org/x/text"
@ -149,7 +150,7 @@
"transport/grpc",
"transport/http"
]
revision = "f6d94689cbd71030af1108ddac733886fcae1d75"
revision = "19ff8768a5c0b8e46ea281065664787eefc24121"
[[projects]]
name = "google.golang.org/appengine"
@ -167,8 +168,8 @@
"socket",
"urlfetch"
]
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06"
version = "v1.2.0"
[[projects]]
branch = "master"
@ -186,7 +187,7 @@
"googleapis/rpc/status",
"protobuf/field_mask"
]
revision = "daca94659cb50e9f37c1b834680f2e46358f10b0"
revision = "c3f76f3b92d1ffa4c58a9ff842a58b8877655e0f"
[[projects]]
name = "google.golang.org/grpc"
@ -202,6 +203,7 @@
"encoding",
"encoding/proto",
"grpclog",
"health/grpc_health_v1",
"internal",
"internal/backoff",
"internal/channelz",
@ -225,6 +227,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "54254ec0ccf29fb2b490b54b12e5f3eb752ab9b8f9d4f5ab097d60f96eeed9d9"
inputs-digest = "0c103e5e32d8ecdd70048b6d91e02b910e30bad54f06b230a9664f585433a669"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -27,7 +27,7 @@
[[constraint]]
name = "cloud.google.com/go"
version = "0.25.0"
version = "0.27.0"
[[constraint]]
name = "contrib.go.opencensus.io/exporter/stackdriver"
@ -35,15 +35,15 @@
[[constraint]]
name = "github.com/golang/protobuf"
version = "1.1.0"
version = "1.2.0"
[[constraint]]
name = "github.com/google/uuid"
version = "0.2.0"
version = "1.0.0"
[[constraint]]
name = "go.opencensus.io"
version = "0.14.0"
version = "0.16.0"
[[constraint]]
branch = "master"
@ -51,7 +51,7 @@
[[constraint]]
name = "google.golang.org/grpc"
version = "1.14.0"
version = "=1.14.0"
[prune]
go-tests = true

View file

@ -26,6 +26,7 @@ import (
"contrib.go.opencensus.io/exporter/stackdriver"
"github.com/google/uuid"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
@ -33,6 +34,7 @@ import (
pb "github.com/GoogleCloudPlatform/microservices-demo/src/checkoutservice/genproto"
money "github.com/GoogleCloudPlatform/microservices-demo/src/checkoutservice/money"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
)
const (
@ -74,10 +76,20 @@ func main() {
}
srv := grpc.NewServer(grpc.StatsHandler(&ocgrpc.ServerHandler{}))
pb.RegisterCheckoutServiceServer(srv, svc)
healthpb.RegisterHealthServer(srv, svc)
log.Printf("starting to listen on tcp: %q", lis.Addr().String())
log.Fatal(srv.Serve(lis))
}
func initStats(exporter *stackdriver.Exporter) {
view.RegisterExporter(exporter)
if err := view.Register(ocgrpc.DefaultServerViews...); err != nil {
log.Printf("Error registering default server views")
} else {
log.Printf("Registered default server views")
}
}
func initTracing() {
// TODO(ahmetb) this method is duplicated in other microservices using Go
// since they are not sharing packages.
@ -89,6 +101,9 @@ func initTracing() {
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
log.Print("registered stackdriver tracing")
// Register the views to collect server stats.
initStats(exporter)
return
}
d := time.Second * 10 * time.Duration(i)
@ -128,6 +143,10 @@ func mustMapEnv(target *string, envKey string) {
*target = v
}
func (cs *checkoutService) Check(ctx context.Context, req *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) {
return &healthpb.HealthCheckResponse{Status: healthpb.HealthCheckResponse_SERVING}, nil
}
func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderRequest) (*pb.PlaceOrderResponse, error) {
log.Printf("[PlaceOrder] user_id=%q user_currency=%q", req.UserId, req.UserCurrency)

View file

@ -1,4 +1,7 @@
FROM node:8
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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 /usr/src/app
COPY package*.json ./
RUN npm install --only=production

View file

@ -22,7 +22,7 @@ const grpc = require('grpc');
const leftPad = require('left-pad');
const PROTO_PATH = path.join(__dirname, './proto/demo.proto');
const PORT = 31337;
const PORT = 7000;
const shopProto = grpc.load(PROTO_PATH).hipstershop;
const client = new shopProto.CurrencyService(`localhost:${PORT}`,
@ -49,7 +49,7 @@ client.getSupportedCurrencies({}, (err, response) => {
}
});
client.convert(request, function (err, response) {
client.convert(request, (err, response) => {
if (err) {
console.error(`Error in convert: ${err}`);
} else {

View file

@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#!/bin/bash -e
# protos are loaded dynamically for node, simply copies over the proto.
mkdir -p proto && \
cp ../../pb/demo.proto proto
mkdir -p proto
cp -r ../../pb/* ./proto

View file

@ -2,17 +2,25 @@
"name": "grpc-currency-service",
"version": "0.1.0",
"description": "A gRPC currency conversion microservice",
"repository": "TODO",
"repository": "https://github.com/GoogleCloudPlatform/microservices-demo",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "semistandard *.js"
},
"license": "Apache-2.0",
"dependencies": {
"@google-cloud/debug-agent": "^2.6.0",
"@google-cloud/profiler": "^0.1.14",
"@google-cloud/trace-agent": "^2.11.0",
"@grpc/proto-loader": "^0.3.0",
"async": "^1.5.2",
"google-protobuf": "^3.0.0",
"grpc": "^1.0.0",
"left-pad": "^1.3.0",
"request": "^2.87.0",
"xml2js": "^0.4.19"
},
"devDependencies": {
"semistandard": "^12.0.1"
}
}

View file

@ -108,9 +108,9 @@ message ShipOrderResponse {
}
message Address {
string street_address_1 = 1;
string street_address_2 = 2;
string city= 3;
string street_address = 1;
string city = 2;
string state = 3;
string country = 4;
int32 zip_code = 5;
}
@ -202,21 +202,9 @@ message SendOrderConfirmationRequest {
// -------------Checkout service-----------------
service CheckoutService {
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {}
rpc PlaceOrder(PlaceOrderRequest) returns (PlaceOrderResponse) {}
}
message CreateOrderRequest {
string user_id = 1;
string user_currency = 2;
Address address = 3;
}
message CreateOrderResponse {
repeated OrderItem items = 1;
Money shipping_cost = 2;
}
message PlaceOrderRequest {
string user_id = 1;
string user_currency = 2;
@ -229,3 +217,26 @@ message PlaceOrderRequest {
message PlaceOrderResponse {
OrderResult order = 1;
}
// ------------Ads service------------------
service AdsService {
rpc GetAds(AdsRequest) returns (AdsResponse) {}
}
message AdsRequest {
// List of important key words from the current page describing the context.
repeated string context_keys = 1;
}
message AdsResponse {
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;
}

View file

@ -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);
}

View file

@ -16,27 +16,49 @@
require('@google-cloud/profiler').start({
serviceContext: {
service: 'currencyservice',
version: '1.0.0'
service: 'currencyservice',
version: '1.0.0'
}
});
require('@google-cloud/trace-agent').start();
require('@google-cloud/debug-agent').start({
require('@google-cloud/trace-agent').start();
require('@google-cloud/debug-agent').start({
serviceContext: {
service: 'currencyservice',
version: 'VERSION'
}
})
});
const path = require('path');
const grpc = require('grpc');
const request = require('request');
const xml2js = require('xml2js');
const protoLoader = require('@grpc/proto-loader');
const MAIN_PROTO_PATH = path.join(__dirname, './proto/demo.proto');
const HEALTH_PROTO_PATH = path.join(__dirname, './proto/grpc/health/v1/health.proto');
const PROTO_PATH = path.join(__dirname, './proto/demo.proto');
const PORT = 7000;
const DATA_URL = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
const shopProto = grpc.load(PROTO_PATH).hipstershop;
const shopProto = _loadProto(MAIN_PROTO_PATH).hipstershop;
const healthProto = _loadProto(HEALTH_PROTO_PATH).grpc.health.v1;
/**
* Helper function that loads a protobuf file.
*/
function _loadProto (path) {
const packageDefinition = protoLoader.loadSync(
path,
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
);
return grpc.loadPackageDefinition(packageDefinition);
}
/**
* Helper function that gets currency data from an XML webpage
@ -116,8 +138,8 @@ function convert (call, callback) {
nanos: euros.nanos * data[request.to_code]
});
result.units = Math.floor(result.units)
result.nanos = Math.floor(result.nanos)
result.units = Math.floor(result.units);
result.nanos = Math.floor(result.nanos);
result.currency_code = request.to_code;
console.log(`conversion request successful`);
@ -130,6 +152,13 @@ function convert (call, callback) {
}
}
/**
* Endpoint for health checks
*/
function check (call, callback) {
callback(null, { status: 'SERVING' });
}
/**
* Starts an RPC server that receives requests for the
* CurrencyConverter service at the sample server port
@ -138,6 +167,7 @@ function main () {
console.log(`Starting gRPC server on port ${PORT}...`);
const server = new grpc.Server();
server.addService(shopProto.CurrencyService.service, {getSupportedCurrencies, convert});
server.addService(healthProto.Health.service, {check});
server.bind(`0.0.0.0:${PORT}`, grpc.ServerCredentials.createInsecure());
server.start();
}

View file

@ -1,6 +1,13 @@
# Use the grpc.io provided Python image as the base image
FROM grpc/python:1.0
# download the grpc health probe
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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
# show python logs as they occur
ENV PYTHONUNBUFFERED=0

View file

@ -19,13 +19,14 @@ import argparse
import os
import sys
import time
import grpc
from jinja2 import Environment, FileSystemLoader, select_autoescape, TemplateError
from google.api_core.exceptions import GoogleAPICallError
import grpc
import demo_pb2
import demo_pb2_grpc
from grpc_health.v1 import health_pb2
from grpc_health.v1 import health_pb2_grpc
# from opencensus.trace.ext.grpc import server_interceptor
# from opencensus.trace.samplers import always_on
@ -56,7 +57,12 @@ env = Environment(
)
template = env.get_template('confirmation.html')
class EmailService(demo_pb2_grpc.EmailServiceServicer):
class BaseEmailService(demo_pb2_grpc.EmailServiceServicer):
def Check(self, request, context):
return health_pb2.HealthCheckResponse(
status=health_pb2.HealthCheckResponse.SERVING)
class EmailService(BaseEmailService):
def __init__(self):
raise Exception('cloud mail client not implemented')
super().__init__()
@ -79,7 +85,6 @@ class EmailService(demo_pb2_grpc.EmailServiceServicer):
"html_body": content
}
)
print("Message sent: {}".format(response.rfc822_message_id))
def SendOrderConfirmation(self, request, context):
@ -104,18 +109,30 @@ class EmailService(demo_pb2_grpc.EmailServiceServicer):
return demo_pb2.Empty()
class DummyEmailService(demo_pb2_grpc.EmailServiceServicer):
class DummyEmailService(BaseEmailService):
def SendOrderConfirmation(self, request, context):
print('A request to send order confirmation email to {} has been received.'.format(request.email))
return demo_pb2.Empty()
class HealthCheck():
def Check(self, request, context):
return health_pb2.HealthCheckResponse(
status=health_pb2.HealthCheckResponse.SERVING)
def start(dummy_mode):
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))#, interceptors=(tracer_interceptor,))
service = None
if dummy_mode:
demo_pb2_grpc.add_EmailServiceServicer_to_server(DummyEmailService(), server)
service = DummyEmailService()
else:
raise Exception('non-dummy mode not implemented')
server.add_insecure_port('[::]:8080')
raise Exception('non-dummy mode not implemented yet')
demo_pb2_grpc.add_EmailServiceServicer_to_server(service, server)
health_pb2_grpc.add_HealthServicer_to_server(service, server)
port = os.environ.get('PORT', "8080")
print("listening on port: "+port)
server.add_insecure_port('[::]:'+port)
server.start()
try:
while True:
@ -125,5 +142,5 @@ def start(dummy_mode):
if __name__ == '__main__':
print('Starting the email service in dummy mode.')
print('starting the email service in dummy mode.')
start(dummy_mode = True)

View file

@ -9,6 +9,7 @@ google-cloud-trace==0.19.0
googleapis-common-protos==1.5.3
grpc-google-iam-v1==0.11.4
grpcio==1.12.1
grpcio-health-checking==1.14.1
grpcio-tools==1.12.1
idna==2.7
Jinja2==2.10

View file

@ -0,0 +1 @@
vendor/

131
src/frontend/Gopkg.lock generated
View file

@ -2,27 +2,43 @@
[[projects]]
digest = "1:467af0aad47996b25b838d6f14c8371123a8a76ec239020a6c5894e1f8f60272"
name = "cloud.google.com/go"
packages = [
"compute/metadata",
"internal/version",
"monitoring/apiv3",
"profiler",
"trace/apiv2"
"trace/apiv2",
]
revision = "aad3f485ee528456e0768f20397b4d9dd941e755"
version = "v0.25.0"
pruneopts = "UT"
revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad"
version = "v0.27.0"
[[projects]]
digest = "1:9fe70def8f0ceb3d455a0acad9dadd6632287cdbf9c8c2ea50e8dabe2ade40c4"
name = "contrib.go.opencensus.io/exporter/stackdriver"
packages = [
".",
"propagation"
"propagation",
]
pruneopts = "UT"
revision = "37aa2801fbf0205003e15636096ebf0373510288"
version = "v0.5.0"
[[projects]]
branch = "master"
digest = "1:3ef905a7059a17712b7b27315692992f84f356e828d38f6ff0624e04103ec675"
name = "github.com/GoogleCloudPlatform/microservices-demo"
packages = [
"src/frontend/genproto",
"src/frontend/money",
]
pruneopts = "UT"
revision = "6d969441585ade8c91c235115c7cdb12ac61354f"
[[projects]]
digest = "1:72856926f8208767b837bf51e3373f49139f61889b67dc7fd3c2a0fd711e3f7a"
name = "github.com/golang/protobuf"
packages = [
"proto",
@ -33,54 +49,70 @@
"ptypes/empty",
"ptypes/struct",
"ptypes/timestamp",
"ptypes/wrappers"
"ptypes/wrappers",
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
pruneopts = "UT"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:089d56c0adb79140365b5c86815ce97233986da6f3a525c6b706773e4b83876f"
name = "github.com/google/pprof"
packages = ["profile"]
revision = "ef437552946f69f7e3bdf1fd81c385c29530944d"
pruneopts = "UT"
revision = "84b7d314e22c8d12334e52726f68517973b6027b"
[[projects]]
digest = "1:3a26588bc48b96825977c1b3df964f8fd842cd6860cc26370588d3563433cf11"
name = "github.com/google/uuid"
packages = ["."]
revision = "064e2069ce9c359c118179501254f67d7d37ba24"
version = "0.2"
pruneopts = "UT"
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
version = "v1.0.0"
[[projects]]
digest = "1:e145e9710a10bc114a6d3e2738aadf8de146adaa031854ffdf7bbfe15da85e63"
name = "github.com/googleapis/gax-go"
packages = ["."]
pruneopts = "UT"
revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f"
version = "v2.0.0"
[[projects]]
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
name = "github.com/gorilla/context"
packages = ["."]
pruneopts = "UT"
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
version = "v1.1.1"
[[projects]]
digest = "1:e73f5b0152105f18bc131fba127d9949305c8693f8a762588a82a48f61756f5f"
name = "github.com/gorilla/mux"
packages = ["."]
pruneopts = "UT"
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
version = "v1.6.2"
[[projects]]
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = "UT"
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
version = "v1.0.6"
[[projects]]
digest = "1:1bb914cfb78f68f488a91cd7872d3d06a5f83c5bbacf0296dbef44e120b00a91"
name = "go.opencensus.io"
packages = [
".",
@ -95,19 +127,24 @@
"tag",
"trace",
"trace/internal",
"trace/propagation"
"trace/propagation",
"trace/tracestate",
]
revision = "e262766cd0d230a1bb7c37281e345e465f19b41b"
version = "v0.14.0"
pruneopts = "UT"
revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89"
version = "v0.16.0"
[[projects]]
branch = "master"
digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "56440b844dfe139a8ac053f4ecac0b20b79058f4"
pruneopts = "UT"
revision = "0e37d006457bf46f9e6692014ba72ef82c33022c"
[[projects]]
branch = "master"
digest = "1:1c14517b2f106c61d75006199b46a46576058661d469658cb0f90739919641d2"
name = "golang.org/x/net"
packages = [
"context",
@ -117,38 +154,46 @@
"http2/hpack",
"idna",
"internal/timeseries",
"trace"
"trace",
]
revision = "f4c29de78a2a91c00474a2e689954305c350adf9"
pruneopts = "UT"
revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
[[projects]]
branch = "master"
digest = "1:f645667d687fc8bf228865a2c5455824ef05bad08841e673673ef2bb89ac5b90"
name = "golang.org/x/oauth2"
packages = [
".",
"google",
"internal",
"jws",
"jwt"
"jwt",
]
revision = "3d292e4d0cdc3a0113e6d207bb137145ef1de42f"
pruneopts = "UT"
revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9"
[[projects]]
branch = "master"
digest = "1:e0140c0c868c6e0f01c0380865194592c011fe521d6e12d78bfd33e756fe018a"
name = "golang.org/x/sync"
packages = ["semaphore"]
pruneopts = "UT"
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
[[projects]]
branch = "master"
digest = "1:374fc90fcb026e9a367e3fad29e988e5dd944b68ca3f24a184d77abc5307dda4"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
"windows",
]
revision = "0ffbfd41fbef8ffcf9b62b0b0aa3a5873ed7a4fe"
pruneopts = "UT"
revision = "d0be0721c37eeb5299f245a996a483160fc36940"
[[projects]]
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
name = "golang.org/x/text"
packages = [
"collate",
@ -164,13 +209,15 @@
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
"unicode/rangetable",
]
pruneopts = "UT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
digest = "1:e9e388241f9f0f02000dddaeeb91153d53f0cd09dcec33879cc7e043a2e65d75"
name = "google.golang.org/api"
packages = [
"googleapi/transport",
@ -180,11 +227,13 @@
"support/bundler",
"transport",
"transport/grpc",
"transport/http"
"transport/http",
]
revision = "f6d94689cbd71030af1108ddac733886fcae1d75"
pruneopts = "UT"
revision = "7ca32eb868bf53ea2fc406698eb98583a8073d19"
[[projects]]
digest = "1:26619fcd2452b4044174d26acd8b09c09dffee9a1c3a22d2383b873aa9a0131f"
name = "google.golang.org/appengine"
packages = [
".",
@ -198,13 +247,15 @@
"internal/socket",
"internal/urlfetch",
"socket",
"urlfetch"
"urlfetch",
]
pruneopts = "UT"
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:7a3da01a8f840fbbef1f027dc091ae52a29c6ab9374e126b6bdc5bf3b0ff2687"
name = "google.golang.org/genproto"
packages = [
"googleapis/api/annotations",
@ -217,11 +268,13 @@
"googleapis/monitoring/v3",
"googleapis/rpc/errdetails",
"googleapis/rpc/status",
"protobuf/field_mask"
"protobuf/field_mask",
]
revision = "daca94659cb50e9f37c1b834680f2e46358f10b0"
pruneopts = "UT"
revision = "36d5787dc5356b711fe8f3040271aaf51c35955b"
[[projects]]
digest = "1:4ad047d772a7d4841687df9534a767a9e243885ed6d7d2ced6af5995a5dc44b3"
name = "google.golang.org/grpc"
packages = [
".",
@ -250,14 +303,32 @@
"resolver/passthrough",
"stats",
"status",
"tap"
"tap",
]
revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455"
version = "v1.14.0"
pruneopts = "UT"
revision = "8dea3dc473e90c8179e519d91302d0597c0ca1d1"
version = "v1.15.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "806889b149b944cab2216a1769d221df9ca18b3b62fb5040e40737fd0550084c"
input-imports = [
"cloud.google.com/go/profiler",
"contrib.go.opencensus.io/exporter/stackdriver",
"github.com/GoogleCloudPlatform/microservices-demo/src/frontend/genproto",
"github.com/GoogleCloudPlatform/microservices-demo/src/frontend/money",
"github.com/golang/protobuf/proto",
"github.com/google/uuid",
"github.com/gorilla/mux",
"github.com/pkg/errors",
"github.com/sirupsen/logrus",
"go.opencensus.io/plugin/ocgrpc",
"go.opencensus.io/plugin/ochttp",
"go.opencensus.io/plugin/ochttp/propagation/b3",
"go.opencensus.io/stats/view",
"go.opencensus.io/trace",
"golang.org/x/net/context",
"google.golang.org/grpc",
]
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -27,19 +27,23 @@
[[constraint]]
name = "cloud.google.com/go"
version = "0.25.0"
version = "0.27.0"
[[constraint]]
name = "contrib.go.opencensus.io/exporter/stackdriver"
version = "0.5.0"
[[constraint]]
branch = "master"
name = "github.com/GoogleCloudPlatform/microservices-demo"
[[constraint]]
name = "github.com/golang/protobuf"
version = "1.1.0"
version = "1.2.0"
[[constraint]]
name = "github.com/google/uuid"
version = "0.2.0"
version = "1.0.0"
[[constraint]]
name = "github.com/gorilla/mux"
@ -55,7 +59,7 @@
[[constraint]]
name = "go.opencensus.io"
version = "0.14.0"
version = "0.16.0"
[[constraint]]
branch = "master"
@ -63,7 +67,7 @@
[[constraint]]
name = "google.golang.org/grpc"
version = "1.14.0"
version = "1.15.0"
[prune]
go-tests = true

View file

@ -24,8 +24,8 @@ var _ = math.Inf
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type CartItem struct {
ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId" json:"product_id,omitempty"`
Quantity int32 `protobuf:"varint,2,opt,name=quantity" json:"quantity,omitempty"`
ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"`
Quantity int32 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -35,7 +35,7 @@ func (m *CartItem) Reset() { *m = CartItem{} }
func (m *CartItem) String() string { return proto.CompactTextString(m) }
func (*CartItem) ProtoMessage() {}
func (*CartItem) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{0}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{0}
}
func (m *CartItem) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CartItem.Unmarshal(m, b)
@ -70,8 +70,8 @@ func (m *CartItem) GetQuantity() int32 {
}
type AddItemRequest struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
Item *CartItem `protobuf:"bytes,2,opt,name=item" json:"item,omitempty"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Item *CartItem `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -81,7 +81,7 @@ func (m *AddItemRequest) Reset() { *m = AddItemRequest{} }
func (m *AddItemRequest) String() string { return proto.CompactTextString(m) }
func (*AddItemRequest) ProtoMessage() {}
func (*AddItemRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{1}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{1}
}
func (m *AddItemRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AddItemRequest.Unmarshal(m, b)
@ -116,7 +116,7 @@ func (m *AddItemRequest) GetItem() *CartItem {
}
type EmptyCartRequest struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -126,7 +126,7 @@ func (m *EmptyCartRequest) Reset() { *m = EmptyCartRequest{} }
func (m *EmptyCartRequest) String() string { return proto.CompactTextString(m) }
func (*EmptyCartRequest) ProtoMessage() {}
func (*EmptyCartRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{2}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{2}
}
func (m *EmptyCartRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EmptyCartRequest.Unmarshal(m, b)
@ -154,7 +154,7 @@ func (m *EmptyCartRequest) GetUserId() string {
}
type GetCartRequest struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -164,7 +164,7 @@ func (m *GetCartRequest) Reset() { *m = GetCartRequest{} }
func (m *GetCartRequest) String() string { return proto.CompactTextString(m) }
func (*GetCartRequest) ProtoMessage() {}
func (*GetCartRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{3}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{3}
}
func (m *GetCartRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetCartRequest.Unmarshal(m, b)
@ -192,8 +192,8 @@ func (m *GetCartRequest) GetUserId() string {
}
type Cart struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -203,7 +203,7 @@ func (m *Cart) Reset() { *m = Cart{} }
func (m *Cart) String() string { return proto.CompactTextString(m) }
func (*Cart) ProtoMessage() {}
func (*Cart) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{4}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{4}
}
func (m *Cart) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Cart.Unmarshal(m, b)
@ -247,7 +247,7 @@ func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{5}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{5}
}
func (m *Empty) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Empty.Unmarshal(m, b)
@ -268,8 +268,8 @@ func (m *Empty) XXX_DiscardUnknown() {
var xxx_messageInfo_Empty proto.InternalMessageInfo
type ListRecommendationsRequest struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -279,7 +279,7 @@ func (m *ListRecommendationsRequest) Reset() { *m = ListRecommendationsR
func (m *ListRecommendationsRequest) String() string { return proto.CompactTextString(m) }
func (*ListRecommendationsRequest) ProtoMessage() {}
func (*ListRecommendationsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{6}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{6}
}
func (m *ListRecommendationsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListRecommendationsRequest.Unmarshal(m, b)
@ -314,7 +314,7 @@ func (m *ListRecommendationsRequest) GetProductIds() []string {
}
type ListRecommendationsResponse struct {
ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"`
ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -324,7 +324,7 @@ func (m *ListRecommendationsResponse) Reset() { *m = ListRecommendations
func (m *ListRecommendationsResponse) String() string { return proto.CompactTextString(m) }
func (*ListRecommendationsResponse) ProtoMessage() {}
func (*ListRecommendationsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{7}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{7}
}
func (m *ListRecommendationsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListRecommendationsResponse.Unmarshal(m, b)
@ -352,11 +352,11 @@ func (m *ListRecommendationsResponse) GetProductIds() []string {
}
type Product struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
Picture string `protobuf:"bytes,4,opt,name=picture" json:"picture,omitempty"`
PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd" json:"price_usd,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"`
PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -366,7 +366,7 @@ func (m *Product) Reset() { *m = Product{} }
func (m *Product) String() string { return proto.CompactTextString(m) }
func (*Product) ProtoMessage() {}
func (*Product) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{8}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{8}
}
func (m *Product) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Product.Unmarshal(m, b)
@ -422,7 +422,7 @@ func (m *Product) GetPriceUsd() *Money {
}
type ListProductsResponse struct {
Products []*Product `protobuf:"bytes,1,rep,name=products" json:"products,omitempty"`
Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -432,7 +432,7 @@ func (m *ListProductsResponse) Reset() { *m = ListProductsResponse{} }
func (m *ListProductsResponse) String() string { return proto.CompactTextString(m) }
func (*ListProductsResponse) ProtoMessage() {}
func (*ListProductsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{9}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{9}
}
func (m *ListProductsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListProductsResponse.Unmarshal(m, b)
@ -460,7 +460,7 @@ func (m *ListProductsResponse) GetProducts() []*Product {
}
type GetProductRequest struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -470,7 +470,7 @@ func (m *GetProductRequest) Reset() { *m = GetProductRequest{} }
func (m *GetProductRequest) String() string { return proto.CompactTextString(m) }
func (*GetProductRequest) ProtoMessage() {}
func (*GetProductRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{10}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{10}
}
func (m *GetProductRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetProductRequest.Unmarshal(m, b)
@ -498,7 +498,7 @@ func (m *GetProductRequest) GetId() string {
}
type SearchProductsRequest struct {
Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"`
Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -508,7 +508,7 @@ func (m *SearchProductsRequest) Reset() { *m = SearchProductsRequest{} }
func (m *SearchProductsRequest) String() string { return proto.CompactTextString(m) }
func (*SearchProductsRequest) ProtoMessage() {}
func (*SearchProductsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{11}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{11}
}
func (m *SearchProductsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SearchProductsRequest.Unmarshal(m, b)
@ -536,7 +536,7 @@ func (m *SearchProductsRequest) GetQuery() string {
}
type SearchProductsResponse struct {
Results []*Product `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"`
Results []*Product `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -546,7 +546,7 @@ func (m *SearchProductsResponse) Reset() { *m = SearchProductsResponse{}
func (m *SearchProductsResponse) String() string { return proto.CompactTextString(m) }
func (*SearchProductsResponse) ProtoMessage() {}
func (*SearchProductsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{12}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{12}
}
func (m *SearchProductsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SearchProductsResponse.Unmarshal(m, b)
@ -574,8 +574,8 @@ func (m *SearchProductsResponse) GetResults() []*Product {
}
type GetQuoteRequest struct {
Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"`
Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -585,7 +585,7 @@ func (m *GetQuoteRequest) Reset() { *m = GetQuoteRequest{} }
func (m *GetQuoteRequest) String() string { return proto.CompactTextString(m) }
func (*GetQuoteRequest) ProtoMessage() {}
func (*GetQuoteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{13}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{13}
}
func (m *GetQuoteRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetQuoteRequest.Unmarshal(m, b)
@ -620,7 +620,7 @@ func (m *GetQuoteRequest) GetItems() []*CartItem {
}
type GetQuoteResponse struct {
CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd" json:"cost_usd,omitempty"`
CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd,proto3" json:"cost_usd,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -630,7 +630,7 @@ func (m *GetQuoteResponse) Reset() { *m = GetQuoteResponse{} }
func (m *GetQuoteResponse) String() string { return proto.CompactTextString(m) }
func (*GetQuoteResponse) ProtoMessage() {}
func (*GetQuoteResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{14}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{14}
}
func (m *GetQuoteResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetQuoteResponse.Unmarshal(m, b)
@ -658,8 +658,8 @@ func (m *GetQuoteResponse) GetCostUsd() *Money {
}
type ShipOrderRequest struct {
Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"`
Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -669,7 +669,7 @@ func (m *ShipOrderRequest) Reset() { *m = ShipOrderRequest{} }
func (m *ShipOrderRequest) String() string { return proto.CompactTextString(m) }
func (*ShipOrderRequest) ProtoMessage() {}
func (*ShipOrderRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{15}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{15}
}
func (m *ShipOrderRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ShipOrderRequest.Unmarshal(m, b)
@ -704,7 +704,7 @@ func (m *ShipOrderRequest) GetItems() []*CartItem {
}
type ShipOrderResponse struct {
TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId" json:"tracking_id,omitempty"`
TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId,proto3" json:"tracking_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -714,7 +714,7 @@ func (m *ShipOrderResponse) Reset() { *m = ShipOrderResponse{} }
func (m *ShipOrderResponse) String() string { return proto.CompactTextString(m) }
func (*ShipOrderResponse) ProtoMessage() {}
func (*ShipOrderResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{16}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{16}
}
func (m *ShipOrderResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ShipOrderResponse.Unmarshal(m, b)
@ -742,11 +742,11 @@ func (m *ShipOrderResponse) GetTrackingId() string {
}
type Address struct {
StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress" json:"street_address,omitempty"`
City string `protobuf:"bytes,2,opt,name=city" json:"city,omitempty"`
State string `protobuf:"bytes,3,opt,name=state" json:"state,omitempty"`
Country string `protobuf:"bytes,4,opt,name=country" json:"country,omitempty"`
ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode" json:"zip_code,omitempty"`
StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"`
City string `protobuf:"bytes,2,opt,name=city,proto3" json:"city,omitempty"`
State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"`
Country string `protobuf:"bytes,4,opt,name=country,proto3" json:"country,omitempty"`
ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode,proto3" json:"zip_code,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -756,7 +756,7 @@ func (m *Address) Reset() { *m = Address{} }
func (m *Address) String() string { return proto.CompactTextString(m) }
func (*Address) ProtoMessage() {}
func (*Address) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{17}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{17}
}
func (m *Address) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Address.Unmarshal(m, b)
@ -814,17 +814,17 @@ func (m *Address) GetZipCode() int32 {
// Represents an amount of money with its currency type.
type Money struct {
// The 3-letter currency code defined in ISO 4217.
CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode" json:"currency_code,omitempty"`
CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"`
// The whole units of the amount.
// For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar.
Units int64 `protobuf:"varint,2,opt,name=units" json:"units,omitempty"`
Units int64 `protobuf:"varint,2,opt,name=units,proto3" json:"units,omitempty"`
// 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.
Nanos int32 `protobuf:"varint,3,opt,name=nanos" json:"nanos,omitempty"`
Nanos int32 `protobuf:"varint,3,opt,name=nanos,proto3" json:"nanos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -834,7 +834,7 @@ func (m *Money) Reset() { *m = Money{} }
func (m *Money) String() string { return proto.CompactTextString(m) }
func (*Money) ProtoMessage() {}
func (*Money) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{18}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{18}
}
func (m *Money) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Money.Unmarshal(m, b)
@ -877,7 +877,7 @@ func (m *Money) GetNanos() int32 {
type GetSupportedCurrenciesResponse struct {
// The 3-letter currency code defined in ISO 4217.
CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes" json:"currency_codes,omitempty"`
CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes,proto3" json:"currency_codes,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -887,7 +887,7 @@ func (m *GetSupportedCurrenciesResponse) Reset() { *m = GetSupportedCurr
func (m *GetSupportedCurrenciesResponse) String() string { return proto.CompactTextString(m) }
func (*GetSupportedCurrenciesResponse) ProtoMessage() {}
func (*GetSupportedCurrenciesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{19}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{19}
}
func (m *GetSupportedCurrenciesResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetSupportedCurrenciesResponse.Unmarshal(m, b)
@ -915,9 +915,9 @@ func (m *GetSupportedCurrenciesResponse) GetCurrencyCodes() []string {
}
type CurrencyConversionRequest struct {
From *Money `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"`
From *Money `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"`
// The 3-letter currency code defined in ISO 4217.
ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode" json:"to_code,omitempty"`
ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode,proto3" json:"to_code,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -927,7 +927,7 @@ func (m *CurrencyConversionRequest) Reset() { *m = CurrencyConversionReq
func (m *CurrencyConversionRequest) String() string { return proto.CompactTextString(m) }
func (*CurrencyConversionRequest) ProtoMessage() {}
func (*CurrencyConversionRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{20}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{20}
}
func (m *CurrencyConversionRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CurrencyConversionRequest.Unmarshal(m, b)
@ -962,10 +962,10 @@ func (m *CurrencyConversionRequest) GetToCode() string {
}
type CreditCardInfo struct {
CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber" json:"credit_card_number,omitempty"`
CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv" json:"credit_card_cvv,omitempty"`
CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear" json:"credit_card_expiration_year,omitempty"`
CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth" json:"credit_card_expiration_month,omitempty"`
CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber,proto3" json:"credit_card_number,omitempty"`
CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv,proto3" json:"credit_card_cvv,omitempty"`
CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear,proto3" json:"credit_card_expiration_year,omitempty"`
CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth,proto3" json:"credit_card_expiration_month,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -975,7 +975,7 @@ func (m *CreditCardInfo) Reset() { *m = CreditCardInfo{} }
func (m *CreditCardInfo) String() string { return proto.CompactTextString(m) }
func (*CreditCardInfo) ProtoMessage() {}
func (*CreditCardInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{21}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{21}
}
func (m *CreditCardInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CreditCardInfo.Unmarshal(m, b)
@ -1024,8 +1024,8 @@ func (m *CreditCardInfo) GetCreditCardExpirationMonth() int32 {
}
type ChargeRequest struct {
Amount *Money `protobuf:"bytes,1,opt,name=amount" json:"amount,omitempty"`
CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"`
Amount *Money `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"`
CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1035,7 +1035,7 @@ func (m *ChargeRequest) Reset() { *m = ChargeRequest{} }
func (m *ChargeRequest) String() string { return proto.CompactTextString(m) }
func (*ChargeRequest) ProtoMessage() {}
func (*ChargeRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{22}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{22}
}
func (m *ChargeRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChargeRequest.Unmarshal(m, b)
@ -1070,7 +1070,7 @@ func (m *ChargeRequest) GetCreditCard() *CreditCardInfo {
}
type ChargeResponse struct {
TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId" json:"transaction_id,omitempty"`
TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1080,7 +1080,7 @@ func (m *ChargeResponse) Reset() { *m = ChargeResponse{} }
func (m *ChargeResponse) String() string { return proto.CompactTextString(m) }
func (*ChargeResponse) ProtoMessage() {}
func (*ChargeResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{23}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{23}
}
func (m *ChargeResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChargeResponse.Unmarshal(m, b)
@ -1108,8 +1108,8 @@ func (m *ChargeResponse) GetTransactionId() string {
}
type OrderItem struct {
Item *CartItem `protobuf:"bytes,1,opt,name=item" json:"item,omitempty"`
Cost *Money `protobuf:"bytes,2,opt,name=cost" json:"cost,omitempty"`
Item *CartItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"`
Cost *Money `protobuf:"bytes,2,opt,name=cost,proto3" json:"cost,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1119,7 +1119,7 @@ func (m *OrderItem) Reset() { *m = OrderItem{} }
func (m *OrderItem) String() string { return proto.CompactTextString(m) }
func (*OrderItem) ProtoMessage() {}
func (*OrderItem) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{24}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{24}
}
func (m *OrderItem) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_OrderItem.Unmarshal(m, b)
@ -1154,11 +1154,11 @@ func (m *OrderItem) GetCost() *Money {
}
type OrderResult struct {
OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId" json:"order_id,omitempty"`
ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId" json:"shipping_tracking_id,omitempty"`
ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost" json:"shipping_cost,omitempty"`
ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress" json:"shipping_address,omitempty"`
Items []*OrderItem `protobuf:"bytes,5,rep,name=items" json:"items,omitempty"`
OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"`
ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId,proto3" json:"shipping_tracking_id,omitempty"`
ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost,proto3" json:"shipping_cost,omitempty"`
ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress,proto3" json:"shipping_address,omitempty"`
Items []*OrderItem `protobuf:"bytes,5,rep,name=items,proto3" json:"items,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1168,7 +1168,7 @@ func (m *OrderResult) Reset() { *m = OrderResult{} }
func (m *OrderResult) String() string { return proto.CompactTextString(m) }
func (*OrderResult) ProtoMessage() {}
func (*OrderResult) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{25}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{25}
}
func (m *OrderResult) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_OrderResult.Unmarshal(m, b)
@ -1224,8 +1224,8 @@ func (m *OrderResult) GetItems() []*OrderItem {
}
type SendOrderConfirmationRequest struct {
Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"`
Order *OrderResult `protobuf:"bytes,2,opt,name=order" json:"order,omitempty"`
Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
Order *OrderResult `protobuf:"bytes,2,opt,name=order,proto3" json:"order,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1235,7 +1235,7 @@ func (m *SendOrderConfirmationRequest) Reset() { *m = SendOrderConfirmat
func (m *SendOrderConfirmationRequest) String() string { return proto.CompactTextString(m) }
func (*SendOrderConfirmationRequest) ProtoMessage() {}
func (*SendOrderConfirmationRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{26}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{26}
}
func (m *SendOrderConfirmationRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendOrderConfirmationRequest.Unmarshal(m, b)
@ -1270,11 +1270,11 @@ func (m *SendOrderConfirmationRequest) GetOrder() *OrderResult {
}
type PlaceOrderRequest struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency" json:"user_currency,omitempty"`
Address *Address `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"`
Email string `protobuf:"bytes,5,opt,name=email" json:"email,omitempty"`
CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency,proto3" json:"user_currency,omitempty"`
Address *Address `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"`
CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1284,7 +1284,7 @@ func (m *PlaceOrderRequest) Reset() { *m = PlaceOrderRequest{} }
func (m *PlaceOrderRequest) String() string { return proto.CompactTextString(m) }
func (*PlaceOrderRequest) ProtoMessage() {}
func (*PlaceOrderRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{27}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{27}
}
func (m *PlaceOrderRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PlaceOrderRequest.Unmarshal(m, b)
@ -1340,7 +1340,7 @@ func (m *PlaceOrderRequest) GetCreditCard() *CreditCardInfo {
}
type PlaceOrderResponse struct {
Order *OrderResult `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"`
Order *OrderResult `protobuf:"bytes,1,opt,name=order,proto3" json:"order,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1350,7 +1350,7 @@ func (m *PlaceOrderResponse) Reset() { *m = PlaceOrderResponse{} }
func (m *PlaceOrderResponse) String() string { return proto.CompactTextString(m) }
func (*PlaceOrderResponse) ProtoMessage() {}
func (*PlaceOrderResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_e1d03823e14b5fb0, []int{28}
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{28}
}
func (m *PlaceOrderResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PlaceOrderResponse.Unmarshal(m, b)
@ -1377,6 +1377,131 @@ func (m *PlaceOrderResponse) GetOrder() *OrderResult {
return nil
}
type AdRequest struct {
// List of important key words from the current page describing the context.
ContextKeys []string `protobuf:"bytes,1,rep,name=context_keys,json=contextKeys,proto3" json:"context_keys,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *AdRequest) Reset() { *m = AdRequest{} }
func (m *AdRequest) String() string { return proto.CompactTextString(m) }
func (*AdRequest) ProtoMessage() {}
func (*AdRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{29}
}
func (m *AdRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AdRequest.Unmarshal(m, b)
}
func (m *AdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_AdRequest.Marshal(b, m, deterministic)
}
func (dst *AdRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_AdRequest.Merge(dst, src)
}
func (m *AdRequest) XXX_Size() int {
return xxx_messageInfo_AdRequest.Size(m)
}
func (m *AdRequest) XXX_DiscardUnknown() {
xxx_messageInfo_AdRequest.DiscardUnknown(m)
}
var xxx_messageInfo_AdRequest proto.InternalMessageInfo
func (m *AdRequest) GetContextKeys() []string {
if m != nil {
return m.ContextKeys
}
return nil
}
type AdResponse struct {
Ads []*Ad `protobuf:"bytes,1,rep,name=ads,proto3" json:"ads,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *AdResponse) Reset() { *m = AdResponse{} }
func (m *AdResponse) String() string { return proto.CompactTextString(m) }
func (*AdResponse) ProtoMessage() {}
func (*AdResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{30}
}
func (m *AdResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AdResponse.Unmarshal(m, b)
}
func (m *AdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_AdResponse.Marshal(b, m, deterministic)
}
func (dst *AdResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_AdResponse.Merge(dst, src)
}
func (m *AdResponse) XXX_Size() int {
return xxx_messageInfo_AdResponse.Size(m)
}
func (m *AdResponse) XXX_DiscardUnknown() {
xxx_messageInfo_AdResponse.DiscardUnknown(m)
}
var xxx_messageInfo_AdResponse proto.InternalMessageInfo
func (m *AdResponse) GetAds() []*Ad {
if m != nil {
return m.Ads
}
return nil
}
type Ad struct {
// url to redirect to when an ad is clicked.
RedirectUrl string `protobuf:"bytes,1,opt,name=redirect_url,json=redirectUrl,proto3" json:"redirect_url,omitempty"`
// short advertisement text to display.
Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Ad) Reset() { *m = Ad{} }
func (m *Ad) String() string { return proto.CompactTextString(m) }
func (*Ad) ProtoMessage() {}
func (*Ad) Descriptor() ([]byte, []int) {
return fileDescriptor_demo_88bb8fdac9cd6be5, []int{31}
}
func (m *Ad) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Ad.Unmarshal(m, b)
}
func (m *Ad) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Ad.Marshal(b, m, deterministic)
}
func (dst *Ad) XXX_Merge(src proto.Message) {
xxx_messageInfo_Ad.Merge(dst, src)
}
func (m *Ad) XXX_Size() int {
return xxx_messageInfo_Ad.Size(m)
}
func (m *Ad) XXX_DiscardUnknown() {
xxx_messageInfo_Ad.DiscardUnknown(m)
}
var xxx_messageInfo_Ad proto.InternalMessageInfo
func (m *Ad) GetRedirectUrl() string {
if m != nil {
return m.RedirectUrl
}
return ""
}
func (m *Ad) GetText() string {
if m != nil {
return m.Text
}
return ""
}
func init() {
proto.RegisterType((*CartItem)(nil), "hipstershop.CartItem")
proto.RegisterType((*AddItemRequest)(nil), "hipstershop.AddItemRequest")
@ -1407,6 +1532,9 @@ func init() {
proto.RegisterType((*SendOrderConfirmationRequest)(nil), "hipstershop.SendOrderConfirmationRequest")
proto.RegisterType((*PlaceOrderRequest)(nil), "hipstershop.PlaceOrderRequest")
proto.RegisterType((*PlaceOrderResponse)(nil), "hipstershop.PlaceOrderResponse")
proto.RegisterType((*AdRequest)(nil), "hipstershop.AdRequest")
proto.RegisterType((*AdResponse)(nil), "hipstershop.AdResponse")
proto.RegisterType((*Ad)(nil), "hipstershop.Ad")
}
// Reference imports to suppress errors if they are not otherwise used.
@ -2127,95 +2255,165 @@ var _CheckoutService_serviceDesc = grpc.ServiceDesc{
Metadata: "demo.proto",
}
func init() { proto.RegisterFile("demo.proto", fileDescriptor_demo_e1d03823e14b5fb0) }
var fileDescriptor_demo_e1d03823e14b5fb0 = []byte{
// 1389 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xdd, 0x72, 0xd3, 0xc6,
0x17, 0x8f, 0x12, 0x3b, 0xb6, 0x8f, 0x63, 0x27, 0xd9, 0x7f, 0xc2, 0xdf, 0x28, 0x7c, 0xa4, 0x9b,
0x81, 0x42, 0x81, 0x94, 0x49, 0x3b, 0xc3, 0x45, 0x69, 0x29, 0x63, 0x32, 0xc6, 0x33, 0x50, 0xa8,
0x02, 0x1d, 0x3a, 0x74, 0xea, 0x11, 0xda, 0x05, 0xab, 0x44, 0x5a, 0xb1, 0xbb, 0xca, 0xd4, 0x5c,
0xb6, 0x0f, 0xd0, 0xfb, 0x3e, 0x42, 0x5f, 0xa0, 0xef, 0xd0, 0xfb, 0xbe, 0x42, 0x9f, 0xa3, 0xb3,
0x2b, 0xad, 0xbe, 0x62, 0x25, 0xe1, 0xa6, 0x77, 0xda, 0xb3, 0xbf, 0x3d, 0xe7, 0x77, 0xce, 0x9e,
0x73, 0xf6, 0x08, 0x80, 0xd0, 0x80, 0xed, 0x46, 0x9c, 0x49, 0x86, 0xba, 0x53, 0x3f, 0x12, 0x92,
0x72, 0x31, 0x65, 0x11, 0xde, 0x87, 0xf6, 0xd0, 0xe5, 0x72, 0x2c, 0x69, 0x80, 0x2e, 0x02, 0x44,
0x9c, 0x91, 0xd8, 0x93, 0x13, 0x9f, 0x0c, 0xac, 0x6d, 0xeb, 0x5a, 0xc7, 0xe9, 0xa4, 0x92, 0x31,
0x41, 0x36, 0xb4, 0xdf, 0xc5, 0x6e, 0x28, 0x7d, 0x39, 0x1b, 0x2c, 0x6e, 0x5b, 0xd7, 0x9a, 0x4e,
0xb6, 0xc6, 0xcf, 0xa0, 0x7f, 0x9f, 0x10, 0xa5, 0xc5, 0xa1, 0xef, 0x62, 0x2a, 0x24, 0xfa, 0x3f,
0xb4, 0x62, 0x41, 0x79, 0xae, 0x69, 0x59, 0x2d, 0xc7, 0x04, 0x5d, 0x87, 0x86, 0x2f, 0x69, 0xa0,
0x55, 0x74, 0xf7, 0x36, 0x77, 0x0b, 0x6c, 0x76, 0x0d, 0x15, 0x47, 0x43, 0xf0, 0x0d, 0x58, 0xdb,
0x0f, 0x22, 0x39, 0x53, 0xe2, 0xd3, 0xf4, 0xe2, 0xeb, 0xd0, 0x1f, 0x51, 0x79, 0x26, 0xe8, 0x23,
0x68, 0x28, 0x5c, 0x3d, 0xc7, 0x1b, 0xd0, 0x54, 0x04, 0xc4, 0x60, 0x71, 0x7b, 0xa9, 0x9e, 0x64,
0x82, 0xc1, 0x2d, 0x68, 0x6a, 0x96, 0xf8, 0x3b, 0xb0, 0x1f, 0xf9, 0x42, 0x3a, 0xd4, 0x63, 0x41,
0x40, 0x43, 0xe2, 0x4a, 0x9f, 0x85, 0xe2, 0xd4, 0x80, 0x5c, 0x86, 0x6e, 0x1e, 0xf6, 0xc4, 0x64,
0xc7, 0x81, 0x2c, 0xee, 0x02, 0x7f, 0x05, 0x5b, 0x73, 0xf5, 0x8a, 0x88, 0x85, 0x82, 0x56, 0xcf,
0x5b, 0xc7, 0xce, 0xff, 0x6e, 0x41, 0xeb, 0x69, 0xb2, 0x44, 0x7d, 0x58, 0xcc, 0x08, 0x2c, 0xfa,
0x04, 0x21, 0x68, 0x84, 0x6e, 0x40, 0xf5, 0x6d, 0x74, 0x1c, 0xfd, 0x8d, 0xb6, 0xa1, 0x4b, 0xa8,
0xf0, 0xb8, 0x1f, 0x29, 0x43, 0x83, 0x25, 0xbd, 0x55, 0x14, 0xa1, 0x01, 0xb4, 0x22, 0xdf, 0x93,
0x31, 0xa7, 0x83, 0x86, 0xde, 0x35, 0x4b, 0xf4, 0x29, 0x74, 0x22, 0xee, 0x7b, 0x74, 0x12, 0x0b,
0x32, 0x68, 0xea, 0x2b, 0x46, 0xa5, 0xe8, 0x3d, 0x66, 0x21, 0x9d, 0x39, 0x6d, 0x0d, 0x7a, 0x2e,
0x08, 0x7e, 0x08, 0x1b, 0xca, 0xb9, 0x94, 0x5f, 0xee, 0xd5, 0x6d, 0x68, 0xa7, 0x2e, 0x24, 0x2e,
0x75, 0xf7, 0x36, 0x4a, 0x7a, 0xd2, 0x03, 0x4e, 0x86, 0xc2, 0x3b, 0xb0, 0x3e, 0xa2, 0x46, 0x91,
0x89, 0x7a, 0xc5, 0x5f, 0x7c, 0x0b, 0x36, 0x0f, 0xa8, 0xcb, 0xbd, 0x69, 0x6e, 0x30, 0x01, 0x6e,
0x40, 0xf3, 0x5d, 0x4c, 0xf9, 0x2c, 0xc5, 0x26, 0x0b, 0xfc, 0x10, 0xce, 0x55, 0xe1, 0x29, 0xbf,
0x5d, 0x68, 0x71, 0x2a, 0xe2, 0xc3, 0x53, 0xe8, 0x19, 0x10, 0x0e, 0x61, 0x75, 0x44, 0xe5, 0xb7,
0x31, 0x93, 0xd4, 0x98, 0xdc, 0x85, 0x96, 0x4b, 0x08, 0xa7, 0x42, 0x68, 0xa3, 0x55, 0x15, 0xf7,
0x93, 0x3d, 0xc7, 0x80, 0x3e, 0x2c, 0x2b, 0xef, 0xc3, 0x5a, 0x6e, 0x2f, 0xe5, 0x7c, 0x0b, 0xda,
0x1e, 0x13, 0x52, 0xdf, 0x8d, 0x55, 0x7b, 0x37, 0x2d, 0x85, 0x51, 0x57, 0xc3, 0x60, 0xed, 0x60,
0xea, 0x47, 0x4f, 0x38, 0xa1, 0xfc, 0x3f, 0xe1, 0xfc, 0x39, 0xac, 0x17, 0x0c, 0xe6, 0xe9, 0x2d,
0xb9, 0xeb, 0xbd, 0xf5, 0xc3, 0x37, 0x79, 0xed, 0x80, 0x11, 0x8d, 0x09, 0xfe, 0xcd, 0x82, 0x56,
0x6a, 0x17, 0x5d, 0x81, 0xbe, 0x90, 0x9c, 0x52, 0x39, 0x29, 0xb2, 0xec, 0x38, 0xbd, 0x44, 0x6a,
0x60, 0x08, 0x1a, 0x9e, 0x69, 0x63, 0x1d, 0x47, 0x7f, 0xab, 0x04, 0x10, 0xd2, 0x95, 0x34, 0xcd,
0xf7, 0x64, 0xa1, 0x32, 0xdd, 0x63, 0x71, 0x28, 0xf9, 0xcc, 0x64, 0x7a, 0xba, 0x44, 0xe7, 0xa1,
0xfd, 0xde, 0x8f, 0x26, 0x1e, 0x23, 0x54, 0x27, 0x7a, 0xd3, 0x69, 0xbd, 0xf7, 0xa3, 0x21, 0x23,
0x14, 0xbf, 0x80, 0xa6, 0x0e, 0x25, 0xda, 0x81, 0x9e, 0x17, 0x73, 0x4e, 0x43, 0x6f, 0x96, 0x00,
0x13, 0x36, 0x2b, 0x46, 0xa8, 0xd0, 0xca, 0x70, 0x1c, 0xfa, 0x52, 0x68, 0x36, 0x4b, 0x4e, 0xb2,
0x50, 0xd2, 0xd0, 0x0d, 0x99, 0xd0, 0x74, 0x9a, 0x4e, 0xb2, 0xc0, 0x23, 0xb8, 0x34, 0xa2, 0xf2,
0x20, 0x8e, 0x22, 0xc6, 0x25, 0x25, 0xc3, 0x44, 0x8f, 0x4f, 0xf3, 0xbc, 0xbc, 0x02, 0xfd, 0x92,
0x49, 0xd3, 0x10, 0x7a, 0x45, 0x9b, 0x02, 0xff, 0x00, 0xe7, 0x87, 0x99, 0x20, 0x3c, 0xa2, 0x5c,
0xf8, 0x2c, 0x34, 0x97, 0x7c, 0x15, 0x1a, 0xaf, 0x39, 0x0b, 0x4e, 0xc8, 0x11, 0xbd, 0xaf, 0x5a,
0x9a, 0x64, 0x89, 0x63, 0x49, 0x24, 0x97, 0x25, 0xd3, 0x01, 0xf8, 0xc7, 0x82, 0xfe, 0x90, 0x53,
0xe2, 0xab, 0x7e, 0x4c, 0xc6, 0xe1, 0x6b, 0x86, 0x6e, 0x02, 0xf2, 0xb4, 0x64, 0xe2, 0xb9, 0x9c,
0x4c, 0xc2, 0x38, 0x78, 0x45, 0x79, 0x1a, 0x8f, 0x35, 0x2f, 0xc3, 0x7e, 0xa3, 0xe5, 0xe8, 0x2a,
0xac, 0x16, 0xd1, 0xde, 0xd1, 0x51, 0xfa, 0xe4, 0xf4, 0x72, 0xe8, 0xf0, 0xe8, 0x08, 0x7d, 0x09,
0x5b, 0x45, 0x1c, 0xfd, 0x39, 0xf2, 0xb9, 0x6e, 0x8f, 0x93, 0x19, 0x75, 0x79, 0x1a, 0xbb, 0x41,
0x7e, 0x66, 0x3f, 0x03, 0x7c, 0x4f, 0x5d, 0x8e, 0xee, 0xc1, 0x85, 0x9a, 0xe3, 0x01, 0x0b, 0xe5,
0x54, 0x5f, 0x79, 0xd3, 0x39, 0x3f, 0xef, 0xfc, 0x63, 0x05, 0xc0, 0x33, 0xe8, 0x0d, 0xa7, 0x2e,
0x7f, 0x93, 0xd5, 0xf4, 0x27, 0xb0, 0xec, 0x06, 0x2a, 0x43, 0x4e, 0x08, 0x5e, 0x8a, 0x40, 0x77,
0xa1, 0x5b, 0xb0, 0x9e, 0x3e, 0x88, 0x5b, 0xe5, 0x0a, 0x29, 0x05, 0xd1, 0x81, 0x9c, 0x09, 0xbe,
0x03, 0x7d, 0x63, 0x3a, 0xbf, 0x7a, 0xc9, 0xdd, 0x50, 0xb8, 0x9e, 0x76, 0x21, 0x2b, 0x96, 0x5e,
0x41, 0x3a, 0x26, 0xf8, 0x47, 0xe8, 0xe8, 0x0a, 0xd3, 0x6f, 0xbe, 0x79, 0x8d, 0xad, 0x53, 0x5f,
0x63, 0x95, 0x15, 0xaa, 0x33, 0xa4, 0x3c, 0xe7, 0x66, 0x85, 0xda, 0xc7, 0xbf, 0x2c, 0x42, 0xd7,
0x94, 0x70, 0x7c, 0x28, 0x55, 0xa1, 0x30, 0xb5, 0xcc, 0x09, 0xb5, 0xf4, 0x7a, 0x4c, 0xd0, 0x6d,
0xd8, 0x10, 0x53, 0x3f, 0x8a, 0x54, 0x6d, 0x17, 0x8b, 0x3c, 0xc9, 0x26, 0x64, 0xf6, 0x9e, 0x65,
0xc5, 0x8e, 0xee, 0x40, 0x2f, 0x3b, 0xa1, 0xd9, 0x2c, 0xd5, 0xb2, 0x59, 0x31, 0xc0, 0x21, 0x13,
0x12, 0xdd, 0x83, 0xb5, 0xec, 0xa0, 0xe9, 0x0d, 0x8d, 0x13, 0x3a, 0xd8, 0xaa, 0x41, 0x9b, 0x9e,
0x71, 0xd3, 0x74, 0xb2, 0xa6, 0xee, 0x64, 0xe7, 0x4a, 0xa7, 0xb2, 0x80, 0x9a, 0x56, 0x46, 0xe0,
0xc2, 0x01, 0x0d, 0x89, 0x96, 0x0f, 0x59, 0xf8, 0xda, 0xe7, 0x81, 0x4e, 0x9b, 0xc2, 0x73, 0x43,
0x03, 0xd7, 0x3f, 0x34, 0xcf, 0x8d, 0x5e, 0xa0, 0x5d, 0x68, 0xea, 0xd0, 0xa4, 0x31, 0x1e, 0x1c,
0xb7, 0x91, 0xc4, 0xd4, 0x49, 0x60, 0xf8, 0x6f, 0x0b, 0xd6, 0x9f, 0x1e, 0xba, 0x1e, 0x2d, 0xf5,
0xe8, 0xda, 0x49, 0x63, 0x07, 0x7a, 0x7a, 0xc3, 0xb4, 0x82, 0x34, 0xce, 0x2b, 0x4a, 0x68, 0xba,
0x41, 0xb1, 0xc3, 0x2f, 0x9d, 0xa5, 0xc3, 0x67, 0x9e, 0x34, 0x8b, 0x9e, 0x54, 0x72, 0x7b, 0xf9,
0xc3, 0x72, 0xfb, 0x01, 0xa0, 0xa2, 0x5b, 0xd9, 0x93, 0x9b, 0x46, 0xc7, 0x3a, 0x53, 0x74, 0xf6,
0xfe, 0xb2, 0xa0, 0xab, 0x72, 0xf8, 0x80, 0xf2, 0x23, 0xdf, 0xa3, 0xe8, 0xae, 0x7e, 0x27, 0x74,
0xda, 0x6f, 0x55, 0x7d, 0x2a, 0x8c, 0xae, 0x76, 0x39, 0x99, 0x92, 0xd9, 0x6e, 0x01, 0x7d, 0x01,
0xad, 0x74, 0xbe, 0xac, 0x9c, 0x2e, 0x4f, 0x9d, 0xf6, 0xfa, 0xb1, 0x1a, 0xc2, 0x0b, 0xe8, 0x6b,
0xe8, 0x64, 0x93, 0x2c, 0xba, 0x78, 0x5c, 0x7f, 0x51, 0xc1, 0x5c, 0xf3, 0x7b, 0xbf, 0x5a, 0xb0,
0x59, 0x9e, 0x00, 0x8d, 0x5b, 0x3f, 0xc1, 0xff, 0xe6, 0x8c, 0x87, 0xe8, 0xe3, 0x92, 0x9a, 0xfa,
0xc1, 0xd4, 0xbe, 0x76, 0x3a, 0x30, 0xb9, 0x00, 0xc5, 0x62, 0x11, 0x36, 0xd3, 0xd1, 0x66, 0xe8,
0x4a, 0xf7, 0x90, 0xbd, 0x31, 0x2c, 0x46, 0xb0, 0x52, 0x9c, 0xe3, 0xd0, 0x1c, 0x2f, 0xec, 0x8f,
0x8e, 0x59, 0xaa, 0x8e, 0x55, 0x78, 0x01, 0x3d, 0x00, 0xc8, 0xc7, 0x38, 0x74, 0xa9, 0x1a, 0xea,
0xf2, 0x7c, 0x67, 0xcf, 0x9d, 0xba, 0xf0, 0x02, 0x7a, 0x09, 0xfd, 0xf2, 0xe0, 0x86, 0x70, 0x09,
0x39, 0x77, 0x08, 0xb4, 0x77, 0x4e, 0xc4, 0x64, 0x51, 0xf8, 0xc3, 0x82, 0xd5, 0x83, 0xb4, 0x3d,
0x18, 0xff, 0xc7, 0xd0, 0x36, 0xf3, 0x16, 0xba, 0x50, 0x25, 0x5d, 0x1c, 0xfb, 0xec, 0x8b, 0x35,
0xbb, 0x59, 0x04, 0x1e, 0x41, 0x27, 0x1b, 0x83, 0x2a, 0xc9, 0x52, 0x9d, 0xc7, 0xec, 0x4b, 0x75,
0xdb, 0x19, 0xd9, 0x3f, 0x2d, 0x58, 0x35, 0xc5, 0x6d, 0xc8, 0xbe, 0x84, 0x73, 0xf3, 0xc7, 0x88,
0xb9, 0xd7, 0x76, 0xa3, 0x4a, 0xf8, 0x84, 0xf9, 0x03, 0x2f, 0xa0, 0x11, 0xb4, 0x92, 0x91, 0x42,
0xa2, 0xab, 0xe5, 0x5a, 0xa8, 0x1b, 0x38, 0xec, 0x39, 0xed, 0x1b, 0x2f, 0xec, 0x3d, 0x87, 0xfe,
0x53, 0x77, 0x16, 0xd0, 0x30, 0xab, 0xe0, 0x21, 0x2c, 0x27, 0x6f, 0x1e, 0xb2, 0xcb, 0x9a, 0x8b,
0x6f, 0xb0, 0xbd, 0x35, 0x77, 0x2f, 0x0b, 0xc8, 0x14, 0x56, 0xf6, 0x55, 0x8f, 0x32, 0x4a, 0x5f,
0xa8, 0x5f, 0x82, 0x39, 0xad, 0x1a, 0x5d, 0xaf, 0x64, 0x43, 0x7d, 0x3b, 0xaf, 0xa9, 0xd9, 0x57,
0xb0, 0x3a, 0x9c, 0x52, 0xef, 0x2d, 0x8b, 0x33, 0x0f, 0x9e, 0x00, 0xe4, 0x9d, 0xad, 0x92, 0xdd,
0xc7, 0x3a, 0xb9, 0x7d, 0xb9, 0x76, 0xdf, 0x78, 0xf3, 0x6a, 0x59, 0xff, 0xd4, 0x7f, 0xf6, 0x6f,
0x00, 0x00, 0x00, 0xff, 0xff, 0x59, 0xab, 0x01, 0x43, 0xe2, 0x0f, 0x00, 0x00,
// AdServiceClient is the client API for AdService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type AdServiceClient interface {
GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error)
}
type adServiceClient struct {
cc *grpc.ClientConn
}
func NewAdServiceClient(cc *grpc.ClientConn) AdServiceClient {
return &adServiceClient{cc}
}
func (c *adServiceClient) GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) {
out := new(AdResponse)
err := c.cc.Invoke(ctx, "/hipstershop.AdService/GetAds", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// AdServiceServer is the server API for AdService service.
type AdServiceServer interface {
GetAds(context.Context, *AdRequest) (*AdResponse, error)
}
func RegisterAdServiceServer(s *grpc.Server, srv AdServiceServer) {
s.RegisterService(&_AdService_serviceDesc, srv)
}
func _AdService_GetAds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AdServiceServer).GetAds(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/hipstershop.AdService/GetAds",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AdServiceServer).GetAds(ctx, req.(*AdRequest))
}
return interceptor(ctx, in, info, handler)
}
var _AdService_serviceDesc = grpc.ServiceDesc{
ServiceName: "hipstershop.AdService",
HandlerType: (*AdServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetAds",
Handler: _AdService_GetAds_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "demo.proto",
}
func init() { proto.RegisterFile("demo.proto", fileDescriptor_demo_88bb8fdac9cd6be5) }
var fileDescriptor_demo_88bb8fdac9cd6be5 = []byte{
// 1483 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x72, 0xd3, 0xc6,
0x17, 0x8f, 0x92, 0x38, 0x8e, 0x8f, 0x63, 0x27, 0xd9, 0x7f, 0x12, 0x8c, 0xc2, 0x47, 0xd8, 0x0c,
0xfc, 0xa1, 0x80, 0x61, 0xd2, 0xce, 0x70, 0x01, 0x2d, 0xcd, 0x98, 0x8c, 0xf1, 0x14, 0x0a, 0x55,
0xa0, 0x43, 0x87, 0x4e, 0x3d, 0x42, 0xbb, 0x60, 0x95, 0x48, 0x2b, 0x76, 0x57, 0x19, 0xcc, 0x65,
0xfb, 0x00, 0xbd, 0xef, 0x23, 0xf4, 0x05, 0xfa, 0x0e, 0xbd, 0xef, 0x2b, 0xf4, 0x39, 0x3a, 0xbb,
0xd2, 0xea, 0xcb, 0x76, 0x02, 0x37, 0xbd, 0xf3, 0x9e, 0xfd, 0xe9, 0x9c, 0xdf, 0x39, 0x7b, 0xbe,
0x12, 0x00, 0x42, 0x03, 0xd6, 0x8d, 0x38, 0x93, 0x0c, 0x35, 0x47, 0x7e, 0x24, 0x24, 0xe5, 0x62,
0xc4, 0x22, 0x7c, 0x00, 0xcb, 0x3d, 0x97, 0xcb, 0x81, 0xa4, 0x01, 0x3a, 0x0f, 0x10, 0x71, 0x46,
0x62, 0x4f, 0x0e, 0x7d, 0xd2, 0xb1, 0x76, 0xac, 0xab, 0x0d, 0xa7, 0x91, 0x4a, 0x06, 0x04, 0xd9,
0xb0, 0xfc, 0x2e, 0x76, 0x43, 0xe9, 0xcb, 0x71, 0x67, 0x7e, 0xc7, 0xba, 0x5a, 0x73, 0xb2, 0x33,
0x7e, 0x06, 0xed, 0x7d, 0x42, 0x94, 0x16, 0x87, 0xbe, 0x8b, 0xa9, 0x90, 0xe8, 0x0c, 0xd4, 0x63,
0x41, 0x79, 0xae, 0x69, 0x49, 0x1d, 0x07, 0x04, 0x5d, 0x83, 0x45, 0x5f, 0xd2, 0x40, 0xab, 0x68,
0xee, 0x6d, 0x76, 0x0b, 0x6c, 0xba, 0x86, 0x8a, 0xa3, 0x21, 0xf8, 0x3a, 0xac, 0x1d, 0x04, 0x91,
0x1c, 0x2b, 0xf1, 0x69, 0x7a, 0xf1, 0x35, 0x68, 0xf7, 0xa9, 0xfc, 0x28, 0xe8, 0x23, 0x58, 0x54,
0xb8, 0xd9, 0x1c, 0xaf, 0x43, 0x4d, 0x11, 0x10, 0x9d, 0xf9, 0x9d, 0x85, 0xd9, 0x24, 0x13, 0x0c,
0xae, 0x43, 0x4d, 0xb3, 0xc4, 0xdf, 0x83, 0xfd, 0xc8, 0x17, 0xd2, 0xa1, 0x1e, 0x0b, 0x02, 0x1a,
0x12, 0x57, 0xfa, 0x2c, 0x14, 0xa7, 0x06, 0xe4, 0x22, 0x34, 0xf3, 0xb0, 0x27, 0x26, 0x1b, 0x0e,
0x64, 0x71, 0x17, 0xf8, 0x2b, 0xd8, 0x9e, 0xaa, 0x57, 0x44, 0x2c, 0x14, 0xb4, 0xfa, 0xbd, 0x35,
0xf1, 0xfd, 0xef, 0x16, 0xd4, 0x9f, 0x26, 0x47, 0xd4, 0x86, 0xf9, 0x8c, 0xc0, 0xbc, 0x4f, 0x10,
0x82, 0xc5, 0xd0, 0x0d, 0xa8, 0x7e, 0x8d, 0x86, 0xa3, 0x7f, 0xa3, 0x1d, 0x68, 0x12, 0x2a, 0x3c,
0xee, 0x47, 0xca, 0x50, 0x67, 0x41, 0x5f, 0x15, 0x45, 0xa8, 0x03, 0xf5, 0xc8, 0xf7, 0x64, 0xcc,
0x69, 0x67, 0x51, 0xdf, 0x9a, 0x23, 0xba, 0x05, 0x8d, 0x88, 0xfb, 0x1e, 0x1d, 0xc6, 0x82, 0x74,
0x6a, 0xfa, 0x89, 0x51, 0x29, 0x7a, 0x8f, 0x59, 0x48, 0xc7, 0xce, 0xb2, 0x06, 0x3d, 0x17, 0x04,
0x3f, 0x84, 0x0d, 0xe5, 0x5c, 0xca, 0x2f, 0xf7, 0xea, 0x36, 0x2c, 0xa7, 0x2e, 0x24, 0x2e, 0x35,
0xf7, 0x36, 0x4a, 0x7a, 0xd2, 0x0f, 0x9c, 0x0c, 0x85, 0x77, 0x61, 0xbd, 0x4f, 0x8d, 0x22, 0x13,
0xf5, 0x8a, 0xbf, 0xf8, 0x26, 0x6c, 0x1e, 0x52, 0x97, 0x7b, 0xa3, 0xdc, 0x60, 0x02, 0xdc, 0x80,
0xda, 0xbb, 0x98, 0xf2, 0x71, 0x8a, 0x4d, 0x0e, 0xf8, 0x21, 0x6c, 0x55, 0xe1, 0x29, 0xbf, 0x2e,
0xd4, 0x39, 0x15, 0xf1, 0xd1, 0x29, 0xf4, 0x0c, 0x08, 0x87, 0xb0, 0xda, 0xa7, 0xf2, 0xbb, 0x98,
0x49, 0x6a, 0x4c, 0x76, 0xa1, 0xee, 0x12, 0xc2, 0xa9, 0x10, 0xda, 0x68, 0x55, 0xc5, 0x7e, 0x72,
0xe7, 0x18, 0xd0, 0xa7, 0x65, 0xe5, 0x3e, 0xac, 0xe5, 0xf6, 0x52, 0xce, 0x37, 0x61, 0xd9, 0x63,
0x42, 0xea, 0xb7, 0xb1, 0x66, 0xbe, 0x4d, 0x5d, 0x61, 0xd4, 0xd3, 0x30, 0x58, 0x3b, 0x1c, 0xf9,
0xd1, 0x13, 0x4e, 0x28, 0xff, 0x4f, 0x38, 0x7f, 0x01, 0xeb, 0x05, 0x83, 0x79, 0x7a, 0x4b, 0xee,
0x7a, 0x6f, 0xfd, 0xf0, 0x4d, 0x5e, 0x3b, 0x60, 0x44, 0x03, 0x82, 0x7f, 0xb3, 0xa0, 0x9e, 0xda,
0x45, 0x97, 0xa1, 0x2d, 0x24, 0xa7, 0x54, 0x0e, 0x8b, 0x2c, 0x1b, 0x4e, 0x2b, 0x91, 0x1a, 0x18,
0x82, 0x45, 0xcf, 0xb4, 0xb1, 0x86, 0xa3, 0x7f, 0xab, 0x04, 0x10, 0xd2, 0x95, 0x34, 0xcd, 0xf7,
0xe4, 0xa0, 0x32, 0xdd, 0x63, 0x71, 0x28, 0xf9, 0xd8, 0x64, 0x7a, 0x7a, 0x44, 0x67, 0x61, 0xf9,
0x83, 0x1f, 0x0d, 0x3d, 0x46, 0xa8, 0x4e, 0xf4, 0x9a, 0x53, 0xff, 0xe0, 0x47, 0x3d, 0x46, 0x28,
0x7e, 0x01, 0x35, 0x1d, 0x4a, 0xb4, 0x0b, 0x2d, 0x2f, 0xe6, 0x9c, 0x86, 0xde, 0x38, 0x01, 0x26,
0x6c, 0x56, 0x8c, 0x50, 0xa1, 0x95, 0xe1, 0x38, 0xf4, 0xa5, 0xd0, 0x6c, 0x16, 0x9c, 0xe4, 0xa0,
0xa4, 0xa1, 0x1b, 0x32, 0xa1, 0xe9, 0xd4, 0x9c, 0xe4, 0x80, 0xfb, 0x70, 0xa1, 0x4f, 0xe5, 0x61,
0x1c, 0x45, 0x8c, 0x4b, 0x4a, 0x7a, 0x89, 0x1e, 0x9f, 0xe6, 0x79, 0x79, 0x19, 0xda, 0x25, 0x93,
0xa6, 0x21, 0xb4, 0x8a, 0x36, 0x05, 0xfe, 0x11, 0xce, 0xf6, 0x32, 0x41, 0x78, 0x4c, 0xb9, 0xf0,
0x59, 0x68, 0x1e, 0xf9, 0x0a, 0x2c, 0xbe, 0xe6, 0x2c, 0x38, 0x21, 0x47, 0xf4, 0xbd, 0x6a, 0x69,
0x92, 0x25, 0x8e, 0x25, 0x91, 0x5c, 0x92, 0x4c, 0x07, 0xe0, 0x1f, 0x0b, 0xda, 0x3d, 0x4e, 0x89,
0xaf, 0xfa, 0x31, 0x19, 0x84, 0xaf, 0x19, 0xba, 0x01, 0xc8, 0xd3, 0x92, 0xa1, 0xe7, 0x72, 0x32,
0x0c, 0xe3, 0xe0, 0x15, 0xe5, 0x69, 0x3c, 0xd6, 0xbc, 0x0c, 0xfb, 0xad, 0x96, 0xa3, 0x2b, 0xb0,
0x5a, 0x44, 0x7b, 0xc7, 0xc7, 0xe9, 0xc8, 0x69, 0xe5, 0xd0, 0xde, 0xf1, 0x31, 0xfa, 0x12, 0xb6,
0x8b, 0x38, 0xfa, 0x3e, 0xf2, 0xb9, 0x6e, 0x8f, 0xc3, 0x31, 0x75, 0x79, 0x1a, 0xbb, 0x4e, 0xfe,
0xcd, 0x41, 0x06, 0xf8, 0x81, 0xba, 0x1c, 0xdd, 0x87, 0x73, 0x33, 0x3e, 0x0f, 0x58, 0x28, 0x47,
0xfa, 0xc9, 0x6b, 0xce, 0xd9, 0x69, 0xdf, 0x3f, 0x56, 0x00, 0x3c, 0x86, 0x56, 0x6f, 0xe4, 0xf2,
0x37, 0x59, 0x4d, 0x7f, 0x06, 0x4b, 0x6e, 0xa0, 0x32, 0xe4, 0x84, 0xe0, 0xa5, 0x08, 0x74, 0x0f,
0x9a, 0x05, 0xeb, 0xe9, 0x40, 0xdc, 0x2e, 0x57, 0x48, 0x29, 0x88, 0x0e, 0xe4, 0x4c, 0xf0, 0x1d,
0x68, 0x1b, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xb4, 0x0b, 0x59, 0xb1, 0xb4, 0x0a,
0xd2, 0x01, 0xc1, 0x3f, 0x41, 0x43, 0x57, 0x98, 0x9e, 0xf9, 0x66, 0x1a, 0x5b, 0xa7, 0x4e, 0x63,
0x95, 0x15, 0xaa, 0x33, 0xa4, 0x3c, 0xa7, 0x66, 0x85, 0xba, 0xc7, 0xbf, 0xcc, 0x43, 0xd3, 0x94,
0x70, 0x7c, 0x24, 0x55, 0xa1, 0x30, 0x75, 0xcc, 0x09, 0xd5, 0xf5, 0x79, 0x40, 0xd0, 0x6d, 0xd8,
0x10, 0x23, 0x3f, 0x8a, 0x54, 0x6d, 0x17, 0x8b, 0x3c, 0xc9, 0x26, 0x64, 0xee, 0x9e, 0x65, 0xc5,
0x8e, 0xee, 0x40, 0x2b, 0xfb, 0x42, 0xb3, 0x59, 0x98, 0xc9, 0x66, 0xc5, 0x00, 0x7b, 0x4c, 0x48,
0x74, 0x1f, 0xd6, 0xb2, 0x0f, 0x4d, 0x6f, 0x58, 0x3c, 0xa1, 0x83, 0xad, 0x1a, 0xb4, 0xe9, 0x19,
0x37, 0x4c, 0x27, 0xab, 0xe9, 0x4e, 0xb6, 0x55, 0xfa, 0x2a, 0x0b, 0xa8, 0x69, 0x65, 0x04, 0xce,
0x1d, 0xd2, 0x90, 0x68, 0x79, 0x8f, 0x85, 0xaf, 0x7d, 0x1e, 0xe8, 0xb4, 0x29, 0x8c, 0x1b, 0x1a,
0xb8, 0xfe, 0x91, 0x19, 0x37, 0xfa, 0x80, 0xba, 0x50, 0xd3, 0xa1, 0x49, 0x63, 0xdc, 0x99, 0xb4,
0x91, 0xc4, 0xd4, 0x49, 0x60, 0xf8, 0x6f, 0x0b, 0xd6, 0x9f, 0x1e, 0xb9, 0x1e, 0x2d, 0xf5, 0xe8,
0x99, 0x9b, 0xc6, 0x2e, 0xb4, 0xf4, 0x85, 0x69, 0x05, 0x69, 0x9c, 0x57, 0x94, 0xd0, 0x74, 0x83,
0x62, 0x87, 0x5f, 0xf8, 0x98, 0x0e, 0x9f, 0x79, 0x52, 0x2b, 0x7a, 0x52, 0xc9, 0xed, 0xa5, 0x4f,
0xcb, 0xed, 0x07, 0x80, 0x8a, 0x6e, 0x65, 0x23, 0x37, 0x8d, 0x8e, 0xf5, 0x71, 0xd1, 0xe9, 0x42,
0x63, 0x9f, 0x98, 0xa0, 0x5c, 0x82, 0x15, 0x8f, 0x85, 0x92, 0xbe, 0x97, 0xc3, 0xb7, 0x74, 0x6c,
0xba, 0x62, 0x33, 0x95, 0x7d, 0x43, 0xc7, 0x02, 0xdf, 0x02, 0x50, 0xf8, 0xd4, 0xda, 0x25, 0x58,
0x70, 0x89, 0x19, 0xee, 0xab, 0x95, 0x18, 0x38, 0xea, 0x0e, 0xdf, 0x85, 0xf9, 0x7d, 0xa2, 0x34,
0x2b, 0xe6, 0x9c, 0x7a, 0x72, 0x18, 0x73, 0xf3, 0xa2, 0x4d, 0x23, 0x7b, 0xce, 0x8f, 0xd4, 0xbc,
0x51, 0x56, 0xcc, 0xbc, 0x51, 0xbf, 0xf7, 0xfe, 0xb2, 0xa0, 0xa9, 0x2a, 0xec, 0x90, 0xf2, 0x63,
0xdf, 0xa3, 0xe8, 0x9e, 0x9e, 0x62, 0xba, 0x28, 0xb7, 0xab, 0x11, 0x2f, 0x2c, 0xd6, 0x76, 0x39,
0xd5, 0x93, 0xcd, 0x73, 0x0e, 0xdd, 0x85, 0x7a, 0xba, 0xfd, 0x56, 0xbe, 0x2e, 0xef, 0xc4, 0xf6,
0xfa, 0x44, 0x85, 0xe3, 0x39, 0xf4, 0x35, 0x34, 0xb2, 0x3d, 0x1b, 0x9d, 0x9f, 0xd4, 0x5f, 0x54,
0x30, 0xd5, 0xfc, 0xde, 0xaf, 0x16, 0x6c, 0x96, 0xf7, 0x53, 0xe3, 0xd6, 0xcf, 0xf0, 0xbf, 0x29,
0xcb, 0x2b, 0xfa, 0x7f, 0x49, 0xcd, 0xec, 0xb5, 0xd9, 0xbe, 0x7a, 0x3a, 0x30, 0x79, 0x30, 0xc5,
0x62, 0x1e, 0x36, 0xd3, 0xc5, 0xab, 0xe7, 0x4a, 0xf7, 0x88, 0xbd, 0x31, 0x2c, 0xfa, 0xb0, 0x52,
0xdc, 0x32, 0xd1, 0x14, 0x2f, 0xec, 0x4b, 0x13, 0x96, 0xaa, 0x4b, 0x1f, 0x9e, 0x43, 0x0f, 0x00,
0xf2, 0x25, 0x13, 0x5d, 0xa8, 0x86, 0xba, 0xbc, 0x7d, 0xda, 0x53, 0x77, 0x42, 0x3c, 0x87, 0x5e,
0x42, 0xbb, 0xbc, 0x56, 0x22, 0x5c, 0x42, 0x4e, 0x5d, 0x51, 0xed, 0xdd, 0x13, 0x31, 0x59, 0x14,
0xfe, 0xb0, 0x60, 0xf5, 0x30, 0x6d, 0x5e, 0xc6, 0xff, 0x01, 0x2c, 0x9b, 0x6d, 0x10, 0x9d, 0xab,
0x92, 0x2e, 0x2e, 0xa5, 0xf6, 0xf9, 0x19, 0xb7, 0x59, 0x04, 0x1e, 0x41, 0x23, 0x5b, 0xd2, 0x2a,
0xc9, 0x52, 0xdd, 0x16, 0xed, 0x0b, 0xb3, 0xae, 0x33, 0xb2, 0x7f, 0x5a, 0xb0, 0x6a, 0x5a, 0x8f,
0x21, 0xfb, 0x12, 0xb6, 0xa6, 0x2f, 0x39, 0x53, 0x9f, 0xed, 0x7a, 0x95, 0xf0, 0x09, 0xdb, 0x11,
0x9e, 0x43, 0x7d, 0xa8, 0x27, 0x0b, 0x8f, 0x44, 0x57, 0xca, 0xb5, 0x30, 0x6b, 0x1d, 0xb2, 0xa7,
0x0c, 0x17, 0x3c, 0xb7, 0xf7, 0x1c, 0xda, 0x4f, 0xdd, 0x71, 0x40, 0xc3, 0xac, 0x82, 0x7b, 0xb0,
0x94, 0x4c, 0x64, 0x64, 0x97, 0x35, 0x17, 0x37, 0x04, 0x7b, 0x7b, 0xea, 0x5d, 0x16, 0x90, 0x11,
0xac, 0x1c, 0xa8, 0x0e, 0x6a, 0x94, 0xbe, 0x50, 0x7f, 0xb0, 0x4c, 0x19, 0x24, 0xe8, 0x5a, 0x25,
0x1b, 0x66, 0x0f, 0x9b, 0x19, 0x35, 0xfb, 0x0a, 0x56, 0x7b, 0x23, 0xea, 0xbd, 0x65, 0x71, 0xe6,
0xc1, 0x13, 0x80, 0xbc, 0xef, 0x56, 0xb2, 0x7b, 0x62, 0xce, 0xd8, 0x17, 0x67, 0xde, 0x67, 0xde,
0x3c, 0x54, 0x2d, 0xd8, 0x68, 0xbf, 0x0b, 0x4b, 0x7d, 0xb5, 0x83, 0x0b, 0xb4, 0x55, 0x6d, 0xa7,
0xa9, 0xc6, 0x33, 0x13, 0x72, 0xa3, 0xe9, 0xd5, 0x92, 0xfe, 0xe7, 0xc5, 0xe7, 0xff, 0x06, 0x00,
0x00, 0xff, 0xff, 0x22, 0xc9, 0xfe, 0x20, 0xca, 0x10, 0x00, 0x00,
}

View file

@ -15,8 +15,10 @@
package main
import (
"context"
"fmt"
"html/template"
"math/rand"
"net/http"
"os"
"strconv"
@ -78,6 +80,7 @@ func (fe *frontendServer) homeHandler(w http.ResponseWriter, r *http.Request) {
"products": ps,
"cart_size": len(cart),
"banner_color": os.Getenv("BANNER_COLOR"), // illustrates canary deployments
"ad": fe.chooseAd(r.Context(), log),
}); err != nil {
log.Error(err)
}
@ -130,6 +133,7 @@ func (fe *frontendServer) productHandler(w http.ResponseWriter, r *http.Request)
if err := templates.ExecuteTemplate(w, "product", map[string]interface{}{
"session_id": sessionID(r),
"request_id": r.Context().Value(ctxKeyRequestID{}),
"ad": fe.chooseAd(r.Context(), log),
"user_currency": currentCurrency(r),
"currencies": currencies,
"product": product,
@ -340,6 +344,17 @@ func (fe *frontendServer) setCurrencyHandler(w http.ResponseWriter, r *http.Requ
w.WriteHeader(http.StatusFound)
}
// chooseAd queries for advertisements available and randomly chooses one, if
// available. It ignores the error retrieving the ad since it is not critical.
func (fe *frontendServer) chooseAd(ctx context.Context, log logrus.FieldLogger) *pb.Ad {
ads, err := fe.getAd(ctx)
if err != nil {
log.WithField("error", err).Warn("failed to retrieve ads")
return nil
}
return ads[rand.Intn(len(ads))]
}
func renderHTTPError(log logrus.FieldLogger, r *http.Request, w http.ResponseWriter, err error, code int) {
log.WithField("error", err).Error("request error")
errMsg := fmt.Sprintf("%+v", err)

View file

@ -29,6 +29,7 @@ import (
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/plugin/ochttp"
"go.opencensus.io/plugin/ochttp/propagation/b3"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"google.golang.org/grpc"
)
@ -73,6 +74,9 @@ type frontendServer struct {
shippingSvcAddr string
shippingSvcConn *grpc.ClientConn
adSvcAddr string
adSvcConn *grpc.ClientConn
}
func main() {
@ -96,6 +100,7 @@ func main() {
mustMapEnv(&svc.recommendationSvcAddr, "RECOMMENDATION_SERVICE_ADDR")
mustMapEnv(&svc.checkoutSvcAddr, "CHECKOUT_SERVICE_ADDR")
mustMapEnv(&svc.shippingSvcAddr, "SHIPPING_SERVICE_ADDR")
mustMapEnv(&svc.adSvcAddr, "AD_SERVICE_ADDR")
mustConnGRPC(ctx, &svc.currencySvcConn, svc.currencySvcAddr)
mustConnGRPC(ctx, &svc.productCatalogSvcConn, svc.productCatalogSvcAddr)
@ -103,6 +108,7 @@ func main() {
mustConnGRPC(ctx, &svc.recommendationSvcConn, svc.recommendationSvcAddr)
mustConnGRPC(ctx, &svc.shippingSvcConn, svc.shippingSvcAddr)
mustConnGRPC(ctx, &svc.checkoutSvcConn, svc.checkoutSvcAddr)
mustConnGRPC(ctx, &svc.adSvcConn, svc.adSvcAddr)
r := mux.NewRouter()
r.HandleFunc("/", svc.homeHandler).Methods(http.MethodGet, http.MethodHead)
@ -114,6 +120,8 @@ func main() {
r.HandleFunc("/logout", svc.logoutHandler).Methods(http.MethodGet)
r.HandleFunc("/cart/checkout", svc.placeOrderHandler).Methods(http.MethodPost)
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
r.HandleFunc("/robots.txt", func(w http.ResponseWriter, _ *http.Request) { fmt.Fprint(w, "User-agent: *\nDisallow: /") })
r.HandleFunc("/_healthz", func(w http.ResponseWriter, _ *http.Request) { fmt.Fprint(w, "ok") })
var handler http.Handler = r
handler = &logHandler{log: log, next: handler} // add logging
@ -126,6 +134,20 @@ func main() {
log.Fatal(http.ListenAndServe(addr+":"+srvPort, handler))
}
func initStats(log logrus.FieldLogger, exporter *stackdriver.Exporter) {
view.RegisterExporter(exporter)
if err := view.Register(ochttp.DefaultServerViews...); err != nil {
log.Warn("Error registering http default server views")
} else {
log.Info("Registered http default server views")
}
if err := view.Register(ocgrpc.DefaultClientViews...); err != nil {
log.Warn("Error registering grpc default client views")
} else {
log.Info("Registered grpc default client views")
}
}
func initTracing(log logrus.FieldLogger) {
// TODO(ahmetb) this method is duplicated in other microservices using Go
// since they are not sharing packages.
@ -138,6 +160,9 @@ func initTracing(log logrus.FieldLogger) {
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
log.Info("registered stackdriver tracing")
// Register the views to collect server stats.
initStats(log, exporter)
return
}
d := time.Second * 20 * time.Duration(i)

View file

@ -16,6 +16,7 @@ package main
import (
"context"
"time"
pb "github.com/GoogleCloudPlatform/microservices-demo/src/frontend/genproto"
@ -114,3 +115,13 @@ func (fe *frontendServer) getRecommendations(ctx context.Context, userID string,
}
return out, err
}
func (fe *frontendServer) getAd(ctx context.Context) ([]*pb.Ad, error) {
ctx, cancel := context.WithTimeout(ctx, time.Millisecond*100)
defer cancel()
resp, err := pb.NewAdServiceClient(fe.adSvcConn).GetAds(ctx, &pb.AdRequest{
ContextKeys: nil,
})
return resp.GetAds(), errors.Wrap(err, "failed to get ads")
}

View file

@ -0,0 +1,10 @@
{{ define "text_ad" }}
<div class="container">
<div class="alert alert-dark" role="alert">
<strong>Advertisement:</strong>
<a href="{{.RedirectUrl}}" rel="nofollow" target="_blank" class="alert-link">
{{.Text}}
</a>
</div>
</div>
{{ end }}

View file

@ -1,7 +1,12 @@
{{ define "footer" }}
<footer class="py-5 px-5">
<div class="container">
<p>&copy; 2018 Google Inc</p>
<p>
&copy; 2018 Google Inc
<span class="text-muted">
<a href="https://github.com/GoogleCloudPlatform/microservices-demo/">(Source Code)</a>
</span>
</p>
<p>
<small class="text-muted">
This website is hosted for demo purposes only. It is not an
@ -12,7 +17,6 @@
{{ if $.session_id }}session-id: {{ $.session_id }}</br>{{end}}
{{ if $.request_id }}request-id: {{ $.request_id }}</br>{{end}}
</small>
</div>
</footer>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>

View file

@ -51,6 +51,9 @@
</div>
{{ end }}
</div>
<div class="row">
{{ with $.ad }}{{ template "text_ad" . }}{{ end}}
</div>
</div>
</div>
</main>

View file

@ -47,9 +47,10 @@
{{ template "recommendations" $.recommendations }}
{{ end }}
{{ with $.ad }}{{ template "text_ad" . }}{{ end}}
</div>
</div>
</main>
{{ template "footer" . }}
{{ end }}

View file

@ -1,4 +1,7 @@
FROM node:8
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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 /usr/src/app

View file

@ -16,26 +16,26 @@ const cardValidator = require('simple-card-validator');
const uuid = require('uuid/v4');
class CreditCardError extends Error {
constructor(message) {
constructor (message) {
super(message);
this.code = 400; // Invalid argument error
}
}
class InvalidCreditCard extends CreditCardError {
constructor(cardType) {
constructor (cardType) {
super(`Credit card info is invalid`);
}
}
class UnacceptedCreditCard extends CreditCardError {
constructor(cardType) {
constructor (cardType) {
super(`Sorry, we cannot process ${cardType} credit cards. Only VISA or MasterCard is accepted.`);
}
}
class ExpiredCreditCard extends CreditCardError {
constructor(number, month, year) {
constructor (number, month, year) {
super(`Your credit card (ending ${number.substr(-4)}) expired on ${month}/${year}`);
}
}
@ -46,34 +46,29 @@ class ExpiredCreditCard extends CreditCardError {
* @param {*} request
* @return transaction_id - a random uuid v4.
*/
module.exports = function charge(request) {
module.exports = function charge (request) {
const { amount, credit_card: creditCard } = request;
const cardNumber = creditCard.credit_card_number;
const cardInfo = cardValidator(cardNumber);
const {
card_type: cardType,
valid,
cvv_length: cvvLength,
valid
} = cardInfo.getCardDetails();
if (!valid)
throw new InvalidCreditCard();
if (!valid) { throw new InvalidCreditCard(); }
// Only VISA and mastercard is accepted, other card types (AMEX, dinersclub) will
// throw UnacceptedCreditCard error.
if (!(cardType === 'visa' || cardType == 'mastercard'))
throw new UnacceptedCreditCard(cardType);
if (!(cardType === 'visa' || cardType === 'mastercard')) { throw new UnacceptedCreditCard(cardType); }
// Also validate expiration is > today.
const currentMonth = new Date().getMonth() + 1;
const currentYear = new Date().getFullYear();
const { credit_card_expiration_year: year, credit_card_expiration_month: month } = creditCard;
if ((currentYear * 12 + currentMonth) > (year * 12 + month))
throw new ExpiredCreditCard(cardNumber.replace('-', ''), month, year);
if ((currentYear * 12 + currentMonth) > (year * 12 + month)) { throw new ExpiredCreditCard(cardNumber.replace('-', ''), month, year); }
console.log(`Transaction processed: ${cardType} ending ${cardNumber.substr(-4)} \
Amount: ${amount.currency_code}${amount.units}.${amount.nanos}`)
return { transaction_id: uuid() }
}
Amount: ${amount.currency_code}${amount.units}.${amount.nanos}`);
return { transaction_id: uuid() };
};

View file

@ -14,9 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#!/bin/bash -e
# protos are loaded dynamically for node, simply copies over the proto.
mkdir -p proto && \
cp ../../pb/demo.proto proto
mkdir -p proto
cp -r ../../pb/* ./proto

View file

@ -17,25 +17,25 @@
'use strict';
require('@google-cloud/profiler').start({
serviceContext: {
service: 'paymentservice',
version: '1.0.0'
}
});
serviceContext: {
service: 'paymentservice',
version: '1.0.0'
}
});
require('@google-cloud/trace-agent').start();
require('@google-cloud/debug-agent').start({
serviceContext: {
service: 'paymentservice',
version: 'VERSION'
}
})
serviceContext: {
service: 'paymentservice',
version: 'VERSION'
}
});
const path = require('path');
const HipsterShopServer = require('./server');
const PORT = process.env['PORT'];
const PROTO_PATH = __dirname + '/proto/demo.proto';
const PROTO_PATH = path.join(__dirname, '/proto/');
const server = new HipsterShopServer(PROTO_PATH, PORT);
server.listen();

View file

@ -2,9 +2,11 @@
"name": "paymentservice",
"version": "0.0.1",
"description": "Payment Microservice demo",
"repository": "https://github.com/GoogleCloudPlatform/microservices-demo",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "semistandard *.js"
},
"author": "Jonathan Lui",
"license": "ISC",
@ -16,5 +18,8 @@
"grpc": "^1.12.3",
"simple-card-validator": "^1.1.0",
"uuid": "^3.2.1"
},
"devDependencies": {
"semistandard": "^12.0.1"
}
}

View file

@ -108,9 +108,9 @@ message ShipOrderResponse {
}
message Address {
string street_address_1 = 1;
string street_address_2 = 2;
string city= 3;
string street_address = 1;
string city = 2;
string state = 3;
string country = 4;
int32 zip_code = 5;
}
@ -202,21 +202,9 @@ message SendOrderConfirmationRequest {
// -------------Checkout service-----------------
service CheckoutService {
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {}
rpc PlaceOrder(PlaceOrderRequest) returns (PlaceOrderResponse) {}
}
message CreateOrderRequest {
string user_id = 1;
string user_currency = 2;
Address address = 3;
}
message CreateOrderResponse {
repeated OrderItem items = 1;
Money shipping_cost = 2;
}
message PlaceOrderRequest {
string user_id = 1;
string user_currency = 2;
@ -229,3 +217,26 @@ message PlaceOrderRequest {
message PlaceOrderResponse {
OrderResult order = 1;
}
// ------------Ads service------------------
service AdsService {
rpc GetAds(AdsRequest) returns (AdsResponse) {}
}
message AdsRequest {
// List of important key words from the current page describing the context.
repeated string context_keys = 1;
}
message AdsResponse {
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;
}

View file

@ -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);
}

View file

@ -12,17 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
const path = require('path');
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
const charge = require('./charge');
class HipsterShopServer {
constructor(protoFile, port = HipsterShopServer.DEFAULT_PORT) {
constructor (protoRoot, port = HipsterShopServer.DEFAULT_PORT) {
this.port = port;
this.packages = {
hipsterShop: this.loadProto(path.join(protoRoot, 'demo.proto')),
health: this.loadProto(path.join(protoRoot, 'grpc/health/v1/health.proto'))
};
this.server = new grpc.Server();
this.loadProto(protoFile);
this.loadAllProtos(protoRoot);
}
/**
@ -30,10 +36,10 @@ class HipsterShopServer {
* @param {*} call { ChargeRequest }
* @param {*} callback fn(err, ChargeResponse)
*/
static ChargeServiceHandler(call, callback) {
static ChargeServiceHandler (call, callback) {
try {
console.log(`PaymentService#Charge invoked with request ${JSON.stringify(call.request)}`)
const response = charge(call.request)
console.log(`PaymentService#Charge invoked with request ${JSON.stringify(call.request)}`);
const response = charge(call.request);
callback(null, response);
} catch (err) {
console.warn(err);
@ -41,13 +47,17 @@ class HipsterShopServer {
}
}
listen() {
static CheckHandler (call, callback) {
callback(null, { status: 'SERVING' });
}
listen () {
this.server.bind(`0.0.0.0:${this.port}`, grpc.ServerCredentials.createInsecure());
console.log(`PaymentService grpc server listening on ${this.port}`);
this.server.start();
}
loadProto(path) {
loadProto (path) {
const packageDefinition = protoLoader.loadSync(
path,
{
@ -55,21 +65,28 @@ class HipsterShopServer {
longs: String,
enums: String,
defaults: true,
oneofs: true,
},
oneofs: true
}
);
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const hipsterShopPackage = protoDescriptor.hipstershop;
this.addProtoService(hipsterShopPackage.PaymentService.service);
return grpc.loadPackageDefinition(packageDefinition);
}
addProtoService(service) {
loadAllProtos (protoRoot) {
const hipsterShopPackage = this.packages.hipsterShop.hipstershop;
const healthPackage = this.packages.health.grpc.health.v1;
this.server.addService(
service,
hipsterShopPackage.PaymentService.service,
{
charge: HipsterShopServer.ChargeServiceHandler.bind(this),
},
charge: HipsterShopServer.ChargeServiceHandler.bind(this)
}
);
this.server.addService(
healthPackage.Health.service,
{
check: HipsterShopServer.CheckHandler.bind(this)
}
);
}
}

View file

@ -1,4 +1,4 @@
FROM golang:1.10-alpine as builder
FROM golang:1.10-alpine AS builder
RUN apk add --no-cache ca-certificates git && \
wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \
chmod +x /go/bin/dep
@ -13,8 +13,11 @@ RUN dep ensure --vendor-only -v
COPY . .
RUN go build -o /productcatalogservice .
FROM alpine as release
FROM alpine AS release
RUN apk add --no-cache ca-certificates
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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 /productcatalogservice
COPY --from=builder /productcatalogservice ./server
COPY products.json .

View file

@ -10,8 +10,8 @@
"profiler",
"trace/apiv2"
]
revision = "aad3f485ee528456e0768f20397b4d9dd941e755"
version = "v0.25.0"
revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad"
version = "v0.27.0"
[[projects]]
name = "contrib.go.opencensus.io/exporter/stackdriver"
@ -36,8 +36,8 @@
"ptypes/timestamp",
"ptypes/wrappers"
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
name = "github.com/google/go-cmp"
@ -54,7 +54,7 @@
branch = "master"
name = "github.com/google/pprof"
packages = ["profile"]
revision = "ef437552946f69f7e3bdf1fd81c385c29530944d"
revision = "e027b505a088ac3c68c339a1d7ce7724bf34538b"
[[projects]]
name = "github.com/googleapis/gax-go"
@ -77,10 +77,11 @@
"tag",
"trace",
"trace/internal",
"trace/propagation"
"trace/propagation",
"trace/tracestate"
]
revision = "e262766cd0d230a1bb7c37281e345e465f19b41b"
version = "v0.14.0"
revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89"
version = "v0.16.0"
[[projects]]
branch = "master"
@ -95,7 +96,7 @@
"internal/timeseries",
"trace"
]
revision = "f4c29de78a2a91c00474a2e689954305c350adf9"
revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
[[projects]]
branch = "master"
@ -107,7 +108,7 @@
"jws",
"jwt"
]
revision = "3d292e4d0cdc3a0113e6d207bb137145ef1de42f"
revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9"
[[projects]]
branch = "master"
@ -119,7 +120,7 @@
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "0ffbfd41fbef8ffcf9b62b0b0aa3a5873ed7a4fe"
revision = "1561086e645b2809fb9f8a1e2a38160bf8d53bf4"
[[projects]]
name = "golang.org/x/text"
@ -155,7 +156,7 @@
"transport/grpc",
"transport/http"
]
revision = "f6d94689cbd71030af1108ddac733886fcae1d75"
revision = "19ff8768a5c0b8e46ea281065664787eefc24121"
[[projects]]
name = "google.golang.org/appengine"
@ -173,8 +174,8 @@
"socket",
"urlfetch"
]
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06"
version = "v1.2.0"
[[projects]]
branch = "master"
@ -192,7 +193,7 @@
"googleapis/rpc/status",
"protobuf/field_mask"
]
revision = "daca94659cb50e9f37c1b834680f2e46358f10b0"
revision = "c3f76f3b92d1ffa4c58a9ff842a58b8877655e0f"
[[projects]]
name = "google.golang.org/grpc"
@ -208,6 +209,7 @@
"encoding",
"encoding/proto",
"grpclog",
"health/grpc_health_v1",
"internal",
"internal/backoff",
"internal/channelz",
@ -231,6 +233,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "c8e8e119ed16d97490ab7d949aa70654738f91a59da70583dfed22ee44661a1b"
inputs-digest = "b68fd9438c2eb711d9fc51c1f23c5ca0d5169bf4022351dfc400cd35ba39dfaa"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -27,7 +27,7 @@
[[constraint]]
name = "cloud.google.com/go"
version = "0.25.0"
version = "0.27.0"
[[constraint]]
name = "contrib.go.opencensus.io/exporter/stackdriver"
@ -35,7 +35,7 @@
[[constraint]]
name = "github.com/golang/protobuf"
version = "1.1.0"
version = "1.2.0"
[[constraint]]
name = "github.com/google/go-cmp"
@ -43,7 +43,7 @@
[[constraint]]
name = "go.opencensus.io"
version = "0.14.0"
version = "0.16.0"
[[constraint]]
branch = "master"
@ -51,7 +51,7 @@
[[constraint]]
name = "google.golang.org/grpc"
version = "1.14.0"
version = "=1.14.0"
[prune]
go-tests = true

View file

@ -26,11 +26,13 @@ import (
"time"
pb "github.com/GoogleCloudPlatform/microservices-demo/src/productcatalogservice/genproto"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
"cloud.google.com/go/profiler"
"contrib.go.opencensus.io/exporter/stackdriver"
"github.com/golang/protobuf/jsonpb"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
@ -68,11 +70,22 @@ func run(port int) string {
log.Fatal(err)
}
srv := grpc.NewServer(grpc.StatsHandler(&ocgrpc.ServerHandler{}))
pb.RegisterProductCatalogServiceServer(srv, &productCatalog{})
svc := &productCatalog{}
pb.RegisterProductCatalogServiceServer(srv, svc)
healthpb.RegisterHealthServer(srv, svc)
go srv.Serve(l)
return l.Addr().String()
}
func initStats(exporter *stackdriver.Exporter) {
view.RegisterExporter(exporter)
if err := view.Register(ocgrpc.DefaultServerViews...); err != nil {
log.Printf("Error registering default server views")
} else {
log.Printf("Registered default server views")
}
}
func initTracing() {
// TODO(ahmetb) this method is duplicated in other microservices using Go
// since they are not sharing packages.
@ -84,6 +97,9 @@ func initTracing() {
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
log.Print("registered stackdriver tracing")
// Register the views to collect server stats.
initStats(exporter)
return
}
d := time.Second * 10 * time.Duration(i)
@ -127,6 +143,10 @@ func parseCatalog() []*pb.Product {
return cat.Products
}
func (p *productCatalog) Check(ctx context.Context, req *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) {
return &healthpb.HealthCheckResponse{Status: healthpb.HealthCheckResponse_SERVING}, nil
}
func (p *productCatalog) ListProducts(context.Context, *pb.Empty) (*pb.ListProductsResponse, error) {
return &pb.ListProductsResponse{Products: parseCatalog()}, nil
}

View file

@ -3,6 +3,11 @@ FROM grpc/python:1.0
# show python logs as they occur
ENV PYTHONUNBUFFERED=0
# download the grpc health probe
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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
# get packages
WORKDIR /recommendationservice
COPY requirements.txt requirements.txt

File diff suppressed because one or more lines are too long

View file

@ -1,19 +1,3 @@
#!/usr/bin/python
#
# 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.
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
@ -441,11 +425,6 @@ class CheckoutServiceStub(object):
Args:
channel: A grpc.Channel.
"""
self.CreateOrder = channel.unary_unary(
'/hipstershop.CheckoutService/CreateOrder',
request_serializer=demo__pb2.CreateOrderRequest.SerializeToString,
response_deserializer=demo__pb2.CreateOrderResponse.FromString,
)
self.PlaceOrder = channel.unary_unary(
'/hipstershop.CheckoutService/PlaceOrder',
request_serializer=demo__pb2.PlaceOrderRequest.SerializeToString,
@ -458,13 +437,6 @@ class CheckoutServiceServicer(object):
"""
def CreateOrder(self, request, context):
# missing associated documentation comment in .proto file
pass
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def PlaceOrder(self, request, context):
# missing associated documentation comment in .proto file
pass
@ -475,11 +447,6 @@ class CheckoutServiceServicer(object):
def add_CheckoutServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'CreateOrder': grpc.unary_unary_rpc_method_handler(
servicer.CreateOrder,
request_deserializer=demo__pb2.CreateOrderRequest.FromString,
response_serializer=demo__pb2.CreateOrderResponse.SerializeToString,
),
'PlaceOrder': grpc.unary_unary_rpc_method_handler(
servicer.PlaceOrder,
request_deserializer=demo__pb2.PlaceOrderRequest.FromString,
@ -489,3 +456,47 @@ def add_CheckoutServiceServicer_to_server(servicer, server):
generic_handler = grpc.method_handlers_generic_handler(
'hipstershop.CheckoutService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class AdsServiceStub(object):
"""------------Ads service------------------
"""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.GetAds = channel.unary_unary(
'/hipstershop.AdsService/GetAds',
request_serializer=demo__pb2.AdsRequest.SerializeToString,
response_deserializer=demo__pb2.AdsResponse.FromString,
)
class AdsServiceServicer(object):
"""------------Ads service------------------
"""
def GetAds(self, request, context):
# missing associated documentation comment in .proto file
pass
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_AdsServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'GetAds': grpc.unary_unary_rpc_method_handler(
servicer.GetAds,
request_deserializer=demo__pb2.AdsRequest.FromString,
response_serializer=demo__pb2.AdsResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'hipstershop.AdsService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

View file

@ -15,16 +15,19 @@
# limitations under the License.
import grpc
import demo_pb2
import demo_pb2_grpc
from concurrent import futures
import time
import traceback
import random
import os
import googleclouddebugger
import demo_pb2
import demo_pb2_grpc
from grpc_health.v1 import health_pb2
from grpc_health.v1 import health_pb2_grpc
# TODO(morganmclean,ahmetb) tracing currently disabled due to memory leak (see TODO below)
# from opencensus.trace.ext.grpc import server_interceptor
# from opencensus.trace.samplers import always_on
@ -35,7 +38,7 @@ class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer):
def ListRecommendations(self, request, context):
max_responses = 5
# fetch list of products from product catalog stub
cat_response = stub.ListProducts(demo_pb2.Empty())
cat_response = product_catalog_stub.ListProducts(demo_pb2.Empty())
product_ids = [x.id for x in cat_response.products]
filtered_products = list(set(product_ids)-set(request.product_ids))
num_products = len(filtered_products)
@ -50,6 +53,11 @@ class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer):
response.product_ids.extend(prod_list)
return response
def Check(self, request, context):
return health_pb2.HealthCheckResponse(
status=health_pb2.HealthCheckResponse.SERVING)
if __name__ == "__main__":
print("initializing recommendationservice")
@ -78,16 +86,16 @@ if __name__ == "__main__":
if catalog_addr == "":
raise Exception('PRODUCT_CATALOG_SERVICE_ADDR environment variable not set')
print("product catalog address: " + catalog_addr)
# stub for product catalog service
channel = grpc.insecure_channel(catalog_addr)
stub = demo_pb2_grpc.ProductCatalogServiceStub(channel)
product_catalog_stub = demo_pb2_grpc.ProductCatalogServiceStub(channel)
# create gRPC server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) # ,interceptors=(tracer_interceptor,))
# add class to gRPC server
demo_pb2_grpc.add_RecommendationServiceServicer_to_server(RecommendationService(), server)
service = RecommendationService()
demo_pb2_grpc.add_RecommendationServiceServicer_to_server(service, server)
health_pb2_grpc.add_HealthServicer_to_server(service, server)
# start server
print("listening on port: " + port)

View file

@ -1,29 +1,30 @@
cachetools==2.1.0
certifi==2018.4.16
chardet==3.0.4
enum34==1.1.6
futures==3.2.0
google-api-core==1.2.1
google-api-python-client==1.7.4
google-auth==1.5.0
google-auth-httplib2==0.0.3
google-cloud-core==0.28.1
google-cloud-trace==0.19.0
google-python-cloud-debugger==2.8
googleapis-common-protos==1.5.3
grpcio==1.13.0
grpcio-tools==1.0.0
httplib2==0.11.3
idna==2.7
opencensus==0.1.5
protobuf==3.5.2.post1
pyasn1==0.4.3
pyasn1-modules==0.2.2
pytz==2018.5
PyYAML==3.13
requests==2.19.1
rsa==3.4.2
six==1.11.0
uritemplate==3.0.0
urllib3==1.23
virtualenv==16.0.0
cachetools==2.1.0
certifi==2018.4.16
chardet==3.0.4
enum34==1.1.6
futures==3.2.0
google-api-core==1.2.1
google-api-python-client==1.7.4
google-auth==1.5.0
google-auth-httplib2==0.0.3
google-cloud-core==0.28.1
google-cloud-trace==0.19.0
google-python-cloud-debugger==2.8
googleapis-common-protos==1.5.3
grpcio==1.13.0
grpcio-health-checking==1.14.1
grpcio-tools==1.0.0
httplib2==0.11.3
idna==2.7
opencensus==0.1.5
protobuf==3.5.2.post1
pyasn1==0.4.3
pyasn1-modules==0.2.2
pytz==2018.5
PyYAML==3.13
requests==2.19.1
rsa==3.4.2
six==1.11.0
uritemplate==3.0.0
urllib3==1.23
virtualenv==16.0.0

View file

@ -14,6 +14,9 @@ RUN go install .
FROM alpine as release
RUN apk add --no-cache ca-certificates
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.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
COPY --from=builder /go/bin/shippingservice /shippingservice
ENV APP_PORT=50051
EXPOSE 50051

View file

@ -10,8 +10,8 @@
"profiler",
"trace/apiv2"
]
revision = "aad3f485ee528456e0768f20397b4d9dd941e755"
version = "v0.25.0"
revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad"
version = "v0.27.0"
[[projects]]
name = "contrib.go.opencensus.io/exporter/stackdriver"
@ -35,14 +35,14 @@
"ptypes/timestamp",
"ptypes/wrappers"
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/google/pprof"
packages = ["profile"]
revision = "ef437552946f69f7e3bdf1fd81c385c29530944d"
revision = "e027b505a088ac3c68c339a1d7ce7724bf34538b"
[[projects]]
name = "github.com/googleapis/gax-go"
@ -65,10 +65,11 @@
"tag",
"trace",
"trace/internal",
"trace/propagation"
"trace/propagation",
"trace/tracestate"
]
revision = "e262766cd0d230a1bb7c37281e345e465f19b41b"
version = "v0.14.0"
revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89"
version = "v0.16.0"
[[projects]]
branch = "master"
@ -83,7 +84,7 @@
"internal/timeseries",
"trace"
]
revision = "f4c29de78a2a91c00474a2e689954305c350adf9"
revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
[[projects]]
branch = "master"
@ -95,7 +96,7 @@
"jws",
"jwt"
]
revision = "3d292e4d0cdc3a0113e6d207bb137145ef1de42f"
revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9"
[[projects]]
branch = "master"
@ -107,7 +108,7 @@
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "0ffbfd41fbef8ffcf9b62b0b0aa3a5873ed7a4fe"
revision = "1561086e645b2809fb9f8a1e2a38160bf8d53bf4"
[[projects]]
name = "golang.org/x/text"
@ -143,7 +144,7 @@
"transport/grpc",
"transport/http"
]
revision = "f6d94689cbd71030af1108ddac733886fcae1d75"
revision = "19ff8768a5c0b8e46ea281065664787eefc24121"
[[projects]]
name = "google.golang.org/appengine"
@ -161,8 +162,8 @@
"socket",
"urlfetch"
]
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06"
version = "v1.2.0"
[[projects]]
branch = "master"
@ -180,7 +181,7 @@
"googleapis/rpc/status",
"protobuf/field_mask"
]
revision = "daca94659cb50e9f37c1b834680f2e46358f10b0"
revision = "c3f76f3b92d1ffa4c58a9ff842a58b8877655e0f"
[[projects]]
name = "google.golang.org/grpc"
@ -196,6 +197,7 @@
"encoding",
"encoding/proto",
"grpclog",
"health/grpc_health_v1",
"internal",
"internal/backoff",
"internal/channelz",
@ -221,6 +223,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "3f4776192cec97ef87c4d20a52c9752d106a298befc139e5bca176bf915ed63b"
inputs-digest = "5dac84cd5efcc89491aa3cda06a774c1b370c8e0cbdb99668cbfd8ba27b3e32c"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -27,7 +27,7 @@
[[constraint]]
name = "cloud.google.com/go"
version = "0.25.0"
version = "0.27.0"
[[constraint]]
name = "contrib.go.opencensus.io/exporter/stackdriver"
@ -35,11 +35,11 @@
[[constraint]]
name = "github.com/golang/protobuf"
version = "1.1.0"
version = "1.2.0"
[[constraint]]
name = "go.opencensus.io"
version = "0.14.0"
version = "0.16.0"
[[constraint]]
branch = "master"
@ -47,7 +47,7 @@
[[constraint]]
name = "google.golang.org/grpc"
version = "1.14.0"
version = "=1.14.0"
[prune]
go-tests = true

View file

@ -24,12 +24,14 @@ import (
"cloud.google.com/go/profiler"
"contrib.go.opencensus.io/exporter/stackdriver"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
pb "github.com/GoogleCloudPlatform/microservices-demo/src/shippingservice/genproto"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
)
const (
@ -50,13 +52,15 @@ func main() {
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer(grpc.StatsHandler(&ocgrpc.ServerHandler{}))
pb.RegisterShippingServiceServer(s, &server{})
srv := grpc.NewServer(grpc.StatsHandler(&ocgrpc.ServerHandler{}))
svc := &server{}
pb.RegisterShippingServiceServer(srv, svc)
healthpb.RegisterHealthServer(srv, svc)
log.Printf("Shipping Service listening on port %s", port)
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
reflection.Register(srv)
if err := srv.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
@ -64,6 +68,11 @@ func main() {
// server controls RPC service responses.
type server struct{}
// Check is for health checking.
func (s *server) Check(ctx context.Context, req *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) {
return &healthpb.HealthCheckResponse{Status: healthpb.HealthCheckResponse_SERVING}, nil
}
// GetQuote produces a shipping quote (cost) in USD.
func (s *server) GetQuote(ctx context.Context, in *pb.GetQuoteRequest) (*pb.GetQuoteResponse, error) {
log.Printf("[GetQuote] received request")
@ -103,6 +112,15 @@ func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.Sh
}, nil
}
func initStats(exporter *stackdriver.Exporter) {
view.RegisterExporter(exporter)
if err := view.Register(ocgrpc.DefaultServerViews...); err != nil {
log.Printf("Error registering default server views")
} else {
log.Printf("Registered default server views")
}
}
func initTracing() {
// TODO(ahmetb) this method is duplicated in other microservices using Go
// since they are not sharing packages.
@ -114,6 +132,9 @@ func initTracing() {
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
log.Print("registered stackdriver tracing")
// Register the views to collect server stats.
initStats(exporter)
return
}
d := time.Second * 10 * time.Duration(i)