diff --git a/AUTH.md b/AUTH.md new file mode 100644 index 00000000000..9850b8b24ef --- /dev/null +++ b/AUTH.md @@ -0,0 +1,88 @@ +#gRPC Authentication support + +gRPC is designed to plug-in a number of authentication mechanisms. We provide an overview +of the various auth mechanisms supported, discuss the API and demonstrate usage through +code examples, and conclude with a discussion of extensibility. + +###SSL/TLS +gRPC has SSL/TLS integration and promotes the use of SSL/TLS to authenticate the server, +and encrypt all the data exchanged between the client and the server. Optional +mechanisms are available for clients to provide certificates to accomplish mutual +authentication. + +###OAuth 2.0 +gRPC provides a generic mechanism (described below) to attach metadata to requests +and responses. This mechanism can be used to attach OAuth 2.0 Access Tokens to +RPCs being made at a client. Additional support for acquiring Access Tokens while +accessing Google APIs through gRPC is provided for certain auth flows, demonstrated +through code examples below. + +###API +To reduce complexity and minimize API clutter, gRPC works with a unified concept of +a Credentials object. Users construct gRPC credentials using corresponding bootstrap +credentials (e.g., SSL client certs or Service Account Keys), and use the +credentials while creating a gRPC channel to any server. Depending on the type of +credential supplied, the channel uses the credentials during the initial SSL/TLS +handshake with the server, or uses the credential to generate and attach Access +Tokens to each request being made on the channel. + +###Code Examples + +####SSL/TLS for server authentication and encryption +This is the simplest authentication scenario, where a client just wants to +authenticate the server and encrypt all data. + +``` +SslCredentialsOptions ssl_opts; // Options to override SSL params, empty by default +// Create the credentials object by providing service account key in constructor +std::unique_ptr creds = CredentialsFactory::SslCredentials(ssl_opts); +// Create a channel using the credentials created in the previous step +std::shared_ptr channel = CreateChannel(server_name, creds, channel_args); +// Create a stub on the channel +std::unique_ptr stub(Greeter::NewStub(channel)); +// Make actual RPC calls on the stub. +grpc::Status s = stub->sayHello(&context, *request, response); +``` + +For advanced use cases such as modifying the root CA or using client certs, +the corresponding options can be set in the SslCredentialsOptions parameter +passed to the factory method. + + +###Authenticating with Google + +gRPC applications can use a simple API to create a credential that works in various deployment scenarios. + +``` +std::unique_ptr creds = CredentialsFactory::DefaultGoogleCredentials(); +// Create a channel, stub and make RPC calls (same as in the previous example) +std::shared_ptr channel = CreateChannel(server_name, creds, channel_args); +std::unique_ptr stub(Greeter::NewStub(channel)); +grpc::Status s = stub->sayHello(&context, *request, response); +``` + +This credential works for applications using Service Accounts as well as for +applications running in Google Compute Engine (GCE). In the former case, the +service account’s private keys are expected in file located at [TODO: well +known file fath for service account keys] or in the file named in the environment +variable [TODO: add the env var name here]. The keys are used at run-time to +generate bearer tokens that are attached to each outgoing RPC on the +corresponding channel. + +For applications running in GCE, a default service account and corresponding +OAuth scopes can be configured during VM setup. At run-time, this credential +handles communication with the authentication systems to obtain OAuth2 access +tokens and attaches them to each outgoing RPC on the corresponding channel. +Extending gRPC to support other authentication mechanisms +The gRPC protocol is designed with a general mechanism for sending metadata +associated with RPC. Clients can send metadata at the beginning of an RPC and +servers can send back metadata at the beginning and end of the RPC. This +provides a natural mechanism to support OAuth2 and other authentication +mechanisms that need attach bearer tokens to individual request. + +In the simplest case, there is a single line of code required on the client +to add a specific token as metadata to an RPC and a corresponding access on +the server to retrieve this piece of metadata. The generation of the token +on the client side and its verification at the server can be done separately. + +A deeper integration can be achieved by plugging in a gRPC credentials implementation for any custom authentication mechanism that needs to attach per-request tokens. gRPC internals also allow switching out SSL/TLS with other encryption mechanisms. diff --git a/PROTOCOL-HTTP2.md b/PROTOCOL-HTTP2.md new file mode 100644 index 00000000000..810c6b7e529 --- /dev/null +++ b/PROTOCOL-HTTP2.md @@ -0,0 +1,190 @@ +# gRPC over HTTP2 + +## Introduction +This document serves as a detailed description for an implementation of gRPC carried over HTTP2 draft 17 framing. It assumes familiarity with the HTTP2 specification. + +## Protocol +Production rules are using ABNF syntax. + +### Outline + +The following is the general sequence of message atoms in a GRPC request & response message stream + +* Request → Request-Headers *Delimited-Message EOS +* Response → (Response-Headers *Delimited-Message Trailers) / Trailers-Only + + +### Requests + +* Request → Request-Headers *Delimited-Message EOS + +Request-Headers are delivered as HTTP2 headers in HEADERS + CONTINUATION frames. + +* **Request-Headers** → Call-Definition *Custom-Metadata +* **Call-Definition** → Method Scheme Path TE [Authority] [Timeout] [Content-Type] [Message-Type] [Message-Encoding] [User-Agent] +* **Method** → “:method POST” +* **Scheme** → “:scheme ” (“http” / “https”) +* **Path** → “:path” {_path identifying method within exposed API_} +* **Authority** → “:authority” {_virtual host name of authority_} +* **TE** → “te” “trailers” # Used to detect incompatible proxies +* **Timeout** → “grpc-timeout” TimeoutValue TimeoutUnit +* **TimeoutValue** → {_positive integer as ASCII string of at most 8 digits_} +* **TimeoutUnit** → Hour / Minute / Second / Millisecond / Microsecond / Nanosecond +* **Hour** → “H” +* **Minute** → “M” +* **Second** → “S” +* **Millisecond** → “m” +* **Microsecond** → “u” +* **Nanosecond** → “n” +* **Content-Type** → “content-type” “application/grpc” [(“+proto” / “+json” / {_custom_})] +* **Message-Encoding** → “grpc-encoding ” (“gzip” / “deflate” / “snappy” / {_custom_} ) +* **User-Agent** → “user-agent” {_structured user-agent string_} +* **Message-Type** → “grpc-message-type” {_type name for message schema_} +* **Custom-Metadata** → Binary-Header / ASCII-Header +* **Binary-Header** → {lowercase ASCII header name ending in “-bin” } {_base64 encoded value_} +* **ASCII-Header** → {lowercase ASCII header name} {_value_} + + +HTTP2 requires that reserved headers, ones starting with “:” appear before all other headers. Additionally implementations should send **Timeout** immediately after the reserved headers and they should send the **Call-Definition** headers before sending **Custom-Metadata**. + +If **Timeout** is omitted a server should assume an infinite timeout. Client implementations are free to send a default minimum timeout based on their deployment requirements. + +**Custom-Metadata** is an arbitrary set of key-value pairs defined by the application layer. Aside from transport limits on the total length of HTTP2 HEADERS the only other constraint is that header names starting with “grpc-” are reserved for future use. + +Note that HTTP2 does not allow arbitrary octet sequences for header values so binary header values must be encoded using Base64 as per https://tools.ietf.org/html/rfc4648#section-4. Implementations MUST accept padded and un-padded values and should emit un-padded values. Applications define binary headers by having their names end with “-bin”. Runtime libraries use this suffix to detect binary headers and properly apply base64 encoding & decoding as headers are sent and received. + +The repeated sequence of **Delimited-Message** items is delivered in DATA frames + +* **Delimited-Message** → Compressed-Flag Message-Length Message +* **Compressed-Flag** → 0 / 1 # encoded as 1 byte unsigned integer +* **Message-Length** → {_length of Message_} # encoded as 4 byte unsigned integer +* **Message** → *{binary octet} + +A **Compressed-Flag** value of 1 indicates that the binary octet sequence of **Message** is compressed using the mechanism declared by the **Message-Encoding** header. A value of 0 indicates that no encoding of **Message** bytes has occurred. Compression contexts are NOT maintained over message boundaries, implementations must create a new context for each message in the stream. If the **Message-Encoding** header is omitted then the **Compressed-Flag** must be 0. + +For requests, **EOS** (end-of-stream) is indicated by the presence of the END_STREAM flag on the last received DATA frame. In scenarios where the **Request** stream needs to be closed but no data remains to be sent implementations MUST send an empty DATA frame with this flag set. + +###Responses + +* **Response** → (Response-Headers *Delimited-Message Trailers) / Trailers-Only +* **Response-Headers** → HTTP-Status [Message-Encoding] Content-Type *Custom-Metadata +* **Trailers-Only** → HTTP-Status Content-Type Trailers +* **Trailers** → Status [Status-Message] *Custom-Metadata +* **HTTP-Status** → “:status 200” +* **Status** → “grpc-status” +* **Status-Message** → “grpc-message” + +**Response-Headers** & **Trailers-Only** are each delivered in a single HTTP2 HEADERS frame block. Most responses are expected to have both headers and trailers but **Trailers-Only** is permitted for calls that produce an immediate error. Status must be sent in **Trailers** even if the status code is OK. + +For responses end-of-stream is indicated by the presence of the END_STREAM flag on the last received HEADERS frame that carries **Trailers**. + +Implementations should expect broken deployments to send non-200 HTTP status codes in responses as well as a variety of non-GRPC content-types and to omit **Status** & **Status-Message**. Implementations must synthesize a **Status** & **Status-Message** to propagate to the application layer when this occurs. + +####Example + +Sample unary-call showing HTTP2 framing sequence + +**Request** + +``` +HEADERS (flags = END_HEADERS) +:method = POST +:scheme = http +:path = /google.pubsub.v2.PublisherService/CreateTopic +:authority = pubsub.googleapis.com +grpc-timeout = 1S +content-type = application/grpc+proto +grpc-encoding = gzip +authorization = Bearer y235.wef315yfh138vh31hv93hv8h3v + +DATA (flags = END_STREAM) + +``` +**Response** +``` +HEADERS (flags = END_HEADERS) +:status = 200 +grpc-encoding = gzip + +DATA + + +HEADERS (flags = END_STREAM, END_HEADERS) +grpc-status = 0 # OK +trace-proto-bin = jher831yy13JHy3hc +``` +####User Agents + +While the protocol does not require a user-agent to function it is recommended that clients provide a structured user-agent string that provides a basic description of the calling library, version & platform to facilitate issue diagnosis in heterogeneous environments. The following structure is recommended to library developers +``` +User-Agent → “grpc-” Language ?(“-” Variant) “/” Version ?( “ (“ *(AdditionalProperty “;”) “)” ) +``` +E.g. + +``` +grpc-java/1.2.3 +grpc-ruby/1.2.3 +grpc-ruby-jruby/1.3.4 +grpc-java-android/0.9.1 (gingerbread/1.2.4; nexus5; tmobile) +``` +####HTTP2 Transport Mapping + +#####Stream Identification +All GRPC calls need to specify an internal ID. We will use HTTP2 stream-ids as call identifiers in this scheme. NOTE: These id’s are contextual to an open HTTP2 session and will not be unique within a given process that is handling more than one HTTP2 session nor can they be used as GUIDs. + +#####Data Frames +DATA frame boundaries have no relation to **Delimited-Message** boundaries and implementations should make no assumptions about their alignment. + +#####Errors + +When an application or runtime error occurs during an RPC a **Status** and **Status-Message** are delivered in **Trailers**. + +In some cases it is possible that the framing of the message stream has become corrupt and the RPC runtime will choose to use an **RST_STREAM** frame to indicate this state to its peer. RPC runtime implementations should interpret RST_STREAM as immediate full-closure of the stream and should propagate an error up to the calling application layer. + +The following mapping from RST_STREAM error codes to GRPC error codes is applied. + +HTTP2 Code|GRPC Code +----------|----------- +NO_ERROR(0)|INTERNAL - An explicit GRPC status of OK should have been sent but this might be used to aggressively lameduck in some scenarios. +PROTOCOL_ERROR(1)|INTERNAL +INTERNAL_ERROR(2)|INTERNAL +FLOW_CONTROL_ERROR(3)|INTERNAL +SETTINGS_TIMEOUT(4)|INTERNAL +STREAM_CLOSED|No mapping as there is no open stream to propagate to. Implementations should log. +FRAME_SIZE_ERROR|INTERNAL +REFUSED_STREAM|UNAVAILABLE - Indicates that no processing occurred and the request can be retried, possibly elsewhere. +CANCEL(8)|Mapped to call cancellation when sent by a client.Mapped to CANCELLED when sent by a server. Note that servers should only use this mechanism when they need to cancel a call but the payload byte sequence is incomplete. +COMPRESSION_ERROR|INTERNAL +CONNECT_ERROR|INTERNAL +ENHANCE_YOUR_CALM|RESOURCE_EXHAUSTED ...with additional error detail provided by runtime to indicate that the exhausted resource is bandwidth. +INADEQUATE_SECURITY| PERMISSION_DENIED … with additional detail indicating that permission was denied as protocol is not secure enough for call. + + +#####Security + +The HTTP2 specification mandates the use of TLS 1.2 or higher when TLS is used with HTTP2. It also places some additional constraints on the allowed ciphers in deployments to avoid known-problems as well as requiring SNI support. It is also expected that HTTP2 will be used in conjunction with proprietary transport security mechanisms about which the specification can make no meaningful recommendations. + +#####Connection Management +######GOAWAY Frame +Sent by servers to clients to indicate that they will no longer accept any new streams on the associated connections. This frame includes the id of the last successfully accepted stream by the server. Clients should consider any stream initiated after the last successfully accepted stream as UNAVAILABLE and retry the call elsewhere. Clients are free to continue working with the already accepted streams until they complete or the connection is terminated. + +Servers should send GOAWAY before terminating a connection to reliably inform clients which work has been accepted by the server and is being executed. + +######PING Frame +Both clients and servers can send a PING frame that the peer must respond to by precisely echoing what they received. This is used to assert that the connection is still live as well as providing a means to estimate end-to-end latency. If a server initiated PING does not receive a response within the deadline expected by the runtime all outstanding calls on the server will be closed with a CANCELLED status. An expired client initiated PING will cause all calls to be closed with an UNAVAILABLE status. Note that the frequency of PINGs is highly dependent on the network environment, implementations are free to adjust PING frequency based on network and application requirements. + +######Connection failure +If a detectable connection failure occurs on the client all calls will be closed with an UNAVAILABLE status. For servers open calls will be closed with a CANCELLED status. + + +### Appendix A - GRPC for Protobuf + +The service interfaces declared by protobuf are easily mapped onto GRPC by code generation extensions to protoc. The following defines the mapping to be used + + +* **Path** → / Service-Name / {_method name_} +* **Service-Name** → ?( {_proto package name_} "." ) {_service name_} +* **Message-Type** → {_fully qualified proto message name_} +* **Content-Type** → "application/grpc+proto" + + diff --git a/README.md b/README.md index 9a668f3b1cd..acea9289a7a 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,511 @@ -# gRPC Helloworld Tutorial -## TODO: move this to the tutorial sub-folder +# Getting started -A great way to get introduced to gRPC is to work through this tutorial, which -walks you through the construction of simple client and server that introduces -various features of gRPC. +Welcome to the developer documentation for gRPC, a language-neutral, +platform-neutral remote procedure call (RPC) system developed at Google. -When you finish the tutorial, you will be able to +This document introduces you to gRPC with a quick overview and a simple +Hello World example. More documentation is coming soon! -- Create an protobuf schema that defines a simple RPC service -- Create a Java server that implements the schema interface -- Create a Java client that accesses the server -- Create a Go client that accesses the Java server -- Update the service with advanced features like RPC streaming +## Quick start +You can find quick start guides for each language, including installation instructions and examples here: +* [C++](https://github.com/grpc/grpc-common/tree/master/cpp) +* [Java](https://github.com/grpc/grpc-common/tree/master/java) +* [Python](https://github.com/grpc/grpc-common/tree/master/python) +* [Go](https://github.com/grpc/grpc-common/tree/master/go) +* [ruby](https://github.com/grpc/grpc-common/tree/master/ruby) +* [Node.js](https://github.com/grpc/grpc-common/tree/master/node) -# Get Started +## What's in this repository? -The rest of this page explains how you can set up your local machine for development. -If you just want to read the tutorial, you can go straight to the next step: [Step - 0](Step_0.md) +The `grpc-common` repository contains documentation, resources, and examples +for all gRPC users. You can find examples and instructions specific to your +favourite language in the relevant subdirectory. -# Working with the code +You can find out about the gRPC source code repositories in +[`grpc`](https://github.com/grpc/grpc). Each repository provides instructions +for building the appropriate libraries for your language. -You can follow along with this tutorial and hack on the code in the comfort of -your own computer. In this way you can get hands-on practice of really writing -gRPC code. -The tutorial relies on the use of the Git versioning system for source code -management. You don't need to know anything about Git to follow the tutorial -other than how to install and run a few git commands. +## What is gRPC? -# Install Git +In gRPC a *client* application can directly call +methods on a *server* application on a different machine as if it was a +local object, making it easier for you to create distributed applications and +services. As in many RPC systems, gRPC is based around the idea of defining +a *service*, specifying the methods that can be called remotely with their +parameters and return types. On the server side, the server implements this +interface and runs a gRPC server to handle client calls. On the client side, +the client has a *stub* that provides exactly the same methods as the server. + +##TODO: diagram? + +gRPC clients and servers can run and talk to each other in a variety of +environments - from servers inside Google to your own desktop - and can +be written in any of gRPC's [supported languages](link to list). So, for +example, you can easily create a gRPC server in Java with clients in Go, +Python, or Ruby. In addition, the latest Google APIs will have gRPC versions +of their interfaces, letting you easily build Google functionality into +your applications. + + +### Working with protocol buffers + +By default gRPC uses *protocol buffers*, Google’s +mature open source mechanism for serializing structured data (although it +can be used with other data formats such as JSON). As you'll +see in our example below, you define gRPC services using *proto files*, +with method parameters and return types specified as protocol buffer message +types. You +can find out lots more about protocol buffers in the [Protocol Buffers +documentation](https://developers.google.com/protocol-buffers/docs/overview). + +#### Protocol buffer versions + +While protocol buffers have been available for open source users for some +time, our examples use a new flavour of protocol buffers called proto3, +which has a slightly simplified syntax, some useful new features, and supports +lots more languages. This is currently available as an alpha release in +Java, C++, Java_nano (Android Java), Python, and Ruby from [the protocol buffers Github +repo](https://github.com/google/protobuf/releases), as well as a Go language +generator from [the golang/protobuf Github repo](https://github.com/golang/protobuf), with more languages in development. Full documentation for proto3 is currently in development, but you can see +the major differences from the current default version in the [release notes](https://github.com/google/protobuf/releases). + +In general, while you *can* use proto2 (the current default protocol buffers version), we recommend that you use proto3 with gRPC as it lets you use the full range of gRPC-supported languages, as well as avoiding compatibility +issues with proto2 clients talking to proto3 servers and vice versa. + + +## Hello gRPC! + +Now that you know a bit more about gRPC, the easiest way to see how it +works is to look at a simple example. Our Hello World walks you through the +construction of a simple gRPC client-server application, showing you how to: + +- Create a protocol buffers schema that defines a simple RPC service with +a single +Hello World method. +- Create a Java server that implements this interface. +- Create a Java client that accesses the Java server. +- Create a Go client that accesses +the same Java server. +- Update the service with a streaming RPC. + +The complete code for the example is available in the `grpc-common` GitHub +repository. We use the Git versioning system for source code management: +however, you don't need to know anything about Git to follow along other +than how to install and run a few git commands. + +This is an introductory example rather than a comprehensive tutorial, so +don't worry if you're not a Go or +Java developer - the concepts are similar for all languages, and you can +find more implementations of our Hello World example in other languages in +the language-specific folders in this repository. Complete tutorials and +reference documentation for all gRPC languages are coming soon. + + +### Setup + +This section explains how to set up your local machine to work with +the example code. If you just want to read the example, you can go straight +to the [next step](#servicedef). + +#### Install Git You can download and install Git from http://git-scm.com/download. Once installed you should have access to the git command line tool. The main commands that you will need to use are: - git clone ... : clone a remote repository onto your local machine -- git checkout ... : check out a particular branch or a tagged version of the code to hack on +- git checkout ... : check out a particular branch or a tagged version of +the code to hack on -# Download grpc-helloworld +#### Get the source code + +The example code for this and our other examples lives in the `grpc-common` +GitHub repository. Clone this repository to your local machine by running the +following command: -Clone the grpc-helloword repository located at GitHub by running the following command: ``` -git clone https://github.com/google/grpc-helloworld.git +git clone https://github.com/google/grpc-common.git ``` -Change your current directory to grpc-helloworld +Change your current directory to grpc-common/java ``` -cd grpc-helloworld +cd grpc-common/java ``` -# Install Java 8 +#### Install Java 8 -Java gRPC is designed to work with both Java 7 and Java 8. For simplicity, -the example assumes that Java 8 is installed. See -[Install Java 8](http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html) -for instructions. +Java gRPC is designed to work with both Java 7 and Java 8 - our example uses +Java 8. See +[Install Java +8](http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html) +for instructions if you need to install Java 8. -# Install Maven +#### Install Maven -To simplify building and the managing of gRPC's dependencies, the java client -are server are structured as a standard [Maven](http://maven.apache.org/guides/getting-started/) -project. See [Install Maven](http://maven.apache.org/users/index.html) for instructions. +To simplify building and managing gRPC's dependencies, the Java client +and server are structured as a standard +[Maven](http://maven.apache.org/guides/getting-started/) +project. See [Install Maven](http://maven.apache.org/users/index.html) +for instructions. -# Install Go 1.4 +#### Install Go 1.4 Go gRPC requires Go 1.4, the latest version of Go. See [Install Go](https://golang.org/doc/install) for instructions. -# (optional) Install protoc +#### (optional) Install protoc -gRPC uses the latest version of the protocol buffer compiler, protoc. +gRPC uses the latest version of the [protocol +buffer](https://developers.google.com/protocol-buffers/docs/overview) +compiler, protoc. -For following this tutorial, the protoc is not strictly necessary, as all the -generated code is checked into the Git repository. If you want to experiment +Having protoc installed isn't strictly necessary to follow along with this +example, as all the +generated code is checked into the Git repository. However, if you want +to experiment with generating the code yourself, download and install protoc from its [Git repo](https://github.com/google/protobuf) + + +### Defining a service + +The first step in creating our example is to define a *service*: an RPC +service specifies the methods that can be called remotely with their parameters +and return types. As you saw in the +[overview](#protocolbuffers) above, gRPC does this using [protocol +buffers](https://developers.google.com/protocol-buffers/docs/overview). We +use the protocol buffers interface definition language (IDL) to define our +service methods, and define the parameters and return +types as protocol buffer message types. Both the client and the +server use interface code generated from the service definition. + +Here's our example service definition, defined using protocol buffers IDL in +[helloworld.proto](protos/helloworld.proto). The `Greeting` +service has one method, `hello`, that lets the server receive a single +`HelloRequest` +message from the remote client containing the user's name, then send back +a greeting in a single `HelloReply`. This is the simplest type of RPC you +can specify in gRPC - we'll look at some other types later in this document. + +``` +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + + +### Generating gRPC code + +Once we've defined our service, we use the protocol buffer compiler +`protoc` to generate the special client and server code we need to create +our application - right now we're going to generate Java code, though you +can generate gRPC code in any gRPC-supported language (as you'll see later +in this example). The generated code contains both stub code for clients to +use and an abstract interface for servers to implement, both with the method +defined in our `Greeting` service. + +(If you didn't install `protoc` on your system and are working along with +the example, you can skip this step and move +onto the next one where we examine the generated code.) + +As this is our first time using gRPC, we need to build the protobuf plugin +that generates our RPC +classes. By default `protoc` just generates code for reading and writing +protocol buffers, so you need to use plugins to add additional features +to generated code. As we're creating Java code, we use the gRPC Java plugin. + +To build the plugin, follow the instructions in the relevant repo: for Java, +the instructions are in [`grpc-java`](https://github.com/grpc/grpc-java). + +To use it to generate the code: + +```sh +$ mkdir -p src/main/java +$ protoc -I . helloworld.proto +--plugin=protoc-gen-grpc=external/grpc_java/bins/opt/java_plugin \ + --grpc_out=src/main/java \ + --java_out=src/main/java +``` + +[need to update this once I get the plugin built] + +This generates the following classes, which contain all the generated code +we need to create our example: + +- [`Helloworld.java`](java/src/main/java/ex/grpc/Helloworld.java), which +has all the protocol buffer code to populate, serialize, and retrieve our +`HelloRequest` and `HelloReply` message types +- [`GreeterGrpc.java`](java/src/main/java/ex/grpc/GreeterGrpc.java), +which contains (along with some other useful code): + - an interface for `Greeter` servers to implement + + ```java + public static interface Greeter { + + public void SayHello(ex.grpc.Helloworld.HelloRequest request, + com.google.net.stubby.stub.StreamObserver + responseObserver); + } + ``` + + - _stub_ classes that clients can use to talk to a `Greeter` server. As you can see, they also implement the `Greeter` interface. + + ```java +public static class GreeterStub extends + com.google.net.stubby.stub.AbstractStub + implements Greeter { + ... + } + ``` + + +### Writing a server + +Now let's write some code! First we'll create a server application to implement +our service. Note that we're not going to go into a lot of detail about how +to create a server in this section. More detailed information will be in the +tutorial for your chosen language (coming soon). + +Our server application has two classes: + +- a simple service implementation +[GreeterImpl.java](java/src/main/java/ex/grpc/GreeterImpl.java). + +- a server that hosts the service implementation and allows access over the +network: [GreeterServer.java](java/src/main/java/ex/grpc/GreeterServer.java). + +#### Service implementation + +[GreeterImpl.java](java/src/main/java/ex/grpc/GreeterImpl.java) +actually implements our GreetingService's required behaviour. + +As you can see, the class `GreeterImpl` implements the interface +`GreeterGrpc.Greeter` that we [generated](#generating) from our proto +[IDL](java/src/main/proto/helloworld.proto) by implementing the method `hello`: + +```java + public void hello(Helloworld.HelloRequest req, + StreamObserver responseObserver) { + Helloworld.HelloReply reply = + Helloworld.HelloReply.newBuilder().setMessage( + "Hello " + req.getName()).build(); + responseObserver.onValue(reply); + responseObserver.onCompleted(); + } +``` +- `hello` takes two parameters: + -`Helloworld.HelloRequest`: the request + -`StreamObserver`: a response observer, which is + a special interface for the server to call with its response + +To return our response to the client and complete the call: + +1. We construct and populate a `HelloReply` response object with our exciting +message, as specified in our interface definition. +2. We use the`responseObserver` to return the `HelloReply` to the client +and then specify that we've finished dealing with the RPC + + +#### Server implementation + +[GreeterServer.java](java/src/main/java/ex/grpc/GreeterServer.java) +shows the other main feature required to provide a gRPC service; making the service +implementation available from the network. + +```java + private ServerImpl server; + ... + private void start() throws Exception { + server = NettyServerBuilder.forPort(port) + .addService(GreeterGrpc.bindService(new GreeterImpl())) + .build(); + server.startAsync(); + server.awaitRunning(5, TimeUnit.SECONDS); + } + +``` + +Here we create an appropriate gRPC server, binding the `GreeterService` +implementation that we created to a port. Then we start the server running: the server is now ready to receive +requests from `Greeter` service clients on our specified port. We'll cover +how all this works in a bit more detail in our language-specific documentation. + +#### Build it + +Once we've implemented everything, we use Maven to build the server: + +``` +$ mvn package +``` + +We'll look at using a client to access the server in the next section. + + +### Writing a client + +Client-side gRPC is pretty simple. In this step, we'll use the generated code +to write a simple client that can access the `Greeter` server we created +in the [previous section](#server). You can see the complete client code in +[GreeterClient.java](java/src/main/java/ex/grpc/GreeterClient.java). + +Again, we're not going to go into much detail about how to implement a client; +we'll leave that for the tutorial. + +#### Connecting to the service + +First let's look at how we connect to the `Greetings` server. First we need +to create a gRPC channel, specifying the hostname and port of the server we +want to connect to. Then we use the channel to construct the stub instance. + + +```java + private final ChannelImpl channel; + private final GreeterGrpc.GreeterBlockingStub blockingStub; + + public HelloClient(String host, int port) { + channel = NettyChannelBuilder.forAddress(host, port) + .negotiationType(NegotiationType.PLAINTEXT) + .build(); + blockingStub = GreeterGrpc.newBlockingStub(channel); + } + +``` + +In this case, we create a blocking stub. This means that the RPC call waits +for the server to respond, and will either return a response or raise an +exception. gRPC Java has other kinds of stubs that make non-blocking calls +to the server, where the response is returned asynchronously. + +#### Calling an RPC + +Now we can contact the service and obtain a greeting: + +1. We construct and fill in a `HelloRequest` to send to the service. +2. We call the stub's `hello()` RPC with our request and get a `HelloReply` +back, +from which we can get our greeting. + + +```java + public void greet(String name) { + logger.debug("Will try to greet " + name + " ..."); + try { + Helloworld.HelloRequest request = + Helloworld.HelloRequest.newBuilder().setName(name).build(); + Helloworld.HelloReply reply = blockingStub.SayHello(request); + logger.info("Greeting: " + reply.getMessage()); + } catch (RuntimeException e) { + logger.log(Level.WARNING, "RPC failed", e); + return; + } + } + +``` + +#### Build the client + +This is the same as building the server: our client and server are part of +the same maven package so the same command builds both. + +``` +$ mvn package +``` + + +### Try it out! + +We've added simple shell scripts to simplifying running the examples. Now +that they are built, you can run the server with: + +```sh +$ ./run_greeter_server.sh +``` + +and in another terminal window confirm that it receives a message. + +```sh +$ ./run_greeter_client.sh +``` + +### Adding another client + +Finally, let's look at one of gRPC's most useful features - interoperability +between code in different languages. So far, we've just looked at Java code +generated from and implementing our `Greeter` service definition. However, +as you'll see if you look at the language-specific subdirectories +in this repository, we've also generated and implemented `Greeter` +in some of gRPC's other supported languages. Each service +and client uses interface code generated from [exactly the same +.proto](https://github.com/grpc/grpc-common/blob/master/protos/helloworld.proto) +that we used for the Java example. + +So, for example, if we visit the [`go` +directory](https://github.com/grpc/grpc-common/tree/master/go) and look at the +[`greeter_client`](https://github.com/grpc/grpc-common/blob/master/go/greeter_client/main.go), +we can see that like the Java client, it connects to a `Greeter` service +at `localhost:50051` and uses a stub to call the `SayHello` method with a +`HelloRequest`: + +```go +const ( + address = "localhost:50051" + defaultName = "world" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial(address) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := pb.NewGreeterClient(conn) + + // Contact the server and print out its response. + name := defaultName + if len(os.Args) > 1 { + name = os.Args[1] + } + r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: + name}) + if err != nil { + log.Fatalf("could not greet: %v", err) + } + log.Printf("Greeting: %s", r.Message) +} +``` + + +If we run the Java server from earlier in another terminal window, we can +run the Go client and connect to it just like the Java client, even though +it's written in a different language. + +``` +$ greeter_client +``` + diff --git a/Step_0.md b/Step_0.md deleted file mode 100644 index 02a2b04c0e3..00000000000 --- a/Step_0.md +++ /dev/null @@ -1,41 +0,0 @@ -# Step-0: define a service - -This section presents an example of a simple service definition that receives -a message from a remote client. The message contains the users's name and -sends back a greeting to that person. - -It's shown below in full; it's actually contained in separate file -[helloworld.proto](helloworld.proto). - -``` -syntax = "proto3"; - -package helloworld; - -// The request message containing the user's name. -message HelloRequest { - optional string name = 1; -} - -// The response message containing the greetings -message HelloReply { - optional string message = 1; -} - -// The greeting service definition. -service Greeting { - - // Sends a greeting - rpc hello (HelloRequest) returns (HelloReply) { - } -} - -``` - -The service stanza of the message is an example of protobuf service IDL -(Interface Defintion Language). Here, it defines a simple service that -receives a request containing a name and returns a response containing a -message. - -Next, in [Step - 1](Step_1.md), we'll use protoc to generate client code from -this IDL. diff --git a/Step_1.md b/Step_1.md deleted file mode 100644 index 4ac68aba5df..00000000000 --- a/Step_1.md +++ /dev/null @@ -1,33 +0,0 @@ -# Step-1: Generate a service client. - -In this step, we use protoc to generate the java Stub classes. A Stub is the -name gRPC uses for the code that initiates contact with a gRPC service running -remotely via the internet. - -If you did not install protoc on your system, you can skip this step and move -onto the next one where we examine the generated code. - -First, you'll need to build the protobuf plugin that generates the rpc -classes. `protoc` uses other tools called plugins to add additional features -to generated code. - -The grpc Java Stub classes are created using a grpc java plugin, but first the -plugin must be built and installed. - -To build the plugin: -``` -$ pushd external/grpc_java -$ make java_plugin -$ popd -``` - -To use it to generate the code: -``` -$ mkdir -p src/main/java -$ protoc -I . helloworld.proto --plugin=protoc-gen-grpc=external/grpc_java/bins/opt/java_plugin \ - --grpc_out=src/main/java \ - --java_out=src/main/java -``` - -Next, in [Step-2](Step-2.md), we'll use the generated Stub implementation to -write a client that uses the generated code to make a call to a service. diff --git a/Step_2.md b/Step_2.md deleted file mode 100644 index dd134a989c5..00000000000 --- a/Step_2.md +++ /dev/null @@ -1,85 +0,0 @@ -# Step-2: Write a service client. - -This step uses the generated code to write a simple client to access the hello -service. The full client is in [GreetingsClient.java](src/main/java/ex/grpc/GreetingsClient.java). - - -## Configuring the service to connect to. - -The client contains uses a Stub to contact the service. The internet address -is configured in the client constructor. gRPC Channel is the abstraction over -transport handling; its constructor accepts the host name and port of the -service. The channel in turn is used to construct the Stub. - - -``` - private final ChannelImpl channel; - private final GreetingGrpc.GreetingBlockingStub blockingStub; - - public HelloClient(String host, int port) { - channel = NettyChannelBuilder.forAddress(host, port) - .negotiationType(NegotiationType.PLAINTEXT) - .build(); - blockingStub = GreetingGrpc.newBlockingStub(channel); - } - -``` - -## Obtaining a greeting - -The greet method uses the stub to contact the service and obtain a greeting. -It: -- constructs a request -- obtains a reply from the stub -- prints out the greeting - - -``` - public void greet(String name) { - logger.debug("Will try to greet " + name + " ..."); - try { - Helloworld.HelloRequest request = Helloworld.HelloRequest.newBuilder().setName(name).build(); - Helloworld.HelloReply reply = blockingStub.hello(request); - logger.info("Greeting: " + reply.getMessage()); - } catch (RuntimeException e) { - logger.log(Level.WARNING, "RPC failed", e); - return; - } - } - -``` - -## Running from the command line - -The main method puts together the example so that it can be run from a command -line. - -``` - /* Access a service running on the local machine on port 50051 */ - HelloClient client = new HelloClient("localhost", 50051); - String user = "world"; - if (args.length > 1) { - user = args[1]; - } - client.greet(user); - -``` - -It can be built as follows. - -``` -$ mvn package -``` - -It can also be run, but doing so now would end up a with a failure as there is -no server available yet. The [next step](Step-3.md), describes how to -implement, build and run a server that supports the service description. - -## Notes - -- the client uses a blocking stub. This means that the RPC call waits for the - server to respond, and will either return a response or raise an exception. - -- gRPC Java has other kinds of stubs that make non-blocking calls to the - server, where the response is returned asynchronously. Usage of these stubs - is a more advanced topic and will be described in later steps. diff --git a/Step_3.md b/Step_3.md deleted file mode 100644 index 56d6e7cfd3a..00000000000 --- a/Step_3.md +++ /dev/null @@ -1,82 +0,0 @@ -# Step-3: Implement a server. - -This step extends the generated server skeleton code to write a simple server -that provides the hello service. This in introduces two new classes - -- a service implementation [GreetingsImpl.java](src/main/java/ex/grpc/GreetingsImpl.java). - -- a server that hosts the service implementation and allows to accessed over the network: [GreetingsServer.java](src/main/java/ex/grpc/GreetingsServer.java). - -## Service implementation - -[GreetingsSImpl.java](src/main/java/ex/grpc/GreetingsImpl.java) -implements the behaviour we require of our GreetingService. There are a -number of important features of gRPC being used here: - -``` - public void hello(Helloworld.HelloRequest req, - StreamObserver responseObserver) { - Helloworld.HelloReply reply = Helloworld.HelloReply.newBuilder().setMessage( - "Hello " + req.getName()).build(); - responseObserver.onValue(reply); - responseObserver.onCompleted(); - } -``` - -- it provides a class `GreetingsImpl` that implements a generated interface `GreetingsGrpc.Greetings` -- `GreetingsGrpc.Greetings` declares the method `hello` that was declared in the proto [IDL](src/main/proto/helloworld.proto) -- `hello's` signature is typesafe: - hello(Helloworld.HelloRequest req, StreamObserver responseObserver) -- `hello` takes two parameters: - `Helloworld.HelloRequest`: the request - `StreamObserver`: a response observer, an interface to be called with the response value -- to complete the call - - the return value is constructed - - the responseObserver.onValue() is called with the response - - responseObserver.onCompleted() is called to indicate that no more work will done on the RPC. - - -## Server implementation - -[GreetingsServer.java](src/main/java/ex/grpc/GreetingsServer.java) shows the -other main feature to required to provde gRPC service; how to allow a service -implementation to be accessed from the network. - -``` - private void start() throws Exception { - server = NettyServerBuilder.forPort(port) - .addService(GreetingsGrpc.bindService(new GreetingsImpl())) - .build(); - server.startAsync(); - server.awaitRunning(5, TimeUnit.SECONDS); - } - -``` - -- it provides a class `GreetingsServer` that holds a `ServerImpl` that will run the server -- in the `start` method, `GreetingServer` binds the `GreetingsService` implementation to a port and begins running it -- there is also a `stop` method that takes care of shutting down the service and cleaning up when the program exits - -## Build it - -This is the same as before: our client and server are part of the same maven -package so the same command builds both. - -``` -$ mvn package -``` - -## Try them out - -We've added simple shell scripts to simplifying running the examples. Now -that they are built, you can run the server with. - -``` -$ ./run_greetings_server.sh -``` - -In another termainal window and confirm that it receives a message. - -``` -$ ./run_greetings_client.sh -``` diff --git a/cpp/README.md b/cpp/README.md new file mode 100644 index 00000000000..fe9b71620e7 --- /dev/null +++ b/cpp/README.md @@ -0,0 +1,53 @@ +#gRPC in 3 minutes (C++) + +## Installation + +To install gRPC on your system, follow the instructions here: +[https://github.com/grpc/grpc/blob/master/INSTALL](https://github.com/grpc/grpc/blob/master/INSTALL). + +## Hello C++ gRPC! + +Here's how to build and run the C++ implementation of the [Hello World](https://github.com/grpc/grpc-common/blob/master/protos/helloworld.proto) example used in [Getting started](https://github.com/grpc/grpc-common). + +The example code for this and our other examples lives in the `grpc-common` +GitHub repository. Clone this repository to your local machine by running the +following command: + + +```sh +$ git clone https://github.com/google/grpc-common.git +``` + +Change your current directory to grpc-common/cpp/helloworld + +```sh +$ cd grpc-common/cpp/helloworld/ +``` + + +### Generating gRPC code + +To generate the client and server side interfaces: + +```sh +$ make helloworld.pb.cc +``` +Which internally invokes the proto-compiler as: + +```sh +$protoc -I ../../protos/ --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin helloworld.proto +``` + +### Client and server implementations + +The client implementation is at [greeter_client.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_client.cc). + +The server implementation is at [greeter_server.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_server.cc). + +### Try it! + +###TODO: instructions to run server and client + +## Tutorial + +You can find a more detailed tutorial in [gRPC Basics: C++](https://github.com/grpc/grpc-common/blob/master/cpp/cpptutorial.md) diff --git a/cpp/cpptutorial.md b/cpp/cpptutorial.md new file mode 100644 index 00000000000..21026781638 --- /dev/null +++ b/cpp/cpptutorial.md @@ -0,0 +1,130 @@ +#gRPC Basics: C++ + +This tutorial provides a basic C++ programmer's introduction to working with gRPC. By walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Generate server and client code using the protocol buffer compiler. +- Use the C++ gRPC API to write a simple client and server for your service. + +It assumes that you have read the [Getting started](https://github.com/grpc/grpc-common) guide and are familiar with [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial uses the proto3 version of the protocol buffers language, which is currently in alpha release: you can see the [release notes](https://github.com/google/protobuf/releases) for the new version in the protocol buffers Github repository. + +This isn't a comprehensive guide to using gRPC in C++: more reference documentation is coming soon. + +## Why use gRPC? + +Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. + +With gRPC we can define our service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet - all the complexity of communication between different languages and environments is handled for you by gRPC. We also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. + +[possibly insert more advantages here] + +## Example code and setup + +The example code for our tutorial is in [grpc/grpc-common/cpp/route_guide](https://github.com/grpc/grpc-common/cpp/route_guide). To download the example, clone the `grpc-common` repository by running the following command: +```shell +$ git clone https://github.com/google/grpc-common.git +``` + +Then change your current directory to `grpc-common/cpp/route_guide`: +```shell +$ cd grpc-common/cpp/route_guide +``` + +Although we've provided the complete example so you don't need to generate the gRPC code yourself, if you want to try generating your own server and client interface code you can follow the setup instructions for the C++ gRPC libraries in [grpc/grpc/INSTALL](https://github.com/grpc/grpc/blob/master/INSTALL). + + +## Defining the service + +Our first step (as you'll know from [Getting started](https://github.com/grpc/grpc-common)) is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file in [`grpc-common/protos/route_guide.proto`](https://github.com/grpc/grpc-common/blob/master/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +``` +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response types. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call. +``` + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *server-side streaming RPC* where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. As you can see in our example, you specify a server-side streaming method by placing the `stream` keyword before the *response* type. +``` + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *client-side streaming RPC* where the client writes a sequence of messages and sends them to the server, again using a provided stream. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a server-side streaming method by placing the `stream` keyword before the *request* type. +``` + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. +``` + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: +``` +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + + +## Generating client and server code + +Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC C++ plugin. + +For simplicity, we've provided a [makefile](https://github.com/grpc/grpc-common/blob/master/cpp/route_guide/Makefile) that runs `protoc` for you with the appropriate plugin, input, and output (if you want to run this yourself, make sure you've followed the [installation instructions](https://github.com/grpc/grpc/blob/master/INSTALL) first): + +```shell +$ make route_guide.pb.cc +``` + +which actually runs: + +[actual command] + +Running this command generates the following files: +- `route_guide.pb.h`, the header which declares your generated classes +- `route_guide.pb.cc`, which contains the implementation of your classes + +These contain: +- All the protocol buffer code to populate, serialize, and retrieve our request and response message types +- A class called `RouteGuide` that contains both a remote interface type (or *stub*) for clients to call and an abstract interface for servers to implement, both with the methods defined in the `RouteGuide` service. + + +## Creating the server + +First let's look at how we create a `RouteGuide` server. + +There are two parts to making our `RouteGuide` service work: +- Implementing the service interface generated from our service definition: doing the actual "work" of our service. +- Running a gRPC server to listen for requests from clients and return the service responses + + +## Creating the client + + + + + + diff --git a/cpp/helloworld/Makefile b/cpp/helloworld/Makefile new file mode 100644 index 00000000000..83f2ad49044 --- /dev/null +++ b/cpp/helloworld/Makefile @@ -0,0 +1,110 @@ +# +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +CXX = g++ +CPPFLAGS = -I/usr/local/include -pthread +CXXFLAGS = -std=c++11 +LDFLAGS = -L/usr/local/lib -lgrpc -lgrpc++ -lprotobuf -lpthread -ldl +PROTOC = protoc +GRPC_CPP_PLUGIN = grpc_cpp_plugin +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` + +PROTOS_PATH = ../../protos + +vpath %.proto $(PROTOS_PATH) + +all: system-check greeter_client greeter_server + +greeter_client: helloworld.pb.o greeter_client.o + $(CXX) $^ $(LDFLAGS) -o $@ + +greeter_server: helloworld.pb.o greeter_server.o + $(CXX) $^ $(LDFLAGS) -o $@ + +%.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +clean: + rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server + + +# The following is to test your system and ensure a smoother experience. +# They are by no means necessary to actually compile a grpc-enabled software. + +PROTOC_CMD = which $(PROTOC) +PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3 +PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN) +HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false) +ifeq ($(HAS_PROTOC),true) +HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) +endif +HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false) + +SYSTEM_OK = false +ifeq ($(HAS_VALID_PROTOC),true) +ifeq ($(HAS_PLUGIN),true) +SYSTEM_OK = true +endif +endif + +system-check: +ifneq ($(HAS_VALID_PROTOC),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have protoc 3.0.0 installed in your path." + @echo "Please install Google protocol buffers 3.0.0 and its compiler." + @echo "You can find it here:" + @echo + @echo " https://github.com/google/protobuf/releases/tag/v3.0.0-alpha-1" + @echo + @echo "Here is what I get when trying to evaluate your version of protoc:" + @echo + -$(PROTOC) --version + @echo + @echo +endif +ifneq ($(HAS_PLUGIN),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have the grpc c++ protobuf plugin installed in your path." + @echo "Please install grpc. You can find it here:" + @echo + @echo " https://github.com/grpc/grpc" + @echo + @echo "Here is what I get when trying to detect if you have the plugin:" + @echo + -which $(GRPC_CPP_PLUGIN) + @echo + @echo +endif +ifneq ($(SYSTEM_OK),true) + @false +endif diff --git a/cpp/helloworld/README.md b/cpp/helloworld/README.md new file mode 100644 index 00000000000..952325b4461 --- /dev/null +++ b/cpp/helloworld/README.md @@ -0,0 +1,95 @@ +# gRPC C++ Hello World Tutorial + +### Install gRPC +Make sure you have installed gRPC on your system. Follow the instructions here: +[https://github.com/grpc/grpc/blob/master/INSTALL](https://github.com/grpc/grpc/blob/master/INSTALL). + +### Get the tutorial source code + +The example code for this and our other examples lives in the `grpc-common` +GitHub repository. Clone this repository to your local machine by running the +following command: + + +```sh +$ git clone https://github.com/google/grpc-common.git +``` + +Change your current directory to grpc-common/cpp/helloworld + +```sh +$ cd grpc-common/cpp/helloworld/ +``` + +### Defining a service + +The first step in creating our example is to define a *service*: an RPC +service specifies the methods that can be called remotely with their parameters +and return types. As you saw in the +[overview](#protocolbuffers) above, gRPC does this using [protocol +buffers](https://developers.google.com/protocol-buffers/docs/overview). We +use the protocol buffers interface definition language (IDL) to define our +service methods, and define the parameters and return +types as protocol buffer message types. Both the client and the +server use interface code generated from the service definition. + +Here's our example service definition, defined using protocol buffers IDL in +[helloworld.proto](https://github.com/grpc/grpc-common/blob/master/protos/helloworld.proto). The `Greeting` +service has one method, `hello`, that lets the server receive a single +`HelloRequest` +message from the remote client containing the user's name, then send back +a greeting in a single `HelloReply`. This is the simplest type of RPC you +can specify in gRPC - we'll look at some other types later in this document. + +``` +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + + +### Generating gRPC code + +Once we've defined our service, we use the protocol buffer compiler +`protoc` to generate the special client and server code we need to create +our application. The generated code contains both stub code for clients to +use and an abstract interface for servers to implement, both with the method +defined in our `Greeting` service. + +To generate the client and server side interfaces: + +```sh +$ make helloworld.pb.cc +``` +Which internally invokes the proto-compiler as: + +```sh +$protoc -I ../../protos/ --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin helloworld.proto +``` + +### Writing a client + +This is an incomplete tutorial. For now the reader should refer to [greeter_client.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_client.cc). + +### Writing a server + +This is an incomplete tutorial. For now the reader should refer to [greeter_server.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_server.cc). diff --git a/cpp/helloworld/greeter_client.cc b/cpp/helloworld/greeter_client.cc new file mode 100644 index 00000000000..3c2bbc20747 --- /dev/null +++ b/cpp/helloworld/greeter_client.cc @@ -0,0 +1,91 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "helloworld.pb.h" + +using grpc::ChannelArguments; +using grpc::ChannelInterface; +using grpc::ClientContext; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +class GreeterClient { + public: + GreeterClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + std::string SayHello(const std::string& user) { + HelloRequest request; + request.set_name(user); + HelloReply reply; + ClientContext context; + + Status status = stub_->SayHello(&context, request, &reply); + if (status.IsOk()) { + return reply.message(); + } else { + return "Rpc failed"; + } + } + + void Shutdown() { stub_.reset(); } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + grpc_init(); + + GreeterClient greeter( + grpc::CreateChannel("localhost:50051", ChannelArguments())); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + + greeter.Shutdown(); + + grpc_shutdown(); +} diff --git a/cpp/helloworld/greeter_server.cc b/cpp/helloworld/greeter_server.cc new file mode 100644 index 00000000000..01a0bf242dd --- /dev/null +++ b/cpp/helloworld/greeter_server.cc @@ -0,0 +1,84 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "helloworld.pb.h" + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +class GreeterServiceImpl final : public Greeter::Service { + Status SayHello(ServerContext* context, const HelloRequest* request, + HelloReply* reply) override { + std::string prefix("Hello "); + reply->set_message(prefix + request->name()); + return Status::OK; + } +}; + +void RunServer() { + std::string server_address("0.0.0.0:50051"); + GreeterServiceImpl service; + + ServerBuilder builder; + builder.AddPort(server_address); + builder.RegisterService(&service); + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(5)); + } +} + +int main(int argc, char** argv) { + grpc_init(); + + RunServer(); + + grpc_shutdown(); + return 0; +} diff --git a/cpp/helloworld/helloworld.pb.cc b/cpp/helloworld/helloworld.pb.cc new file mode 100644 index 00000000000..9540f2c94c1 --- /dev/null +++ b/cpp/helloworld/helloworld.pb.cc @@ -0,0 +1,640 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: helloworld.proto + +#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION +#include "helloworld.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) + +namespace helloworld { + +namespace { + +const ::google::protobuf::Descriptor* HelloRequest_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + HelloRequest_reflection_ = NULL; +const ::google::protobuf::Descriptor* HelloReply_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + HelloReply_reflection_ = NULL; + +} // namespace + + +void protobuf_AssignDesc_helloworld_2eproto() { + protobuf_AddDesc_helloworld_2eproto(); + const ::google::protobuf::FileDescriptor* file = + ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( + "helloworld.proto"); + GOOGLE_CHECK(file != NULL); + HelloRequest_descriptor_ = file->message_type(0); + static const int HelloRequest_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HelloRequest, name_), + }; + HelloRequest_reflection_ = + ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( + HelloRequest_descriptor_, + HelloRequest::default_instance_, + HelloRequest_offsets_, + -1, + -1, + -1, + sizeof(HelloRequest), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HelloRequest, _internal_metadata_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HelloRequest, _is_default_instance_)); + HelloReply_descriptor_ = file->message_type(1); + static const int HelloReply_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HelloReply, message_), + }; + HelloReply_reflection_ = + ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( + HelloReply_descriptor_, + HelloReply::default_instance_, + HelloReply_offsets_, + -1, + -1, + -1, + sizeof(HelloReply), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HelloReply, _internal_metadata_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HelloReply, _is_default_instance_)); +} + +namespace { + +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); +inline void protobuf_AssignDescriptorsOnce() { + ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, + &protobuf_AssignDesc_helloworld_2eproto); +} + +void protobuf_RegisterTypes(const ::std::string&) { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + HelloRequest_descriptor_, &HelloRequest::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + HelloReply_descriptor_, &HelloReply::default_instance()); +} + +} // namespace + +void protobuf_ShutdownFile_helloworld_2eproto() { + delete HelloRequest::default_instance_; + delete HelloRequest_reflection_; + delete HelloReply::default_instance_; + delete HelloReply_reflection_; +} + +void protobuf_AddDesc_helloworld_2eproto() { + static bool already_here = false; + if (already_here) return; + already_here = true; + GOOGLE_PROTOBUF_VERIFY_VERSION; + + ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( + "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" + "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" + "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" + "loworld.HelloRequest\032\026.helloworld.HelloR" + "eply\"\000B\t\n\007ex.grpcb\006proto3", 185); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( + "helloworld.proto", &protobuf_RegisterTypes); + HelloRequest::default_instance_ = new HelloRequest(); + HelloReply::default_instance_ = new HelloReply(); + HelloRequest::default_instance_->InitAsDefaultInstance(); + HelloReply::default_instance_->InitAsDefaultInstance(); + ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_helloworld_2eproto); +} + +// Force AddDescriptors() to be called at static initialization time. +struct StaticDescriptorInitializer_helloworld_2eproto { + StaticDescriptorInitializer_helloworld_2eproto() { + protobuf_AddDesc_helloworld_2eproto(); + } +} static_descriptor_initializer_helloworld_2eproto_; + +namespace { + +static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD; +static void MergeFromFail(int line) { + GOOGLE_CHECK(false) << __FILE__ << ":" << line; +} + +} // namespace + + +// =================================================================== + +#ifndef _MSC_VER +const int HelloRequest::kNameFieldNumber; +#endif // !_MSC_VER + +HelloRequest::HelloRequest() + : ::google::protobuf::Message() , _internal_metadata_(NULL) { + SharedCtor(); + // @@protoc_insertion_point(constructor:helloworld.HelloRequest) +} + +void HelloRequest::InitAsDefaultInstance() { + _is_default_instance_ = true; +} + +HelloRequest::HelloRequest(const HelloRequest& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + SharedCtor(); + MergeFrom(from); + // @@protoc_insertion_point(copy_constructor:helloworld.HelloRequest) +} + +void HelloRequest::SharedCtor() { + _is_default_instance_ = false; + ::google::protobuf::internal::GetEmptyString(); + _cached_size_ = 0; + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +HelloRequest::~HelloRequest() { + // @@protoc_insertion_point(destructor:helloworld.HelloRequest) + SharedDtor(); +} + +void HelloRequest::SharedDtor() { + name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (this != default_instance_) { + } +} + +void HelloRequest::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* HelloRequest::descriptor() { + protobuf_AssignDescriptorsOnce(); + return HelloRequest_descriptor_; +} + +const HelloRequest& HelloRequest::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_helloworld_2eproto(); + return *default_instance_; +} + +HelloRequest* HelloRequest::default_instance_ = NULL; + +HelloRequest* HelloRequest::New(::google::protobuf::Arena* arena) const { + HelloRequest* n = new HelloRequest; + if (arena != NULL) { + arena->Own(n); + } + return n; +} + +void HelloRequest::Clear() { + name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +bool HelloRequest::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:helloworld.HelloRequest) + for (;;) { + ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); + tag = p.first; + if (!p.second) goto handle_unusual; + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (tag == 10) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE, + "helloworld.HelloRequest.name"); + } else { + goto handle_unusual; + } + if (input->ExpectAtEnd()) goto success; + break; + } + + default: { + handle_unusual: + if (tag == 0 || + ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + goto success; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:helloworld.HelloRequest) + return true; +failure: + // @@protoc_insertion_point(parse_failure:helloworld.HelloRequest) + return false; +#undef DO_ +} + +void HelloRequest::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:helloworld.HelloRequest) + // optional string name = 1; + if (this->name().size() > 0) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "helloworld.HelloRequest.name"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 1, this->name(), output); + } + + // @@protoc_insertion_point(serialize_end:helloworld.HelloRequest) +} + +::google::protobuf::uint8* HelloRequest::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloRequest) + // optional string name = 1; + if (this->name().size() > 0) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "helloworld.HelloRequest.name"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloRequest) + return target; +} + +int HelloRequest::ByteSize() const { + int total_size = 0; + + // optional string name = 1; + if (this->name().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void HelloRequest::MergeFrom(const ::google::protobuf::Message& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const HelloRequest* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void HelloRequest::MergeFrom(const HelloRequest& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + if (from.name().size() > 0) { + + name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_); + } +} + +void HelloRequest::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void HelloRequest::CopyFrom(const HelloRequest& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool HelloRequest::IsInitialized() const { + + return true; +} + +void HelloRequest::Swap(HelloRequest* other) { + if (other == this) return; + InternalSwap(other); +} +void HelloRequest::InternalSwap(HelloRequest* other) { + name_.Swap(&other->name_); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} + +::google::protobuf::Metadata HelloRequest::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = HelloRequest_descriptor_; + metadata.reflection = HelloRequest_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int HelloReply::kMessageFieldNumber; +#endif // !_MSC_VER + +HelloReply::HelloReply() + : ::google::protobuf::Message() , _internal_metadata_(NULL) { + SharedCtor(); + // @@protoc_insertion_point(constructor:helloworld.HelloReply) +} + +void HelloReply::InitAsDefaultInstance() { + _is_default_instance_ = true; +} + +HelloReply::HelloReply(const HelloReply& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + SharedCtor(); + MergeFrom(from); + // @@protoc_insertion_point(copy_constructor:helloworld.HelloReply) +} + +void HelloReply::SharedCtor() { + _is_default_instance_ = false; + ::google::protobuf::internal::GetEmptyString(); + _cached_size_ = 0; + message_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +HelloReply::~HelloReply() { + // @@protoc_insertion_point(destructor:helloworld.HelloReply) + SharedDtor(); +} + +void HelloReply::SharedDtor() { + message_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (this != default_instance_) { + } +} + +void HelloReply::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* HelloReply::descriptor() { + protobuf_AssignDescriptorsOnce(); + return HelloReply_descriptor_; +} + +const HelloReply& HelloReply::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_helloworld_2eproto(); + return *default_instance_; +} + +HelloReply* HelloReply::default_instance_ = NULL; + +HelloReply* HelloReply::New(::google::protobuf::Arena* arena) const { + HelloReply* n = new HelloReply; + if (arena != NULL) { + arena->Own(n); + } + return n; +} + +void HelloReply::Clear() { + message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +bool HelloReply::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:helloworld.HelloReply) + for (;;) { + ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); + tag = p.first; + if (!p.second) goto handle_unusual; + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string message = 1; + case 1: { + if (tag == 10) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_message())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->message().data(), this->message().length(), + ::google::protobuf::internal::WireFormat::PARSE, + "helloworld.HelloReply.message"); + } else { + goto handle_unusual; + } + if (input->ExpectAtEnd()) goto success; + break; + } + + default: { + handle_unusual: + if (tag == 0 || + ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + goto success; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:helloworld.HelloReply) + return true; +failure: + // @@protoc_insertion_point(parse_failure:helloworld.HelloReply) + return false; +#undef DO_ +} + +void HelloReply::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:helloworld.HelloReply) + // optional string message = 1; + if (this->message().size() > 0) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->message().data(), this->message().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "helloworld.HelloReply.message"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 1, this->message(), output); + } + + // @@protoc_insertion_point(serialize_end:helloworld.HelloReply) +} + +::google::protobuf::uint8* HelloReply::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloReply) + // optional string message = 1; + if (this->message().size() > 0) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->message().data(), this->message().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "helloworld.HelloReply.message"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->message(), target); + } + + // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloReply) + return target; +} + +int HelloReply::ByteSize() const { + int total_size = 0; + + // optional string message = 1; + if (this->message().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->message()); + } + + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void HelloReply::MergeFrom(const ::google::protobuf::Message& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const HelloReply* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void HelloReply::MergeFrom(const HelloReply& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + if (from.message().size() > 0) { + + message_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.message_); + } +} + +void HelloReply::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void HelloReply::CopyFrom(const HelloReply& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool HelloReply::IsInitialized() const { + + return true; +} + +void HelloReply::Swap(HelloReply* other) { + if (other == this) return; + InternalSwap(other); +} +void HelloReply::InternalSwap(HelloReply* other) { + message_.Swap(&other->message_); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} + +::google::protobuf::Metadata HelloReply::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = HelloReply_descriptor_; + metadata.reflection = HelloReply_reflection_; + return metadata; +} + + +static const char* Greeter_method_names[] = { + "/helloworld.Greeter/SayHello", +}; + +Greeter::Stub* Greeter::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel) { + Greeter::Stub* stub = new Greeter::Stub(); + stub->set_channel(channel); + return stub; +}; + +::grpc::Status Greeter::Stub::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) { + return ::grpc::BlockingUnaryCall(channel(),::grpc::RpcMethod(Greeter_method_names[0]), context, request, response); +} + +::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq, void* tag) { + return new ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>(channel(), cq, ::grpc::RpcMethod(Greeter_method_names[0]), context, request, tag); +} + +Greeter::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : ::grpc::AsynchronousService(cq, Greeter_method_names, 1) {} + +Greeter::Service::~Service() { + delete service_; +} + +::grpc::Status Greeter::Service::SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) { + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED); +} + +void Greeter::AsyncService::RequestSayHello(::grpc::ServerContext* context, ::helloworld::HelloRequest* request, ::grpc::ServerAsyncResponseWriter< ::helloworld::HelloReply>* response, ::grpc::CompletionQueue* cq, void* tag) { + AsynchronousService::RequestAsyncUnary(0, context, request, response, cq, tag); +} + +::grpc::RpcService* Greeter::Service::service() { + if (service_ != nullptr) { + return service_; + } + service_ = new ::grpc::RpcService(); + service_->AddMethod(new ::grpc::RpcServiceMethod( + Greeter_method_names[0], + ::grpc::RpcMethod::NORMAL_RPC, + new ::grpc::RpcMethodHandler< Greeter::Service, ::helloworld::HelloRequest, ::helloworld::HelloReply>( + std::function< ::grpc::Status(Greeter::Service*, ::grpc::ServerContext*, const ::helloworld::HelloRequest*, ::helloworld::HelloReply*)>(&Greeter::Service::SayHello), this), + new ::helloworld::HelloRequest, new ::helloworld::HelloReply)); + return service_; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace helloworld + +// @@protoc_insertion_point(global_scope) diff --git a/cpp/helloworld/helloworld.pb.h b/cpp/helloworld/helloworld.pb.h new file mode 100644 index 00000000000..1eb870166af --- /dev/null +++ b/cpp/helloworld/helloworld.pb.h @@ -0,0 +1,359 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: helloworld.proto + +#ifndef PROTOBUF_helloworld_2eproto__INCLUDED +#define PROTOBUF_helloworld_2eproto__INCLUDED + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 3000000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace grpc { +class CompletionQueue; +class ChannelInterface; +class RpcService; +class ServerContext; +template class ClientAsyncResponseReader; +template class ServerAsyncResponseWriter; +} // namespace grpc +// @@protoc_insertion_point(includes) + +namespace helloworld { + +// Internal implementation detail -- do not call these. +void protobuf_AddDesc_helloworld_2eproto(); +void protobuf_AssignDesc_helloworld_2eproto(); +void protobuf_ShutdownFile_helloworld_2eproto(); + +class HelloRequest; +class HelloReply; + +// =================================================================== + +class HelloRequest : public ::google::protobuf::Message { + public: + HelloRequest(); + virtual ~HelloRequest(); + + HelloRequest(const HelloRequest& from); + + inline HelloRequest& operator=(const HelloRequest& from) { + CopyFrom(from); + return *this; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const HelloRequest& default_instance(); + + void Swap(HelloRequest* other); + + // implements Message ---------------------------------------------- + + inline HelloRequest* New() const { return New(NULL); } + + HelloRequest* New(::google::protobuf::Arena* arena) const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const HelloRequest& from); + void MergeFrom(const HelloRequest& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + void InternalSwap(HelloRequest* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // @@protoc_insertion_point(class_scope:helloworld.HelloRequest) + private: + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + bool _is_default_instance_; + ::google::protobuf::internal::ArenaStringPtr name_; + mutable int _cached_size_; + friend void protobuf_AddDesc_helloworld_2eproto(); + friend void protobuf_AssignDesc_helloworld_2eproto(); + friend void protobuf_ShutdownFile_helloworld_2eproto(); + + void InitAsDefaultInstance(); + static HelloRequest* default_instance_; +}; +// ------------------------------------------------------------------- + +class HelloReply : public ::google::protobuf::Message { + public: + HelloReply(); + virtual ~HelloReply(); + + HelloReply(const HelloReply& from); + + inline HelloReply& operator=(const HelloReply& from) { + CopyFrom(from); + return *this; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const HelloReply& default_instance(); + + void Swap(HelloReply* other); + + // implements Message ---------------------------------------------- + + inline HelloReply* New() const { return New(NULL); } + + HelloReply* New(::google::protobuf::Arena* arena) const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const HelloReply& from); + void MergeFrom(const HelloReply& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + void InternalSwap(HelloReply* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string message = 1; + inline void clear_message(); + static const int kMessageFieldNumber = 1; + inline const ::std::string& message() const; + inline void set_message(const ::std::string& value); + inline void set_message(const char* value); + inline void set_message(const char* value, size_t size); + inline ::std::string* mutable_message(); + inline ::std::string* release_message(); + inline void set_allocated_message(::std::string* message); + + // @@protoc_insertion_point(class_scope:helloworld.HelloReply) + private: + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + bool _is_default_instance_; + ::google::protobuf::internal::ArenaStringPtr message_; + mutable int _cached_size_; + friend void protobuf_AddDesc_helloworld_2eproto(); + friend void protobuf_AssignDesc_helloworld_2eproto(); + friend void protobuf_ShutdownFile_helloworld_2eproto(); + + void InitAsDefaultInstance(); + static HelloReply* default_instance_; +}; +// =================================================================== + + +// =================================================================== + +// HelloRequest + +// optional string name = 1; +inline void HelloRequest::clear_name() { + name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& HelloRequest::name() const { + // @@protoc_insertion_point(field_get:helloworld.HelloRequest.name) + return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void HelloRequest::set_name(const ::std::string& value) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:helloworld.HelloRequest.name) +} +inline void HelloRequest::set_name(const char* value) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:helloworld.HelloRequest.name) +} +inline void HelloRequest::set_name(const char* value, size_t size) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast(value), size)); + // @@protoc_insertion_point(field_set_pointer:helloworld.HelloRequest.name) +} +inline ::std::string* HelloRequest::mutable_name() { + + // @@protoc_insertion_point(field_mutable:helloworld.HelloRequest.name) + return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* HelloRequest::release_name() { + + return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void HelloRequest::set_allocated_name(::std::string* name) { + if (name != NULL) { + + } else { + + } + name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name); + // @@protoc_insertion_point(field_set_allocated:helloworld.HelloRequest.name) +} + +// ------------------------------------------------------------------- + +// HelloReply + +// optional string message = 1; +inline void HelloReply::clear_message() { + message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& HelloReply::message() const { + // @@protoc_insertion_point(field_get:helloworld.HelloReply.message) + return message_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void HelloReply::set_message(const ::std::string& value) { + + message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:helloworld.HelloReply.message) +} +inline void HelloReply::set_message(const char* value) { + + message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:helloworld.HelloReply.message) +} +inline void HelloReply::set_message(const char* value, size_t size) { + + message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast(value), size)); + // @@protoc_insertion_point(field_set_pointer:helloworld.HelloReply.message) +} +inline ::std::string* HelloReply::mutable_message() { + + // @@protoc_insertion_point(field_mutable:helloworld.HelloReply.message) + return message_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* HelloReply::release_message() { + + return message_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void HelloReply::set_allocated_message(::std::string* message) { + if (message != NULL) { + + } else { + + } + message_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), message); + // @@protoc_insertion_point(field_set_allocated:helloworld.HelloReply.message) +} + + +class Greeter final { + public: + class Stub final : public ::grpc::InternalStub { + public: + ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response); + ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq, void* tag); + }; + static Stub* NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel); + + class Service : public ::grpc::SynchronousService { + public: + Service() : service_(nullptr) {} + virtual ~Service(); + virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response); + ::grpc::RpcService* service() override final; + private: + ::grpc::RpcService* service_; + }; + class AsyncService final : public ::grpc::AsynchronousService { + public: + explicit AsyncService(::grpc::CompletionQueue* cq); + ~AsyncService() {}; + void RequestSayHello(::grpc::ServerContext* context, ::helloworld::HelloRequest* request, ::grpc::ServerAsyncResponseWriter< ::helloworld::HelloReply>* response, ::grpc::CompletionQueue* cq, void *tag); + }; +}; + +// @@protoc_insertion_point(namespace_scope) + +} // namespace helloworld + +#ifndef SWIG +namespace google { +namespace protobuf { + + +} // namespace protobuf +} // namespace google +#endif // SWIG + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_helloworld_2eproto__INCLUDED diff --git a/go/README.md b/go/README.md new file mode 100644 index 00000000000..bf5d6c8cf48 --- /dev/null +++ b/go/README.md @@ -0,0 +1,49 @@ +gRPC in 3 minutes (Go) +====================== + +PREREQUISITES +------------- + +- This requires Go 1.4 +- Requires that [GOPATH is set](https://golang.org/doc/code.html#GOPATH) +```sh +$ go help gopath +$ # ensure the PATH contains $GOPATH/bin +$ export PATH=$PATH:$GOPATH/bin +``` + +INSTALL +------- + +```sh +$ go get -u github.com/grpc-common/go/greeter_client +$ go get -u github.com/grpc-common/go/greeter_server +``` + +TRY IT! +------- + +- Run the server +```sh +$ greeter_server & +``` + +- Run the client +```sh +$ greeter_client +``` + +OPTIONAL - Rebuilding the generated code +---------------------------------------- + +1 First [install protoc](https://github.com/google/protobuf/blob/master/INSTALL.txt) + - For now, this needs to be installed from source + - This is will change once proto3 is officially released + +2 Install the protoc Go plugin. +```sh +$ go get -a github.com/golang/protobuf/protoc-gen-go +$ +$ # from this dir; invoke protoc +$ protoc -I ../protos ../protos/helloworld.proto --go_out=plugins=grpc:. +``` diff --git a/go/greeter_client/main.go b/go/greeter_client/main.go new file mode 100644 index 00000000000..3398040d7e5 --- /dev/null +++ b/go/greeter_client/main.go @@ -0,0 +1,69 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package main + +import ( + "log" + "os" + + pb "github.com/grpc-common/go/helloworld" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +const ( + address = "localhost:50051" + defaultName = "world" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial(address) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := pb.NewGreeterClient(conn) + + // Contact the server and print out its response. + name := defaultName + if len(os.Args) > 1 { + name = os.Args[1] + } + r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name}) + if err != nil { + log.Fatalf("could not greet: %v", err) + } + log.Printf("Greeting: %s", r.Message) +} diff --git a/go/greeter_server/main.go b/go/greeter_server/main.go new file mode 100644 index 00000000000..231f5c607ba --- /dev/null +++ b/go/greeter_server/main.go @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package main + +import ( + "log" + "net" + + pb "github.com/grpc-common/go/helloworld" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +const ( + port = ":50051" +) + +// server is used to implement hellowrld.GreeterServer. +type server struct{} + +// SayHello implements helloworld.GreeterServer +func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + return &pb.HelloReply{Message: "Hello " + in.Name}, nil +} + +func main() { + lis, err := net.Listen("tcp", port) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + pb.RegisterGreeterServer(s, &server{}) + s.Serve(lis) +} diff --git a/go/helloworld/helloworld.pb.go b/go/helloworld/helloworld.pb.go new file mode 100644 index 00000000000..399adda5eaf --- /dev/null +++ b/go/helloworld/helloworld.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go. +// source: helloworld.proto +// DO NOT EDIT! + +/* +Package helloworld is a generated protocol buffer package. + +It is generated from these files: + helloworld.proto + +It has these top-level messages: + HelloRequest + HelloReply +*/ +package helloworld + +import proto "github.com/golang/protobuf/proto" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal + +// The request message containing the user's name. +type HelloRequest struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` +} + +func (m *HelloRequest) Reset() { *m = HelloRequest{} } +func (m *HelloRequest) String() string { return proto.CompactTextString(m) } +func (*HelloRequest) ProtoMessage() {} + +// The response message containing the greetings +type HelloReply struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` +} + +func (m *HelloReply) Reset() { *m = HelloReply{} } +func (m *HelloReply) String() string { return proto.CompactTextString(m) } +func (*HelloReply) ProtoMessage() {} + +func init() { +} + +// Client API for Greeter service + +type GreeterClient interface { + // Sends a greeting + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type greeterClient struct { + cc *grpc.ClientConn +} + +func NewGreeterClient(cc *grpc.ClientConn) GreeterClient { + return &greeterClient{cc} +} + +func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := grpc.Invoke(ctx, "/helloworld.Greeter/sayHello", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Greeter service + +type GreeterServer interface { + // Sends a greeting + SayHello(context.Context, *HelloRequest) (*HelloReply, error) +} + +func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) { + s.RegisterService(&_Greeter_serviceDesc, srv) +} + +func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, buf []byte) (proto.Message, error) { + in := new(HelloRequest) + if err := proto.Unmarshal(buf, in); err != nil { + return nil, err + } + out, err := srv.(GreeterServer).SayHello(ctx, in) + if err != nil { + return nil, err + } + return out, nil +} + +var _Greeter_serviceDesc = grpc.ServiceDesc{ + ServiceName: "helloworld.Greeter", + HandlerType: (*GreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "sayHello", + Handler: _Greeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, +} diff --git a/pom.xml b/java/pom.xml similarity index 100% rename from pom.xml rename to java/pom.xml diff --git a/run_greetings_client.sh b/java/run_greeter_client.sh similarity index 80% rename from run_greetings_client.sh rename to java/run_greeter_client.sh index 8155589adf7..e86ab4ae891 100755 --- a/run_greetings_client.sh +++ b/java/run_greeter_client.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -TARGET='Greetings Client' -TARGET_CLASS='ex.grpc.GreetingsClient' +TARGET='Greeter Client' +TARGET_CLASS='ex.grpc.GreeterClient' TARGET_ARGS="$@" cd "$(dirname "$0")" diff --git a/run_greetings_server.sh b/java/run_greeter_server.sh similarity index 78% rename from run_greetings_server.sh rename to java/run_greeter_server.sh index 248229e129e..836abc7f48a 100755 --- a/run_greetings_server.sh +++ b/java/run_greeter_server.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -TARGET='Greetings Server' -TARGET_CLASS='ex.grpc.GreetingsServer' +TARGET='Greeter Server' +TARGET_CLASS='ex.grpc.GreeterServer' cd "$(dirname "$0")" mvn -q -nsu -am package -Dcheckstyle.skip=true -DskipTests diff --git a/src/main/java/ex/grpc/GreetingsClient.java b/java/src/main/java/ex/grpc/GreeterClient.java similarity index 79% rename from src/main/java/ex/grpc/GreetingsClient.java rename to java/src/main/java/ex/grpc/GreeterClient.java index 4ae2e7076bc..9a4615132d6 100644 --- a/src/main/java/ex/grpc/GreetingsClient.java +++ b/java/src/main/java/ex/grpc/GreeterClient.java @@ -9,17 +9,17 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.concurrent.TimeUnit; -public class GreetingsClient { +public class GreeterClient { private final Logger logger = Logger.getLogger( - GreetingsClient.class.getName()); + GreeterClient.class.getName()); private final ChannelImpl channel; - private final GreetingsGrpc.GreetingsBlockingStub blockingStub; + private final GreeterGrpc.GreeterBlockingStub blockingStub; - public GreetingsClient(String host, int port) { + public GreeterClient(String host, int port) { channel = NettyChannelBuilder.forAddress(host, port) .negotiationType(NegotiationType.PLAINTEXT) .build(); - blockingStub = GreetingsGrpc.newBlockingStub(channel); + blockingStub = GreeterGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { @@ -31,7 +31,7 @@ public class GreetingsClient { logger.fine("Will try to greet " + name + " ..."); Helloworld.HelloRequest req = Helloworld.HelloRequest.newBuilder().setName(name).build(); - Helloworld.HelloReply reply = blockingStub.hello(req); + Helloworld.HelloReply reply = blockingStub.sayHello(req); logger.info("Greeting: " + reply.getMessage()); } catch (RuntimeException e) { logger.log(Level.WARNING, "RPC failed", e); @@ -40,7 +40,7 @@ public class GreetingsClient { } public static void main(String[] args) throws Exception { - GreetingsClient client = new GreetingsClient("localhost", 50051); + GreeterClient client = new GreeterClient("localhost", 50051); try { /* Access a service running on the local machine on port 50051 */ String user = "world"; diff --git a/src/main/java/ex/grpc/GreetingsGrpc.java b/java/src/main/java/ex/grpc/GreeterGrpc.java similarity index 51% rename from src/main/java/ex/grpc/GreetingsGrpc.java rename to java/src/main/java/ex/grpc/GreeterGrpc.java index 97c2f00a1e0..080c3dfc434 100644 --- a/src/main/java/ex/grpc/GreetingsGrpc.java +++ b/java/src/main/java/ex/grpc/GreeterGrpc.java @@ -13,150 +13,150 @@ import static com.google.net.stubby.stub.ServerCalls.asyncUnaryRequestCall; import static com.google.net.stubby.stub.ServerCalls.asyncStreamingRequestCall; @javax.annotation.Generated("by gRPC proto compiler") -public class GreetingsGrpc { +public class GreeterGrpc { private static final com.google.net.stubby.stub.Method METHOD_HELLO = + ex.grpc.Helloworld.HelloReply> METHOD_SAY_HELLO = com.google.net.stubby.stub.Method.create( - com.google.net.stubby.MethodType.UNARY, "hello", + com.google.net.stubby.MethodType.UNARY, "sayHello", com.google.net.stubby.proto.ProtoUtils.marshaller(ex.grpc.Helloworld.HelloRequest.PARSER), com.google.net.stubby.proto.ProtoUtils.marshaller(ex.grpc.Helloworld.HelloReply.PARSER)); - public static GreetingsStub newStub(com.google.net.stubby.Channel channel) { - return new GreetingsStub(channel, CONFIG); + public static GreeterStub newStub(com.google.net.stubby.Channel channel) { + return new GreeterStub(channel, CONFIG); } - public static GreetingsBlockingStub newBlockingStub( + public static GreeterBlockingStub newBlockingStub( com.google.net.stubby.Channel channel) { - return new GreetingsBlockingStub(channel, CONFIG); + return new GreeterBlockingStub(channel, CONFIG); } - public static GreetingsFutureStub newFutureStub( + public static GreeterFutureStub newFutureStub( com.google.net.stubby.Channel channel) { - return new GreetingsFutureStub(channel, CONFIG); + return new GreeterFutureStub(channel, CONFIG); } - public static final GreetingsServiceDescriptor CONFIG = - new GreetingsServiceDescriptor(); + public static final GreeterServiceDescriptor CONFIG = + new GreeterServiceDescriptor(); @javax.annotation.concurrent.Immutable - public static class GreetingsServiceDescriptor extends - com.google.net.stubby.stub.AbstractServiceDescriptor { + public static class GreeterServiceDescriptor extends + com.google.net.stubby.stub.AbstractServiceDescriptor { public final com.google.net.stubby.MethodDescriptor hello; + ex.grpc.Helloworld.HelloReply> sayHello; - private GreetingsServiceDescriptor() { - hello = createMethodDescriptor( - "helloworld.Greetings", METHOD_HELLO); + private GreeterServiceDescriptor() { + sayHello = createMethodDescriptor( + "helloworld.Greeter", METHOD_SAY_HELLO); } - private GreetingsServiceDescriptor( + private GreeterServiceDescriptor( java.util.Map> methodMap) { - hello = (com.google.net.stubby.MethodDescriptor) methodMap.get( - CONFIG.hello.getName()); + CONFIG.sayHello.getName()); } @java.lang.Override - protected GreetingsServiceDescriptor build( + protected GreeterServiceDescriptor build( java.util.Map> methodMap) { - return new GreetingsServiceDescriptor(methodMap); + return new GreeterServiceDescriptor(methodMap); } @java.lang.Override public com.google.common.collect.ImmutableList> methods() { return com.google.common.collect.ImmutableList.>of( - hello); + sayHello); } } - public static interface Greetings { + public static interface Greeter { - public void hello(ex.grpc.Helloworld.HelloRequest request, + public void sayHello(ex.grpc.Helloworld.HelloRequest request, com.google.net.stubby.stub.StreamObserver responseObserver); } - public static interface GreetingsBlockingClient { + public static interface GreeterBlockingClient { - public ex.grpc.Helloworld.HelloReply hello(ex.grpc.Helloworld.HelloRequest request); + public ex.grpc.Helloworld.HelloReply sayHello(ex.grpc.Helloworld.HelloRequest request); } - public static interface GreetingsFutureClient { + public static interface GreeterFutureClient { - public com.google.common.util.concurrent.ListenableFuture hello( + public com.google.common.util.concurrent.ListenableFuture sayHello( ex.grpc.Helloworld.HelloRequest request); } - public static class GreetingsStub extends - com.google.net.stubby.stub.AbstractStub - implements Greetings { - private GreetingsStub(com.google.net.stubby.Channel channel, - GreetingsServiceDescriptor config) { + public static class GreeterStub extends + com.google.net.stubby.stub.AbstractStub + implements Greeter { + private GreeterStub(com.google.net.stubby.Channel channel, + GreeterServiceDescriptor config) { super(channel, config); } @java.lang.Override - protected GreetingsStub build(com.google.net.stubby.Channel channel, - GreetingsServiceDescriptor config) { - return new GreetingsStub(channel, config); + protected GreeterStub build(com.google.net.stubby.Channel channel, + GreeterServiceDescriptor config) { + return new GreeterStub(channel, config); } @java.lang.Override - public void hello(ex.grpc.Helloworld.HelloRequest request, + public void sayHello(ex.grpc.Helloworld.HelloRequest request, com.google.net.stubby.stub.StreamObserver responseObserver) { asyncUnaryCall( - channel.newCall(config.hello), request, responseObserver); + channel.newCall(config.sayHello), request, responseObserver); } } - public static class GreetingsBlockingStub extends - com.google.net.stubby.stub.AbstractStub - implements GreetingsBlockingClient { - private GreetingsBlockingStub(com.google.net.stubby.Channel channel, - GreetingsServiceDescriptor config) { + public static class GreeterBlockingStub extends + com.google.net.stubby.stub.AbstractStub + implements GreeterBlockingClient { + private GreeterBlockingStub(com.google.net.stubby.Channel channel, + GreeterServiceDescriptor config) { super(channel, config); } @java.lang.Override - protected GreetingsBlockingStub build(com.google.net.stubby.Channel channel, - GreetingsServiceDescriptor config) { - return new GreetingsBlockingStub(channel, config); + protected GreeterBlockingStub build(com.google.net.stubby.Channel channel, + GreeterServiceDescriptor config) { + return new GreeterBlockingStub(channel, config); } @java.lang.Override - public ex.grpc.Helloworld.HelloReply hello(ex.grpc.Helloworld.HelloRequest request) { + public ex.grpc.Helloworld.HelloReply sayHello(ex.grpc.Helloworld.HelloRequest request) { return blockingUnaryCall( - channel.newCall(config.hello), request); + channel.newCall(config.sayHello), request); } } - public static class GreetingsFutureStub extends - com.google.net.stubby.stub.AbstractStub - implements GreetingsFutureClient { - private GreetingsFutureStub(com.google.net.stubby.Channel channel, - GreetingsServiceDescriptor config) { + public static class GreeterFutureStub extends + com.google.net.stubby.stub.AbstractStub + implements GreeterFutureClient { + private GreeterFutureStub(com.google.net.stubby.Channel channel, + GreeterServiceDescriptor config) { super(channel, config); } @java.lang.Override - protected GreetingsFutureStub build(com.google.net.stubby.Channel channel, - GreetingsServiceDescriptor config) { - return new GreetingsFutureStub(channel, config); + protected GreeterFutureStub build(com.google.net.stubby.Channel channel, + GreeterServiceDescriptor config) { + return new GreeterFutureStub(channel, config); } @java.lang.Override - public com.google.common.util.concurrent.ListenableFuture hello( + public com.google.common.util.concurrent.ListenableFuture sayHello( ex.grpc.Helloworld.HelloRequest request) { return unaryFutureCall( - channel.newCall(config.hello), request); + channel.newCall(config.sayHello), request); } } public static com.google.net.stubby.ServerServiceDefinition bindService( - final Greetings serviceImpl) { - return com.google.net.stubby.ServerServiceDefinition.builder("helloworld.Greetings") + final Greeter serviceImpl) { + return com.google.net.stubby.ServerServiceDefinition.builder("helloworld.Greeter") .addMethod(createMethodDefinition( - METHOD_HELLO, + METHOD_SAY_HELLO, asyncUnaryRequestCall( new com.google.net.stubby.stub.ServerCalls.UnaryRequestMethod< ex.grpc.Helloworld.HelloRequest, @@ -165,7 +165,7 @@ public class GreetingsGrpc { public void invoke( ex.grpc.Helloworld.HelloRequest request, com.google.net.stubby.stub.StreamObserver responseObserver) { - serviceImpl.hello(request, responseObserver); + serviceImpl.sayHello(request, responseObserver); } }))).build(); } diff --git a/src/main/java/ex/grpc/GreetingsImpl.java b/java/src/main/java/ex/grpc/GreeterImpl.java similarity index 75% rename from src/main/java/ex/grpc/GreetingsImpl.java rename to java/src/main/java/ex/grpc/GreeterImpl.java index 005489acaa2..825ba8631ec 100644 --- a/src/main/java/ex/grpc/GreetingsImpl.java +++ b/java/src/main/java/ex/grpc/GreeterImpl.java @@ -2,10 +2,10 @@ package ex.grpc; import com.google.net.stubby.stub.StreamObserver; -public class GreetingsImpl implements GreetingsGrpc.Greetings { +public class GreeterImpl implements GreeterGrpc.Greeter { @Override - public void hello(Helloworld.HelloRequest req, + public void sayHello(Helloworld.HelloRequest req, StreamObserver responseObserver) { Helloworld.HelloReply reply = Helloworld.HelloReply.newBuilder().setMessage( "Hello " + req.getName()).build(); diff --git a/src/main/java/ex/grpc/GreetingsServer.java b/java/src/main/java/ex/grpc/GreeterServer.java similarity index 83% rename from src/main/java/ex/grpc/GreetingsServer.java rename to java/src/main/java/ex/grpc/GreeterServer.java index 834ae985a44..bb05680b0a6 100644 --- a/src/main/java/ex/grpc/GreetingsServer.java +++ b/java/src/main/java/ex/grpc/GreeterServer.java @@ -7,16 +7,16 @@ import com.google.net.stubby.transport.netty.NettyServerBuilder; import java.util.concurrent.TimeUnit; /** - * Server that manages startup/shutdown of a {@code Greetings} server. + * Server that manages startup/shutdown of a {@code Greeter} server. */ -public class GreetingsServer { +public class GreeterServer { /* The port on which the server should run */ private int port = 50051; private ServerImpl server; private void start() throws Exception { server = NettyServerBuilder.forPort(port) - .addService(GreetingsGrpc.bindService(new GreetingsImpl())) + .addService(GreeterGrpc.bindService(new GreeterImpl())) .build(); server.startAsync(); server.awaitRunning(5, TimeUnit.SECONDS); @@ -33,7 +33,7 @@ public class GreetingsServer { * Main launches the server from the command line. */ public static void main(String[] args) throws Exception { - final GreetingsServer server = new GreetingsServer(); + final GreeterServer server = new GreeterServer(); Runtime.getRuntime().addShutdownHook(new Thread() { @Override diff --git a/src/main/java/ex/grpc/Helloworld.java b/java/src/main/java/ex/grpc/Helloworld.java similarity index 98% rename from src/main/java/ex/grpc/Helloworld.java rename to java/src/main/java/ex/grpc/Helloworld.java index f72040fa2bf..b25a63fca32 100644 --- a/src/main/java/ex/grpc/Helloworld.java +++ b/java/src/main/java/ex/grpc/Helloworld.java @@ -1,5 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: src/main/proto/helloworld.proto +// source: helloworld.proto package ex.grpc; @@ -915,11 +915,11 @@ public final class Helloworld { descriptor; static { java.lang.String[] descriptorData = { - "\n\037src/main/proto/helloworld.proto\022\nhello" + - "world\"\034\n\014HelloRequest\022\014\n\004name\030\001 \001(\t\"\035\n\nH" + - "elloReply\022\017\n\007message\030\001 \001(\t2H\n\tGreetings\022" + - ";\n\005hello\022\030.helloworld.HelloRequest\032\026.hel" + - "loworld.HelloReply\"\000B\t\n\007ex.grpcb\006proto3" + "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" + + "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" + + "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010sayHello\022\030.hel" + + "loworld.HelloRequest\032\026.helloworld.HelloR" + + "eply\"\000B\t\n\007ex.grpcb\006proto3" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { diff --git a/node/.gitignore b/node/.gitignore new file mode 100644 index 00000000000..3d06f5db7b3 --- /dev/null +++ b/node/.gitignore @@ -0,0 +1,3 @@ +*~ +node_modules +npm-debug.log \ No newline at end of file diff --git a/node/README.md b/node/README.md new file mode 100644 index 00000000000..f9df3b0a81d --- /dev/null +++ b/node/README.md @@ -0,0 +1,38 @@ +gRPC in 3 minutes (Node.js) +=========================== + +PREREQUISITES +------------- + +This requires Node 10.x or greater. + +INSTALL +------- + + - Clone this repository + - Follow the instructions in [INSTALL](https://github.com/grpc/grpc/blob/master/INSTALL) to install the gRPC C core. + - Run `npm install` to install dependencies + - If `grpc` is not found, clone the [gRPC](https://github.com/grpc/grpc) repository and run `npm install path/to/grpc/src/node`. + +Try it! +------- + + - Run the server + + ```sh + $ # from this directory + $ nodejs ./greeter_server.js & + ``` + + - Run the client + + ```sh + $ # from this directory + $ nodejs ./greeter_client.js + ``` + +Note +---- + +This directory has a copy of `helloworld.proto` because it currently depends on +some Protocol Buffer 2.0 syntax that is deprecated in Protocol Buffer 3.0. diff --git a/node/greeter_client.js b/node/greeter_client.js new file mode 100644 index 00000000000..ab7050ab213 --- /dev/null +++ b/node/greeter_client.js @@ -0,0 +1,52 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var PROTO_PATH = __dirname + '/helloworld.proto'; + +var grpc = require('grpc'); +var hello_proto = grpc.load(PROTO_PATH).helloworld; + +function main() { + var client = new hello_proto.Greeter('localhost:50051'); + var user; + if (process.argv.length >= 3) { + user = process.argv[2]; + } else { + user = 'world'; + } + client.sayHello({name: user}, function(err, response) { + console.log('Greeting:', response.message); + }); +} + +main(); diff --git a/node/greeter_server.js b/node/greeter_server.js new file mode 100644 index 00000000000..2fb95f0f90e --- /dev/null +++ b/node/greeter_server.js @@ -0,0 +1,63 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var PROTO_PATH = __dirname + '/helloworld.proto'; + +var grpc = require('grpc'); +var hello_proto = grpc.load(PROTO_PATH).helloworld; + +var Server = grpc.buildServer([hello_proto.Greeter.service]); + +/** + * Implements the SayHello RPC method. + */ +function sayHello(call, callback) { + callback(null, {message: 'Hello ' + call.request.name}); +} + +/** + * Starts an RPC server that receives requests for the Greeter service at the + * sample server port + */ +function main() { + var server = new Server({ + "helloworld.Greeter": { + sayHello: sayHello + } + }); + + server.bind('0.0.0.0:50051'); + server.listen(); +} + +main(); diff --git a/node/helloworld.proto b/node/helloworld.proto new file mode 100644 index 00000000000..a52c947f895 --- /dev/null +++ b/node/helloworld.proto @@ -0,0 +1,50 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + optional string name = 1; +} + +// The response message containing the greetings +message HelloReply { + optional string message = 1; +} diff --git a/node/package.json b/node/package.json new file mode 100644 index 00000000000..a669dec8f18 --- /dev/null +++ b/node/package.json @@ -0,0 +1,10 @@ +{ + "name": "grpc-greeter", + "version": "0.1.0", + "dependencies": { + "async": "^0.9.0", + "grpc": "~0.2.0", + "minimist": "^1.1.0", + "underscore": "^1.8.2" + } +} diff --git a/node/route_guide/route_guide.proto b/node/route_guide/route_guide.proto new file mode 100644 index 00000000000..442112823e5 --- /dev/null +++ b/node/route_guide/route_guide.proto @@ -0,0 +1,120 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "io.grpc.examples"; + +package examples; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + optional int32 latitude = 1; + optional int32 longitude = 2; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + optional Point lo = 1; + + // The other corner of the rectangle. + optional Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + optional string name = 1; + + // The point where the feature is detected. + optional Point location = 2; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + optional Point location = 1; + + // The message to be sent. + optional string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + optional int32 point_count = 1; + + // The number of known features passed while traversing the route. + optional int32 feature_count = 2; + + // The distance covered in metres. + optional int32 distance = 3; + + // The duration of the traversal in seconds. + optional int32 elapsed_time = 4; +} diff --git a/node/route_guide/route_guide_client.js b/node/route_guide/route_guide_client.js new file mode 100644 index 00000000000..60c47a429d6 --- /dev/null +++ b/node/route_guide/route_guide_client.js @@ -0,0 +1,231 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var async = require('async'); +var fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('underscore'); +var grpc = require('grpc'); +var examples = grpc.load(__dirname + '/route_guide.proto').examples; +var client = new examples.RouteGuide('localhost:50051'); + +var COORD_FACTOR = 1e7; + +/** + * Run the getFeature demo. Calls getFeature with a point known to have a + * feature and a point known not to have a feature. + * @param {function} callback Called when this demo is complete + */ +function runGetFeature(callback) { + var next = _.after(2, callback); + function featureCallback(error, feature) { + if (error) { + callback(error); + } + if (feature.name === '') { + console.log('Found no feature at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + } else { + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + } + next(); + } + var point1 = { + latitude: 409146138, + longitude: -746188906 + }; + var point2 = { + latitude: 0, + longitude: 0 + }; + client.getFeature(point1, featureCallback); + client.getFeature(point2, featureCallback); +} + +/** + * Run the listFeatures demo. Calls listFeatures with a rectangle containing all + * of the features in the pre-generated database. Prints each response as it + * comes in. + * @param {function} callback Called when this demo is complete + */ +function runListFeatures(callback) { + var rectangle = { + lo: { + latitude: 400000000, + longitude: -750000000 + }, + hi: { + latitude: 420000000, + longitude: -730000000 + } + }; + console.log('Looking for features between 40, -75 and 42, -73'); + var call = client.listFeatures(rectangle); + call.on('data', function(feature) { + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + }); + call.on('end', callback); +} + +/** + * Run the recordRoute demo. Sends several randomly chosen points from the + * pre-generated feature database with a variable delay in between. Prints the + * statistics when they are sent from the server. + * @param {function} callback Called when this demo is complete + */ +function runRecordRoute(callback) { + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) callback(err); + var feature_list = JSON.parse(data); + + var num_points = 10; + var call = client.recordRoute(function(error, stats) { + if (error) { + callback(error); + } + console.log('Finished trip with', stats.point_count, 'points'); + console.log('Passed', stats.feature_count, 'features'); + console.log('Travelled', stats.distance, 'meters'); + console.log('It took', stats.elapsed_time, 'seconds'); + callback(); + }); + /** + * Constructs a function that asynchronously sends the given point and then + * delays sending its callback + * @param {number} lat The latitude to send + * @param {number} lng The longitude to send + * @return {function(function)} The function that sends the point + */ + function pointSender(lat, lng) { + /** + * Sends the point, then calls the callback after a delay + * @param {function} callback Called when complete + */ + return function(callback) { + console.log('Visiting point ' + lat/COORD_FACTOR + ', ' + + lng/COORD_FACTOR); + call.write({ + latitude: lat, + longitude: lng + }); + _.delay(callback, _.random(500, 1500)); + }; + } + var point_senders = []; + for (var i = 0; i < num_points; i++) { + var rand_point = feature_list[_.random(0, feature_list.length - 1)]; + point_senders[i] = pointSender(rand_point.location.latitude, + rand_point.location.longitude); + } + async.series(point_senders, function() { + call.end(); + }); + }); +} + +/** + * Run the routeChat demo. Send some chat messages, and print any chat messages + * that are sent from the server. + * @param {function} callback Called when the demo is complete + */ +function runRouteChat(callback) { + var call = client.routeChat(); + call.on('data', function(note) { + console.log('Got message "' + note.message + '" at ' + + note.location.latitude + ', ' + note.location.longitude); + }); + + call.on('end', callback); + + var notes = [{ + location: { + latitude: 0, + longitude: 0 + }, + message: 'First message' + }, { + location: { + latitude: 0, + longitude: 1 + }, + message: 'Second message' + }, { + location: { + latitude: 1, + longitude: 0 + }, + message: 'Third message' + }, { + location: { + latitude: 0, + longitude: 0 + }, + message: 'Fourth message' + }]; + for (var i = 0; i < notes.length; i++) { + var note = notes[i]; + console.log('Sending message "' + note.message + '" at ' + + note.location.latitude + ', ' + note.location.longitude); + call.write(note); + } + call.end(); +} + +/** + * Run all of the demos in order + */ +function main() { + async.series([ + runGetFeature, + runListFeatures, + runRecordRoute, + runRouteChat + ]); +} + +if (require.main === module) { + main(); +} + +exports.runGetFeature = runGetFeature; + +exports.runListFeatures = runListFeatures; + +exports.runRecordRoute = runRecordRoute; + +exports.runRouteChat = runRouteChat; diff --git a/node/route_guide/route_guide_db.json b/node/route_guide/route_guide_db.json new file mode 100644 index 00000000000..9d6a980ab7d --- /dev/null +++ b/node/route_guide/route_guide_db.json @@ -0,0 +1,601 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 415736605, + "longitude": -742847522 + }, + "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" +}, { + "location": { + "latitude": 413843930, + "longitude": -740501726 + }, + "name": "162 Merrill Road, Highland Mills, NY 10930, USA" +}, { + "location": { + "latitude": 410873075, + "longitude": -744459023 + }, + "name": "Clinton Road, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 412346009, + "longitude": -744026814 + }, + "name": "16 Old Brook Lane, Warwick, NY 10990, USA" +}, { + "location": { + "latitude": 402948455, + "longitude": -747903913 + }, + "name": "3 Drake Lane, Pennington, NJ 08534, USA" +}, { + "location": { + "latitude": 406337092, + "longitude": -740122226 + }, + "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" +}, { + "location": { + "latitude": 406421967, + "longitude": -747727624 + }, + "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" +}, { + "location": { + "latitude": 416318082, + "longitude": -749677716 + }, + "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" +}, { + "location": { + "latitude": 415301720, + "longitude": -748416257 + }, + "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" +}, { + "location": { + "latitude": 402647019, + "longitude": -747071791 + }, + "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" +}, { + "location": { + "latitude": 412567807, + "longitude": -741058078 + }, + "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" +}, { + "location": { + "latitude": 416855156, + "longitude": -744420597 + }, + "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" +}, { + "location": { + "latitude": 404663628, + "longitude": -744820157 + }, + "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" +}, { + "location": { + "latitude": 407113723, + "longitude": -749746483 + }, + "name": "" +}, { + "location": { + "latitude": 402133926, + "longitude": -743613249 + }, + "name": "" +}, { + "location": { + "latitude": 400273442, + "longitude": -741220915 + }, + "name": "" +}, { + "location": { + "latitude": 411236786, + "longitude": -744070769 + }, + "name": "" +}, { + "location": { + "latitude": 411633782, + "longitude": -746784970 + }, + "name": "211-225 Plains Road, Augusta, NJ 07822, USA" +}, { + "location": { + "latitude": 415830701, + "longitude": -742952812 + }, + "name": "" +}, { + "location": { + "latitude": 413447164, + "longitude": -748712898 + }, + "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" +}, { + "location": { + "latitude": 405047245, + "longitude": -749800722 + }, + "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" +}, { + "location": { + "latitude": 418858923, + "longitude": -746156790 + }, + "name": "" +}, { + "location": { + "latitude": 417951888, + "longitude": -748484944 + }, + "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" +}, { + "location": { + "latitude": 407033786, + "longitude": -743977337 + }, + "name": "26 East 3rd Street, New Providence, NJ 07974, USA" +}, { + "location": { + "latitude": 417548014, + "longitude": -740075041 + }, + "name": "" +}, { + "location": { + "latitude": 410395868, + "longitude": -744972325 + }, + "name": "" +}, { + "location": { + "latitude": 404615353, + "longitude": -745129803 + }, + "name": "" +}, { + "location": { + "latitude": 406589790, + "longitude": -743560121 + }, + "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" +}, { + "location": { + "latitude": 414653148, + "longitude": -740477477 + }, + "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" +}, { + "location": { + "latitude": 405957808, + "longitude": -743255336 + }, + "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" +}, { + "location": { + "latitude": 411733589, + "longitude": -741648093 + }, + "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" +}, { + "location": { + "latitude": 412676291, + "longitude": -742606606 + }, + "name": "1270 Lakes Road, Monroe, NY 10950, USA" +}, { + "location": { + "latitude": 409224445, + "longitude": -748286738 + }, + "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" +}, { + "location": { + "latitude": 406523420, + "longitude": -742135517 + }, + "name": "652 Garden Street, Elizabeth, NJ 07202, USA" +}, { + "location": { + "latitude": 401827388, + "longitude": -740294537 + }, + "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" +}, { + "location": { + "latitude": 410564152, + "longitude": -743685054 + }, + "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 408472324, + "longitude": -740726046 + }, + "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" +}, { + "location": { + "latitude": 412452168, + "longitude": -740214052 + }, + "name": "5 White Oak Lane, Stony Point, NY 10980, USA" +}, { + "location": { + "latitude": 409146138, + "longitude": -746188906 + }, + "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" +}, { + "location": { + "latitude": 404701380, + "longitude": -744781745 + }, + "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 409642566, + "longitude": -746017679 + }, + "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" +}, { + "location": { + "latitude": 408031728, + "longitude": -748645385 + }, + "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" +}, { + "location": { + "latitude": 413700272, + "longitude": -742135189 + }, + "name": "367 Prospect Road, Chester, NY 10918, USA" +}, { + "location": { + "latitude": 404310607, + "longitude": -740282632 + }, + "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" +}, { + "location": { + "latitude": 409319800, + "longitude": -746201391 + }, + "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" +}, { + "location": { + "latitude": 406685311, + "longitude": -742108603 + }, + "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" +}, { + "location": { + "latitude": 419018117, + "longitude": -749142781 + }, + "name": "43 Dreher Road, Roscoe, NY 12776, USA" +}, { + "location": { + "latitude": 412856162, + "longitude": -745148837 + }, + "name": "Swan Street, Pine Island, NY 10969, USA" +}, { + "location": { + "latitude": 416560744, + "longitude": -746721964 + }, + "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" +}, { + "location": { + "latitude": 405314270, + "longitude": -749836354 + }, + "name": "" +}, { + "location": { + "latitude": 414219548, + "longitude": -743327440 + }, + "name": "" +}, { + "location": { + "latitude": 415534177, + "longitude": -742900616 + }, + "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" +}, { + "location": { + "latitude": 406898530, + "longitude": -749127080 + }, + "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" +}, { + "location": { + "latitude": 407586880, + "longitude": -741670168 + }, + "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" +}, { + "location": { + "latitude": 400106455, + "longitude": -742870190 + }, + "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" +}, { + "location": { + "latitude": 400066188, + "longitude": -746793294 + }, + "name": "" +}, { + "location": { + "latitude": 418803880, + "longitude": -744102673 + }, + "name": "40 Mountain Road, Napanoch, NY 12458, USA" +}, { + "location": { + "latitude": 414204288, + "longitude": -747895140 + }, + "name": "" +}, { + "location": { + "latitude": 414777405, + "longitude": -740615601 + }, + "name": "" +}, { + "location": { + "latitude": 415464475, + "longitude": -747175374 + }, + "name": "48 North Road, Forestburgh, NY 12777, USA" +}, { + "location": { + "latitude": 404062378, + "longitude": -746376177 + }, + "name": "" +}, { + "location": { + "latitude": 405688272, + "longitude": -749285130 + }, + "name": "" +}, { + "location": { + "latitude": 400342070, + "longitude": -748788996 + }, + "name": "" +}, { + "location": { + "latitude": 401809022, + "longitude": -744157964 + }, + "name": "" +}, { + "location": { + "latitude": 404226644, + "longitude": -740517141 + }, + "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" +}, { + "location": { + "latitude": 410322033, + "longitude": -747871659 + }, + "name": "" +}, { + "location": { + "latitude": 407100674, + "longitude": -747742727 + }, + "name": "" +}, { + "location": { + "latitude": 418811433, + "longitude": -741718005 + }, + "name": "213 Bush Road, Stone Ridge, NY 12484, USA" +}, { + "location": { + "latitude": 415034302, + "longitude": -743850945 + }, + "name": "" +}, { + "location": { + "latitude": 411349992, + "longitude": -743694161 + }, + "name": "" +}, { + "location": { + "latitude": 404839914, + "longitude": -744759616 + }, + "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 414638017, + "longitude": -745957854 + }, + "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" +}, { + "location": { + "latitude": 412127800, + "longitude": -740173578 + }, + "name": "" +}, { + "location": { + "latitude": 401263460, + "longitude": -747964303 + }, + "name": "" +}, { + "location": { + "latitude": 412843391, + "longitude": -749086026 + }, + "name": "" +}, { + "location": { + "latitude": 418512773, + "longitude": -743067823 + }, + "name": "" +}, { + "location": { + "latitude": 404318328, + "longitude": -740835638 + }, + "name": "42-102 Main Street, Belford, NJ 07718, USA" +}, { + "location": { + "latitude": 419020746, + "longitude": -741172328 + }, + "name": "" +}, { + "location": { + "latitude": 404080723, + "longitude": -746119569 + }, + "name": "" +}, { + "location": { + "latitude": 401012643, + "longitude": -744035134 + }, + "name": "" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] diff --git a/node/route_guide/route_guide_server.js b/node/route_guide/route_guide_server.js new file mode 100644 index 00000000000..5dd84126543 --- /dev/null +++ b/node/route_guide/route_guide_server.js @@ -0,0 +1,249 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('underscore'); +var grpc = require('grpc'); +var examples = grpc.load(__dirname + '/route_guide.proto').examples; + +var Server = grpc.buildServer([examples.RouteGuide.service]); + +var COORD_FACTOR = 1e7; + +/** + * For simplicity, a point is a record type that looks like + * {latitude: number, longitude: number}, and a feature is a record type that + * looks like {name: string, location: point}. feature objects with name==='' + * are points with no feature. + */ + +/** + * List of feature objects at points that have been requested so far. + */ +var feature_list = []; + +/** + * Get a feature object at the given point, or creates one if it does not exist. + * @param {point} point The point to check + * @return {feature} The feature object at the point. Note that an empty name + * indicates no feature + */ +function checkFeature(point) { + var feature; + // Check if there is already a feature object for the given point + for (var i = 0; i < feature_list.length; i++) { + feature = feature_list[i]; + if (feature.location.latitude === point.latitude && + feature.location.longitude === point.longitude) { + return feature; + } + } + var name = ''; + feature = { + name: name, + location: point + }; + return feature; +} + +/** + * getFeature request handler. Gets a request with a point, and responds with a + * feature object indicating whether there is a feature at that point. + * @param {EventEmitter} call Call object for the handler to process + * @param {function(Error, feature)} callback Response callback + */ +function getFeature(call, callback) { + callback(null, checkFeature(call.request)); +} + +/** + * listFeatures request handler. Gets a request with two points, and responds + * with a stream of all features in the bounding box defined by those points. + * @param {Writable} call Writable stream for responses with an additional + * request property for the request value. + */ +function listFeatures(call) { + var lo = call.request.lo; + var hi = call.request.hi; + var left = _.min([lo.longitude, hi.longitude]); + var right = _.max([lo.longitude, hi.longitude]); + var top = _.max([lo.latitude, hi.latitude]); + var bottom = _.min([lo.latitude, hi.latitude]); + // For each feature, check if it is in the given bounding box + _.each(feature_list, function(feature) { + if (feature.name === '') { + return; + } + if (feature.location.longitude >= left && + feature.location.longitude <= right && + feature.location.latitude >= bottom && + feature.location.latitude <= top) { + call.write(feature); + } + }); + call.end(); +} + +/** + * Calculate the distance between two points using the "haversine" formula. + * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. + * @param start The starting point + * @param end The end point + * @return The distance between the points in meters + */ +function getDistance(start, end) { + function toRadians(num) { + return num * Math.PI / 180; + } + var lat1 = start.latitude / COORD_FACTOR; + var lat2 = end.latitude / COORD_FACTOR; + var lon1 = start.longitude / COORD_FACTOR; + var lon2 = end.longitude / COORD_FACTOR; + var R = 6371000; // metres + var φ1 = toRadians(lat1); + var φ2 = toRadians(lat2); + var Δφ = toRadians(lat2-lat1); + var Δλ = toRadians(lon2-lon1); + + var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + + Math.cos(φ1) * Math.cos(φ2) * + Math.sin(Δλ/2) * Math.sin(Δλ/2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + + return R * c; +} + +/** + * recordRoute handler. Gets a stream of points, and responds with statistics + * about the "trip": number of points, number of known features visited, total + * distance traveled, and total time spent. + * @param {Readable} call The request point stream. + * @param {function(Error, routeSummary)} callback The callback to pass the + * response to + */ +function recordRoute(call, callback) { + var point_count = 0; + var feature_count = 0; + var distance = 0; + var previous = null; + // Start a timer + var start_time = process.hrtime(); + call.on('data', function(point) { + point_count += 1; + if (checkFeature(point).name !== '') { + feature_count += 1; + } + /* For each point after the first, add the incremental distance from the + * previous point to the total distance value */ + if (previous != null) { + distance += getDistance(previous, point); + } + previous = point; + }); + call.on('end', function() { + callback(null, { + point_count: point_count, + feature_count: feature_count, + // Cast the distance to an integer + distance: distance|0, + // End the timer + elapsed_time: process.hrtime(start_time)[0] + }); + }); +} + +var route_notes = {}; + +/** + * Turn the point into a dictionary key. + * @param {point} point The point to use + * @return {string} The key for an object + */ +function pointKey(point) { + return point.latitude + ' ' + point.longitude; +} + +/** + * routeChat handler. Receives a stream of message/location pairs, and responds + * with a stream of all previous messages at each of those locations. + * @param {Duplex} call The stream for incoming and outgoing messages + */ +function routeChat(call) { + call.on('data', function(note) { + var key = pointKey(note.location); + /* For each note sent, respond with all previous notes that correspond to + * the same point */ + if (route_notes.hasOwnProperty(key)) { + _.each(route_notes[key], function(note) { + call.write(note); + }); + } else { + route_notes[key] = []; + } + // Then add the new note to the list + route_notes[key].push(JSON.parse(JSON.stringify(note))); + }); + call.on('end', function() { + call.end(); + }); +} + +/** + * Get a new server with the handler functions in this file bound to the methods + * it serves. + * @return {Server} The new server object + */ +function getServer() { + return new Server({ + 'examples.RouteGuide' : { + getFeature: getFeature, + listFeatures: listFeatures, + recordRoute: recordRoute, + routeChat: routeChat + } + }); +} + +if (require.main === module) { + // If this is run as a script, start a server on an unused port + var routeServer = getServer(); + routeServer.bind('0.0.0.0:50051'); + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) throw err; + feature_list = JSON.parse(data); + routeServer.listen(); + }); +} + +exports.getServer = getServer; diff --git a/protos/README.md b/protos/README.md new file mode 100644 index 00000000000..48df7c8943e --- /dev/null +++ b/protos/README.md @@ -0,0 +1,8 @@ +# Example protos + +## Contents + +- [helloworld.proto] + - The simple example used in the overview. +- [route_guide.proto] + - An example service described in detail in the tutorial. diff --git a/protos/hellostreamingworld.proto b/protos/hellostreamingworld.proto new file mode 100644 index 00000000000..ec8405c78b3 --- /dev/null +++ b/protos/hellostreamingworld.proto @@ -0,0 +1,53 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package hellostreamingworld; + +// The greeting service definition. +service MultiGreeter { + // Sends multiple greetings + rpc sayHello (HelloRequest) returns (stream HelloReply) {} +} + +// The request message containing the user's name and how many greetings +// they want. +message HelloRequest { + string name = 1; + string num_greetings = 2; +} + +// A response message containing a greeting +message HelloReply { + string message = 1; +} + diff --git a/protos/helloworld.proto b/protos/helloworld.proto new file mode 100644 index 00000000000..f9abd3d87f7 --- /dev/null +++ b/protos/helloworld.proto @@ -0,0 +1,50 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/protos/route_guide.proto b/protos/route_guide.proto new file mode 100644 index 00000000000..7cda80efad8 --- /dev/null +++ b/protos/route_guide.proto @@ -0,0 +1,120 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package examples; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + Point lo = 1; + + // The other corner of the rectangle. + Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + string name = 1; + + // The point where the feature is detected. + Point location = 2; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + Point location = 1; + + // The message to be sent. + string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + int32 point_count = 1; + + // The number of known features passed while traversing the route. + int32 feature_count = 2; + + // The distance covered in metres. + int32 distance = 3; + + // The duration of the traversal in seconds. + int32 elapsed_time = 4; +} diff --git a/ruby/.gitignore b/ruby/.gitignore new file mode 100644 index 00000000000..62fcb4fa943 --- /dev/null +++ b/ruby/.gitignore @@ -0,0 +1,15 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +*.bundle +*.so +*.o +*.a +mkmf.log +vendor diff --git a/ruby/Gemfile b/ruby/Gemfile new file mode 100644 index 00000000000..2d76038e09d --- /dev/null +++ b/ruby/Gemfile @@ -0,0 +1,15 @@ +# -*- ruby -*- +# encoding: utf-8 + +source 'https://rubygems.org/' + +# Update this to reflect the local installation of gRPC. +gem 'grpc', path: '/usr/local/google/repos/grpc/src/ruby' + +# TODO: fix this if/when the gRPC repo structure changes. +# +# At the moment it's not possible to use grpc Ruby via git/github reference +# +# git 'git@github.com:grpc/grpc.git' do +# gem 'grpc' +# end diff --git a/ruby/README.md b/ruby/README.md new file mode 100644 index 00000000000..1fc19a4f246 --- /dev/null +++ b/ruby/README.md @@ -0,0 +1,35 @@ +gRPC in 3 minutes (Ruby) +======================== + +PREREQUISITES +------------- + +This requires Ruby 2.1, as the gRPC API surface uses keyword args. + +INSTALL +------- + +- Clone this repository. +- Follow the instructions in [INSTALL](https://github.com/grpc/grpc/blob/master/INSTALL) to install the gRPC C core. +- *Temporary* Install the full gRPC distribution from source on your local machine and update path: in [Gemfile] to refer src/ruby within it. + - this is necessary until the gRPC ruby gem is published +- Use bundler to install +```sh +$ # from this directory +$ gem install bundler && bundle install +``` + +Try it! +------- + +- Run the server +```sh +$ # from this directory +$ bundle exec ./greeter_server.rb & +``` + +- Run the client +```sh +$ # from this directory +$ bundle exec ./greeter_client.rb +``` diff --git a/ruby/greeter.gemspec b/ruby/greeter.gemspec new file mode 100644 index 00000000000..795c84c0f5f --- /dev/null +++ b/ruby/greeter.gemspec @@ -0,0 +1,23 @@ +# -*- ruby -*- +# encoding: utf-8 + +Gem::Specification.new do |s| + s.name = 'grpc-greeter' + s.version = '0.1.0' + s.authors = ['gRPC Authors'] + s.email = 'temiola@google.com' + s.homepage = 'https://github.com/grpc/grpc-common' + s.summary = 'gRPC Ruby overview sample' + s.description = 'Simple demo of using gRPC from Ruby' + + s.files = `git ls-files -- ruby/*`.split("\n") + s.executables = `git ls-files -- ruby/greeter*.rb`.split("\n").map do |f| + File.basename(f) + end + s.require_paths = ['lib'] + s.platform = Gem::Platform::RUBY + + s.add_dependency 'grpc', '~> 0.0.1' + + s.add_development_dependency 'bundler', '~> 1.7' +end diff --git a/ruby/greeter_client.rb b/ruby/greeter_client.rb new file mode 100755 index 00000000000..e6cb4bad33e --- /dev/null +++ b/ruby/greeter_client.rb @@ -0,0 +1,50 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Sample app that connects to a Greeter service. +# +# Usage: $ path/to/greeter_client.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(this_dir, 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'helloworld_services' + +def main + stub = Helloworld::Greeter::Stub.new('localhost:50051') + user = ARGV.size > 0 ? ARGV[0] : 'world' + message = stub.say_hello(Helloworld::HelloRequest.new(name: user)).message + p "Greeting: #{message}" +end + +main diff --git a/ruby/greeter_server.rb b/ruby/greeter_server.rb new file mode 100755 index 00000000000..d4f9cf7d0f8 --- /dev/null +++ b/ruby/greeter_server.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Sample gRPC server that implements the Greeter::Helloworld service. +# +# Usage: $ path/to/greeter_server.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(this_dir, 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'helloworld_services' + +# GreeterServer is simple server that implements the Helloworld Greeter server. +class GreeterServer < Helloworld::Greeter::Service + # say_hello implements the SayHello rpc method. + def say_hello(hello_req, _unused_call) + Helloworld::HelloReply.new(message: "Hello #{hello_req.name}") + end +end + +# main starts an RpcServer that receives requests to GreeterServer at the sample +# server port. +def main + s = GRPC::RpcServer.new + s.add_http2_port('0.0.0.0:50051') + s.handle(GreeterServer) + s.run +end + +main diff --git a/ruby/lib/helloworld.rb b/ruby/lib/helloworld.rb new file mode 100644 index 00000000000..82bdd78e2a4 --- /dev/null +++ b/ruby/lib/helloworld.rb @@ -0,0 +1,18 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: helloworld.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "helloworld.HelloRequest" do + optional :name, :string, 1 + end + add_message "helloworld.HelloReply" do + optional :message, :string, 1 + end +end + +module Helloworld + HelloRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("helloworld.HelloRequest").msgclass + HelloReply = Google::Protobuf::DescriptorPool.generated_pool.lookup("helloworld.HelloReply").msgclass +end diff --git a/ruby/lib/helloworld_services.rb b/ruby/lib/helloworld_services.rb new file mode 100644 index 00000000000..7da45ebc6b2 --- /dev/null +++ b/ruby/lib/helloworld_services.rb @@ -0,0 +1,24 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: helloworld.proto for package 'helloworld' + +require 'grpc' +require 'helloworld' + +module Helloworld + module Greeter + + # TODO: add proto service documentation here + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'helloworld.Greeter' + + rpc :SayHello, HelloRequest, HelloReply + end + + Stub = Service.rpc_stub_class + end +end diff --git a/src/main/proto/helloworld.proto b/src/main/proto/helloworld.proto deleted file mode 100644 index da5c3a1d85d..00000000000 --- a/src/main/proto/helloworld.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto3"; - -option java_package = "ex.grpc"; - -package helloworld; - -// The request message containing the user's name. -message HelloRequest { - optional string name = 1; -} - -// The response message containing the greetings -message HelloReply { - optional string message = 1; -} - -// The greeting service definition. -service Greetings { - // Sends a greeting - rpc hello (HelloRequest) returns (HelloReply) { - } -}