From 754307bc9fe3d0034ea5d4aeab2eed558eac5900 Mon Sep 17 00:00:00 2001 From: Lisa Carey Date: Wed, 2 Sep 2015 14:32:41 +0100 Subject: [PATCH 1/8] Some presentation improvements: collapsible navbar & added protocol doc to site --- _includes/nav.html | 4 +- _layouts/docs.html | 67 +- css/style.less | 45 ++ docs/index.md | 1033 +++++++++++++++++++++++++----- docs/reference/protocol-http2.md | 197 ++++++ js/common.js | 20 + js/jquery.collapsible.js | 94 +++ 7 files changed, 1279 insertions(+), 181 deletions(-) create mode 100644 docs/reference/protocol-http2.md create mode 100644 js/jquery.collapsible.js diff --git a/_includes/nav.html b/_includes/nav.html index ac46f6c7..df194606 100644 --- a/_includes/nav.html +++ b/_includes/nav.html @@ -20,10 +20,10 @@
  • Documentation
  • Contribute
  • FAQ
  • -
  • Protocol
  • +
  • Protocol
  • - \ No newline at end of file + diff --git a/_layouts/docs.html b/_layouts/docs.html index 0e3e7ee3..ec711a8d 100644 --- a/_layouts/docs.html +++ b/_layouts/docs.html @@ -5,16 +5,18 @@
    diff --git a/css/style.less b/css/style.less index a15cc857..4d39931f 100644 --- a/css/style.less +++ b/css/style.less @@ -1,3 +1,5 @@ +@import url("https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css"); + // Colors @mainBrandColor: #2DA6B0; @secondBrandColor: #197E8B; @@ -42,6 +44,15 @@ h1, h2, h3, h4, h5, h6 { p, li {line-height: 22px;} +p.note { + background-color: @thirdBrandColor; + padding: 9.5px; +} + +p.note code { + background-color: @thirdBrandColor !important; +} + code { color: @codeColor; background-color: @inverseBrandColor; @@ -56,6 +67,31 @@ pre, pre.prettyprint { padding: 9.5px !important; } +//tabs +.ui-widget-content { + font-size:14px !important; + font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif !important; + color: @textColor !important; +} + +.ui-widget-content a { + color: @mainBrandColor !important; +} + +.ui-widget-content a:hover, a:focus { + color: @linkHoverColor !important; +} + +// Tables are table-y +table, th, td { + border: 1px solid lighten(@textColor, 20%); + padding: 6px +} + +th { + background-color: @thirdBrandColor; +} + // Fix Bootstrap mobile menu colors on inverse navbar. .navbar-toggle .icon-bar { background-color: @inverseBrandColor; @@ -131,6 +167,15 @@ pre, pre.prettyprint { } } +// Expandy nav items +h4.arrow-r::before { + content: "▸ " +} + +h4.arrow-d::before { + content: "▾ " +} + // Landing page .landing-context { .lang-list { diff --git a/docs/index.md b/docs/index.md index 2806834d..f09260c1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,22 +12,26 @@ Hello World example. You'll find more tutorials and reference docs in this site
    + ## Quick start -To get up and running with gRPC straight away, see the quick start for your chosen language, which provides links to installation instructions and more: +To get up and running with gRPC straight away, see the quick start for your chosen language, which provides links to installation instructions, quick instructions for building the example used in this guide, and more: * [C++](/docs/installation/c.html) * [Java](/docs/installation/java.html) * [Go](/docs/installation/go.html) +* [Python](/docs/installation/python.html) * [Ruby](/docs/installation/ruby.html) * [Node.js](/docs/installation/node.html) * [Android Java](https://github.com/grpc/grpc-common/tree/master/java/android) (draft) -* [Python](/docs/installation/python.html) * [C#](/docs/installation/csharp.html) +* [Objective-C](/docs/installation/objective-c.html) +* [PHP](/docs/installation/php.html) You can find out about the gRPC source code repositories in [grpc](https://github.com/grpc/grpc). Most of our example code (plus more draft documentation) lives in [grpc-common](https://github.com/grpc/grpc-common). + ## What is gRPC? In gRPC a *client* application can directly call @@ -75,6 +79,7 @@ the major differences from the current default version in the [release notes](ht 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! @@ -85,28 +90,25 @@ 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. +- Create a server that implements this interface in your favourite language (where available). +- Create a client in your favourite language (or any other one you like!) that accesses your server. -The complete code for the example is available in the `grpc-common` GitHub +The complete code for the examples 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 see more -implementations of our Hello World example in each language's -[quick start](#quickstart). There are also further tutorials in this site, and +Note that server code for our example isn't available in all gRPC languages, as gRPC PHP and Objective-C only support creating clients. + +This is an introductory example rather than a comprehensive tutorial for any particular language. You can find more in-depth tutorials in this site, and reference documentation for all gRPC languages is 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 +the example code. If you just want to read the examples, you can go straight to the [next step](#servicedef). #### Install Git @@ -121,30 +123,132 @@ the code to hack on #### Install gRPC -To build and install gRPC plugins and related tools: - -- For Java, see the [Java installation instructions](https://github.com/grpc/grpc-java). -- For Go, see the [Go quick start](/docs/installation/go.html). +To build and install gRPC plugins and related tools, see the [Quickstart](#quickstart) for your chosen language(s). #### Get the source code -The example code for our Java example lives in the `grpc-java` +
    + +
    +The example code for our Java example lives in the grpc-java GitHub repository. Clone this repository to your local machine by running the following command: - - -``` +
     git clone https://github.com/grpc/grpc-java.git
    -```
    +
    -Change your current directory to grpc-java/examples - -``` +Change your current directory to grpc-java/examples. +
     cd grpc-java/examples
    -```
    -
    -
    -
    +
    +
    +
    +

    The example code for this lives in the grpc-common GitHub repository. Clone this repository to your local machine by running the following command: + +

    +$ git clone https://github.com/grpc/grpc-common.git
    +
    + +

    Change your current directory to grpc-common/cpp/helloworld + +

    +$ cd grpc-common/cpp/helloworld/
    +
    +
    +
    +

    The example code for this lives in the grpc-common GitHub repository. Clone this repository to your local machine by running the following command: + +

    +$ git clone https://github.com/grpc/grpc-common.git
    +
    + +

    Change your current directory to grpc-common/python/helloworld + +

    +$ cd grpc-common/python/helloworld/
    +
    +
    +
    +

    Get the example: +

    +$ go get -u github.com/grpc/grpc-common/go/greeter_client
    +$ go get -u github.com/grpc/grpc-common/go/greeter_server
    +
    +

    Change your current directory to grpc-common/go +

    +
    +

    The example code for this lives in the grpc-common GitHub repository. Clone this repository to your local machine by running the following command:

    + +
    +$ git clone https://github.com/grpc/grpc-common.git
    +
    + +

    Change your current directory to grpc-common/ruby. Then use bundler to install the example package's dependencies:

    + +
    +$ gem install bundler # if you don't already have bundler available
    +$ bundle install
    +
    + +
    +
    +

    The example code for this lives in the grpc-common GitHub repository. Clone this repository to your local machine by running the following command:

    + +
    +$ git clone https://github.com/grpc/grpc-common.git
    +
    + +

    Change your current directory to grpc-common/ruby, then install this package's dependencies:

    +
    +$ cd grpc-common/node
    +$ npm install
    +
    + +
    +
    +

    The example code for this lives in the grpc-common GitHub repository. Clone this repository to your local machine by running the following command:

    + +
    +$ git clone https://github.com/grpc/grpc-common.git
    +
    + +

    Open Greeter.sln from Visual Studio (or Monodevelop on Linux). See the C# Quickstart for platform-specific setup.

    +
    +
    +

    The example code for this lives in the grpc-common GitHub repository. Clone this repository to your local machine by running the following command:

    + +
    +$ git clone https://github.com/grpc/grpc-common.git
    +
    + +

    Change your current directory to grpc-common/objective-c/helloworld.

    + +
    +
    +

    The example code for this lives in the grpc-common GitHub repository. Clone this repository to your local machine by running the following command:

    + +
    +$ git clone https://github.com/grpc/grpc-common.git
    +
    + +

    Change your current directory to grpc-common/php.

    + +

    While most of our Hello World examples use the same .proto file, the PHP example has its own copy of helloworld.proto because it currently depends on some proto2 syntax. There is no proto3 support for PHP yet.

    +
    +
    + + + ### Defining a service @@ -191,14 +295,14 @@ message HelloReply { ``` + ### 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 +our application - you +can generate gRPC code in any gRPC-supported language, although PHP and Objective-C only support creating clients. 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 `Greeter` service. @@ -206,92 +310,372 @@ defined in our `Greeter` service. the example, you can skip this step and move onto the next one where we examine the generated code.) -For simplicity, we've provided a [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) with our Java examples that runs `protoc` for you with the appropriate plugin, input, and output: - -``` +
    + +
    +

    For simplicity, we've provided a Gradle build file with our Java examples that runs protoc for you with the appropriate plugin, input, and output: + +

     ../gradlew build
    -```
    +
    -This generates the following classes from our .proto, which contain all the generated code +

    This generates the following classes from our .proto, which contain all the generated code we need to create our example: -- `Helloworld.java`, which +

    • Helloworld.java, which has all the protocol buffer code to populate, serialize, and retrieve our -`HelloRequest` and `HelloReply` message types -- `GreeterGrpc.java`, which contains (along with some other useful code): - - an interface for `Greeter` servers to implement +HelloRequest and HelloReply message types +
    • 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(io.grpc.examples.Helloworld.HelloRequest request,
                   io.grpc.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. +
      • _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
               io.grpc.stub.AbstractStub
               implements Greeter {
            ...
           }
        -  ```
        +  
        +
      +
    +
    +
    +

    To generate the client and server side interfaces, run: - -### Writing a server +

    +$ make helloworld.grpc.pb.cc helloworld.pb.cc
    +
    -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. +

    Which internally invokes the protocol buffer compiler as: -Our server application has two classes: +

    +$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto
    +$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
    +
    -- a main server class that hosts the service implementation and allows access over the -network: [HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java). +

    This generates: +

    • helloworld.pb.h, which declares classes for populating, serializing, and retrieving our HelloRequest and HelloResponse message types, and its implementation helloworld.pb.cc. +
    • helloworld.grpc.pb.h, which declares our generated service classes, and its implementation helloworld.grpc.pb.cc. +
    +
    +
    +

    To generate the client and server side interfaces: +

    +$ ./run_codegen.sh
    +
    -- a simple service implementation class [GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51). +

    Which internally invokes the protocol buffer compiler as: +

    $ protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/helloworld.proto
    -#### Service implementation +

    This generates helloworld_pb2.py, which contains our generated client and server classes, as well as classes for populating, serializing, and retrieving our HelloRequest and HelloResponse message types. -[GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51) -actually implements our `Greeter` service's required behaviour. +

    +
    +To generate the client and server side interfaces, run the protocol buffer compiler: -As you can see, the class `GreeterImpl` implements the interface -`GreeterGrpc.Greeter` that we [generated](#generating) from our proto -[IDL](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto) by implementing the method `sayHello`: +``` +protoc -I ../protos ../protos/helloworld.proto --go_out=plugins=grpc:helloworld +``` + +This generates `helloworld.pb.go`, which contains our generated client and server code, as well as code for populating, serializing, and retrieving our `HelloRequest` and `HelloResponse` message types. + +
    +
    +To generate the client and server side interfaces, run the protocol buffer compiler:

    + +``` +protoc -I ../protos --ruby_out=lib --grpc_out=lib --plugin=protoc-gen-grpc=`which grpc_ruby_plugin` ../protos/helloworld.proto +``` + +This generates the following files in the lib directory: + +- `lib/helloworld.rb` defines a module `Helloworld`, which provides all the protocol buffer code to populate, serialize, and retrieve our request and response message types. +- `lib/helloworld_services.rb` extends the `Helloworld` module with our generated client and server classes. + +
    +
    +The Node.js library dynamically generates service descriptors and client stub definitions from .proto files loaded at runtime, so there's no need to generate any special code when using this language. Instead, in our example server and client we `require` the gRPC library, then use its `load()` method: + +``` +var grpc = require('grpc'); +var hello_proto = grpc.load(PROTO_PATH).helloworld; +``` +
    +
    + +- To generate the code on Windows, we use `protoc.exe` and `grpc_csharp_plugin.exe` binaries that are shipped with the `Grpc.Tools` NuGet package under the `tools` directory. +Normally you would need to add the `Grpc.Tools` package to the solution yourself, but in this example it has been already done for you. The following command should be run from the `csharp/route_guide` directory: -```java - @Override - public void sayHello(HelloRequest req, StreamObserver responseObserver) { - HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); - responseObserver.onValue(reply); - responseObserver.onCompleted(); - } ``` -- `sayHello` takes two parameters: - - `HelloRequest`: the request - - `StreamObserver`: a response observer, which is - a special interface for the server to call with its response +> packages\Grpc.Tools.0.5.0\tools\protoc -I Greeter/protos --csharp_out=Greeter --grpc_out=Greeter --plugin=protoc-gen-grpc=packages\Grpc.Tools.0.5.0\tools\grpc_csharp_plugin.exe Greeter/protos/helloworld.proto +``` + +- On Linux/MacOS, we rely on `protoc` and `grpc_csharp_plugin` being installed by Linuxbrew/Homebrew. Run this command from the route_guide directory: + +``` +$ protoc -I Greeter/protos --csharp_out=Greeter --grpc_out=Greeter --plugin=protoc-gen-grpc=`which grpc_csharp_plugin` Greeter/protos/helloworld.proto +``` + +Running the appropriate command for your OS regenerates the following files in the Greeter directory: + +- `Greeter/Helloworld.cs` defines a namespace `helloworld` + - This contains all the protocol buffer code to populate, serialize, and retrieve our request and response message types +- `Greeter/HelloworldGrpc.cs`, provides stub and service classes, including: + - an interface `Greeter.IGreeter` to inherit from when defining RouteGuide service implementations + - a class `Greeter.GreeterClient` that can be used to access remote RouteGuide instances + + +
    +
    +For simplicity, we've provided a [Podspec file](https://github.com/grpc/grpc-common/blob/master/objective-c/helloworld/HelloWorld.podspec) that runs protoc for you with the appropriate plugin, input, and output, and describes how to compile the generated files. You just need to run in `grpc-common/objective-c/route_guide`: + +``` +$ pod install +``` + +You can then open the XCode workspace created by Cocoapods to see the generated code. Running the command generates: + +- `Helloworld.pbobjc.h`, the header which declares your generated message classes. +- `Helloworld.pbobjc.m`, which contains the implementation of your message classes. +- `Helloworld.pbrpc.h`, the header which declares your generated service classes. +- `Helloworld.pbrpc.m`, which contains the implementation of your service classes. + +
    + +
    +gRPC PHP uses the [protoc-gen-php](https://github.com/datto/protobuf-php) tool to generate code from .proto files. You can find out how to install this in the [PHP Quickstart](/docs/installation/php.html). To generate the code for our Greeter service, run: + +``` +protoc-gen-php -i . -o . ./helloworld.proto +``` + +This generates `helloworld.php`, which contains: + +- All the protocol buffer code to populate, serialize, and retrieve our request and response message types. +- A class called `GreeterClient` that lets clients call the methods defined in the `Greeter` service. + + +
    +
    + + + + +### Writing a server + +Now let's write some code! First we'll create a server application to implement +our service (which, you'll remember, we can do in all gRPC languages except Objective-C and PHP). 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. + +#### Service implementation + +
    + +
    +

    GreeterImpl.java +actually implements our Greeter service's required behaviour.

    + +

    As you can see, the class GreeterImpl implements the interface +GreeterGrpc.Greeter that we generated from our proto +IDL by implementing the method sayHello:

    +
    +  @Override
    +  public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
    +    HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
    +    responseObserver.onValue(reply);
    +    responseObserver.onCompleted();
    +  }
    +
    +
      +
    • sayHello takes two parameters: + +
        +
      • HelloRequest: the request
      • +
      • StreamObserver<HelloReply>: 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. +
    3. We return the HelloReply to the client and then specify that we've finished dealing with the RPC.
    4. +
    +
    +
    +

    greeter_server.cc +implements our Greeter service's required behaviour.

    + +

    As you can see, the class GreeterServiceImpl implements the interface +Greeter::Service that we generated from our proto +service definition by implementing the method sayHello:

    +
    +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;
    +  }
    +};
    +
    + +

    In this case we're implementing the synchronous version of Greeter, which provides our default gRPC server behaviour (there's also an asynchronous interface, Greeter::AsyncService). +

      +
    • sayHello takes three parameters: + +
        +
      • ServerContext: a context object for this RPC. +
      • HelloRequest: the request
      • +
      • HelloReply: the response
      • +
    • +
    + +

    To return our response to the client and complete the call:

    + +
      +
    1. We populate the provided HelloReply response object with our exciting +message, as specified in our interface definition.
    2. +
    3. We return Status::OK to specify that we've finished dealing with the RPC.
    4. +
    +
    +
    +

    greeter_server.py implements our Greeter service's required behaviour. + +

    As you can see, the class Greeter implements the interface +helloworld_pb2.EarlyAdopterGreeterServicer that we generated from our proto +service definition by implementing the method SayHello:

    +
    class Greeter(helloworld_pb2.EarlyAdopterGreeterServicer):
    +
    +  def SayHello(self, request, context):
    +    return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
    +
    +

    To return our response to the client and complete the call: +

      +
    • We construct and populate a HelloReply response object with our exciting +message, as specified in our interface definition.
    • +
    • We return the HelloReply to the client.
    • +
    +
    +
    +

    greeter_server/main.go implements our Greeter service's required behaviour. +

    As you can see, our server has a server struct type. This implements the GreeterServer interface that we generated from our proto +service definition by implementing the method SayHello: +

    // server is used to implement helloworld.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
    +}
    +
    +

    To return our response to the client and complete the call: +

      +
    • We construct and populate a HelloReply response object with our exciting +message, as specified in our interface definition.
    • +
    • We return the HelloReply to the client.
    • +
    + +
    +
    +

    greeter_server.rb implements our Greeter service's required behaviour. +

    Our server has a GreeterServer class, which implements the GreeterServer interface that we generated from our proto +service definition by implementing the method SayHello:

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

    To return our response to the client and complete the call, we construct and populate a HelloReply response object with our exciting +message, as specified in our interface definition, then return.

    + +
    +
    +

    greeter_server.js implements our Greeter service's required behaviour. +

    Our server implements the Greeterservice from our +service definition by implementing the method SayHello:

    +
    +function sayHello(call, callback) {
    +  callback(null, {message: 'Hello ' + call.request.name});
    +}
    +
    +

    To return our response to the client and complete the call, we populate our response and pass it to the provided callback, with a null first parameter to indicate that there is no error.

    + +
    +
    +

    GreeterServer/Program.cs implements our Greeter service's required behaviour. +

    Our server has a GreeterImpl class, which implements the IGreeter interface that we generated from our proto +service definition by implementing the method SayHello:

    +
    +public Task SayHello(ServerCallContext context, HelloRequest request)
    +{
    +    var reply = new HelloReply.Builder { Message = "Hello " + request.Name }.Build();
    +    return Task.FromResult(reply);
    +}
    +
    -To return our response to the client and complete the call: +

    To return our response to the client and complete the call:

    +
      +
    • We construct and populate a HelloReply response object with our exciting +message, as specified in our interface definition.
    • +
    • We return the HelloReply to the client.
    • +
    -1. We construct and populate a `HelloReply` response object with our exciting -message, as specified in our interface definition. -2. We return the `HelloReply` to the client and then specify that we've finished dealing with the RPC. +
    +
    #### Server implementation -[HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java) -shows the other main feature required to provide a gRPC service; making the service +The other main feature required to provide a gRPC service is making the service implementation available from the network. -```java - /* The port on which the server should run */ +
    + +
    +

    HelloWorldServer.java +provides this for our Java example.

    +
      /* The port on which the server should run */
       private int port = 50051;
       private ServerImpl server;
     
    @@ -309,22 +693,108 @@ implementation available from the network.
             System.err.println("*** server shut down");
           }
         });
    -  }
    +  }
    + +
    +
    +

    greeter_server.cc +also provides this for our C++ example.

    +
    void RunServer() {
    +  std::string server_address("0.0.0.0:50051");
    +  GreeterServiceImpl service;
    +
    +  ServerBuilder builder;
    +  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    +  builder.RegisterService(&service);
    +  std::unique_ptr server(builder.BuildAndStart());
    +  std::cout << "Server listening on " << server_address << std::endl;
    +  server->Wait();
    +}
     
    -```
    +
    +
    +
    +

    greeter_server.py +also provides this for our C++ example.

    +
      server = helloworld_pb2.early_adopter_create_Greeter_server(
    +      Greeter(), 50051, None, None)
    +  server.start()
    +  try:
    +    while True:
    +      time.sleep(_ONE_DAY_IN_SECONDS)
    +  except KeyboardInterrupt:
    +    server.stop()
    +
    +
    +
    +

    greeter_server/main.go also provides this for our Go example. +

    +const (
    +	port = ":50051"
    +)
    +...
    +
    +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)
    +}
    +
    + +
    +
    +

    greeter_server.rb also provides this for our Ruby example. +

    +def main
    +  s = GRPC::RpcServer.new
    +  s.add_http2_port('0.0.0.0:50051')
    +  s.handle(GreeterServer)
    +  s.run
    +end
    +
    + +
    +
    +

    greeter_server.js also provides this for our Node.js example. +

    +function main() {
    +  var server = new Server({
    +    "helloworld.Greeter": {
    +      sayHello: sayHello
    +    }
    +  });
    +  server.bind('0.0.0.0:50051');
    +  server.listen();
    +}
    +
    + +
    +
    +

    GreeterServer/Program.cs also provides this for our C# example. +

    Server server = new Server();
    +server.AddServiceDefinition(Greeter.BindService(new GreeterImpl()));
    +int port = server.AddListeningPort("localhost", 50051);
    +server.Start();
    +
    +
    +
    Here we create an appropriate gRPC server, binding the `Greeter` service 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. + ### 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 -[HelloWorldClient.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java). +in the [previous section](#server). Again, we're not going to go into much detail about how to implement a client; we'll leave that for the tutorial. @@ -336,7 +806,20 @@ 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;
     
    @@ -346,103 +829,341 @@ want to connect to. Then we use the channel to construct the stub instance.
                 .build();
         blockingStub = GreeterGrpc.newBlockingStub(channel);
       }
    +
    -``` - -In this case, we create a blocking stub. This means that the RPC call waits +

    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. +

    +
    +
    int main(int argc, char** argv) {
    +  GreeterClient greeter(
    +      grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials(),
    +                          ChannelArguments()));
    +...
    +}
     
    -#### 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.
    -
    +...
    +
    +class GreeterClient {
    + public:
    +  GreeterClient(std::shared_ptr channel)
    +      : stub_(Greeter::NewStub(channel)) {}
    +...
    + private:
    +  std::unique_ptr stub_;
    +};
    +
    +  
    +
    +
    with helloworld_pb2.early_adopter_create_Greeter_stub('localhost', 50051) as stub:
    +...
    +
    +

    The generated code has a helper function helloworld_pb2.early_adopter_create_Greeter_stub() that creates our channel and stub for us. + +

    +
    +
    const (
    +	address     = "localhost:50051"
    +	defaultName = "world"
    +)
     
    -```java
    -    HelloRequest req = HelloRequest.newBuilder().setName(name).build();
    -    HelloReply reply = blockingStub.sayHello(req);
    +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)
    +...
    +}
    + +

    In gRPC Go you use a special Dial() function to create the channel.

    + +
    +
    +
    stub = Helloworld::Greeter::Stub.new('localhost:50051')
    +

    In Ruby, we can do this in a single method call using the Stub class generated from our .proto.

    +
    +
    +
    var client = new hello_proto.Greeter('localhost:50051');
    +

    In Node.js, we can do this in a single step by calling the Greeter stub constructor.

    + +
    +
    +
    using (Channel channel = new Channel("127.0.0.1:50051"))
    +{
    +    var client = Greeter.NewStub(channel);
    +    ...
    +}
    +
    +
    ``` +#import - -### Try it out! +static NSString * const kHostAddress = @"http://localhost:50051"; +HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress]; +``` -Our [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) simplifies building and running the examples. +In Objective-C, we can do this in a single step using our generated `HLWGreeter` class's designated initializer, which expects a `NSString *` with the server address and port. -You can build and run the server from the `grpc-java` root folder with: +
    +
    -```sh -$ ./gradlew :grpc-examples:helloWorldServer ``` +$client = new helloworld\GreeterClient( + new Grpc\BaseStub('localhost:50051', [])); +``` +In PHP, we can do this in a single step using the `GreeterClient` class's constructor. -and in another terminal window confirm that it receives a message. +
    +
    -```sh -$ ./gradlew :grpc-examples:helloWorldClient -``` -### 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 the `grpc-common` 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 the same proto -that we used for the Java example. - -So, for example, if we visit the [`go` example -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" -) +#### Calling an RPC -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) +Now we can contact the service and obtain a greeting: - // 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 { +1. We construct and fill in a `HelloRequest` to send to the service. +2. We call the stub's `SayHello()` RPC with our request and get a populated `HelloReply` if the RPC is successful, from which we can get our greeting. + +
    + +
    +
    +    HelloRequest req = HelloRequest.newBuilder().setName(name).build();
    +    HelloReply reply = blockingStub.sayHello(req);
    +
    + +

    You can see the complete client code in +HelloWorldClient.java. +

    +
    +
      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.ok()) {
    +      return reply.message();
    +    } else {
    +      return "Rpc failed";
    +    }
    +  }
    + +

    You can see the complete client code in greeter_client.cc.

    +
    +
    +
    response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS)
    +print "Greeter client received: " + response.message
    +
    +

    You can see the complete client code in greeter_client.py.

    + +
    +
    +
    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)
     }
    +log.Printf("Greeting: %s", r.Message)
    +

    You can see the complete client code in greeter_client/main.go.

    + +
    +
    +
    +  message = stub.say_hello(Helloworld::HelloRequest.new(name: user)).message
    +  p "Greeting: #{message}"
    +
    +

    You can see the complete client code in greeter_client.rb.

    + +
    +
    +
      client.sayHello({name: user}, function(err, response) {
    +    console.log('Greeting:', response.message);
    +  });
    +

    You can see the complete client code in greeter_client.js.

    + +
    +
    +
    var reply = client.SayHello(new HelloRequest.Builder { Name = user }.Build());
    +Console.WriteLine("Greeting: " + reply.Message);
    +

    You can see the complete example code in GreeterClient/Program.cs.

    + +
    +
    +
        HLWHelloRequest *request = [HLWHelloRequest message];
    +    request.name = @"Objective-C";
    +    [client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
    +      NSLog(@"%@", response.message);
    +    }];
    +

    You can see the complete example code in grpc-common/objective-c/helloworld.

    + +
    +
    +
      $request = new helloworld\HelloRequest();
    +  $request->setName($name);
    +  list($reply, $status) = $client->SayHello($request)->wait();
    +  $message = $reply->getMessage();
    + +

    You can see the complete client code in greeter_client.php.

    + +
    +
    + + + +### Try it out! + +You can try building and running our example using the same language on both the client and server side. Or you can try out one of gRPC's most useful features - interoperability +between code in different languages - and run a server and client in different languages. Each service +and client uses interface code generated from the same proto, which means that any `Greeter` client can talk to any `Greeter` server. + +First run the server: + +
    + +
    +

    Our Gradle build file simplifies building and running the examples. You can build and run the server from the grpc-java root folder with: + +

    +$ ./gradlew :grpc-examples:helloWorldServer
    +
    + +
    +
    +

    You can build and run the server from the grpc-common/cpp/helloworld folder. First build the client and server. +

    $ make
    +Then run the server, which will listen on port 50051: +
    $ ./greeter_server
    +
    +
    +

    You can run the server from grpc-common/python/helloworld using: +

    $ ./run_server.sh
    + +
    +
    +

    You can run the server from grpc-common/go using: +

    $ greeter_server &
    + +
    +
    +

    You can run the server from grpc-common/ruby using: +

    $ bundle exec ./greeter_server.rb &
    + +
    +
    +

    You can run the server from grpc-common/node using: +

    $ node ./greeter_server.js &
    + +
    +
    +

    Build the solution. Then from grpc-common/csharp: + +``` +> cd GreeterServer/bin/Debug +> GreeterServer.exe ``` +

    +
    + +Once the server is running, in another terminal window run the client and confirm that it receives a message. + +
    + +
    +

    You can build and run the client from the grpc-java root folder with: + +

    +$  ./gradlew :grpc-examples:helloWorldClient
    +
    +
    +
    +

    You can build and run the client from the grpc-common/cpp/helloworld folder. If you haven't already built the client, build it using: +

    $ make
    +Then run the client: +
    $ ./greeter_client
    +
    +
    +

    You can run the client from grpc-common/python/helloworld using: +

    $ ./run_client.sh
    + +
    +
    +

    You can run the client from grpc-common/go using: +

    $ greeter_client
    + +
    +
    +

    You can run the client from grpc-common/ruby using: +

    $ bundle exec ./greeter_client.rb
    + +
    +
    +

    You can run the client from grpc-common/node using: +

    $ node ./greeter_client.js
    + +
    +
    +

    Build the solution. Then from grpc-common/csharp: -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. +``` +> cd GreeterClient/bin/Debug +> GreeterClient.exe +``` + +

    +
    +

    Open the XCode workspace created by Cocoapods, and run the app. You can see the results in XCode's log console.

    + +
    +
    +

    You can run the client from grpc-common/php using: ``` -$ greeter_client +$ ./run_greeter_client.sh ``` + +

    +
    + + ## Read more! - Find out how to install gRPC and get started in each language's [quick start](#quickstart). - Follow the tutorial(s) for your favorite language(s). -- [gRPC Authentication Support](https://github.com/grpc/grpc-common/blob/master/grpc-auth-support.md) introduces authentication support in gRPC with supported mechanisms and examples. +- Discover more about [gRPC concepts](/docs/guides/concepts.html), including RPC life-cycle, synchronous and asynchronous calls, deadlines, and more. +- Read a detailed description of the [gRPC over HTTP2 protocol](/docs/reference/protocol-http2.html). +- [gRPC Authentication Support](/docs/guides/auth.html) introduces authentication support in gRPC with supported mechanisms and examples. diff --git a/docs/reference/protocol-http2.md b/docs/reference/protocol-http2.md new file mode 100644 index 00000000..d800ad40 --- /dev/null +++ b/docs/reference/protocol-http2.md @@ -0,0 +1,197 @@ +--- +layout: docs +title: gRPC over HTTP2 +--- + +

    gRPC over HTTP2 protocol

    + +
    + +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. Production rules use 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] [Message-Accept-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_})] +* **Content-Coding** → “gzip” / “deflate” / “snappy” / {_custom_} +* **Message-Encoding** → “grpc-encoding” Content-Coding +* **Message-Accept-Encoding** → “grpc-accept-encoding” Content-Coding *("," Content-Coding) +* **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](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] [Message-Accept-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/js/common.js b/js/common.js index 8809cb32..b4387339 100644 --- a/js/common.js +++ b/js/common.js @@ -1,9 +1,23 @@ +// Jquery UI for tabbed panes +$.getScript("https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js", function(){ + setupTabs(); +}); + // Add the 'external' class to every outbound link on the site. // The css will add a small right arrow after the link. $('a').filter(function() { return this.hostname && this.hostname !== location.hostname; }).addClass("external"); +//Set up tabs +function setupTabs(rootElement) { + rootElement = rootElement || document; + var tabs = $(rootElement).find('div.tabs'); + if(tabs.length > 0) { + tabs.tabs(); + } +}; + // Make the table of contents $(document).ready(function() { $('#toc').toc({ listType: 'ul' }); @@ -14,6 +28,12 @@ $('pre').addClass("prettyprint"); $.getScript("https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js", function(){ }); +// Collapsible navbar menu, using https://github.com/jordnkr/collapsible +$.getScript("/js/jquery.collapsible.js", function(){ + highlightActive(); + $('.submenu').collapsible(); +}); + // TOC script // https://github.com/ghiculescu/jekyll-table-of-contents diff --git a/js/jquery.collapsible.js b/js/jquery.collapsible.js new file mode 100644 index 00000000..1b6f0e22 --- /dev/null +++ b/js/jquery.collapsible.js @@ -0,0 +1,94 @@ +/*! +* Adapted from collapsible.js 1.0.0 +* https://github.com/jordnkr/collapsible +*/ + + function highlightActive() { + function stringEndsWith(str, endsWithString) { + var index = str.indexOf(endsWithString); + if (index >= 0 && str.length == endsWithString.length + index) { + return true; + } else { + return false; + } + } + + // First have to invalidate old active item. + $('.docs-side-nav a.active').removeClass('active'); + var currentLocation = window.location.hostname + window.location.pathname; + $('.docs-side-nav li a[href]').each(function(index, element) { + if (stringEndsWith(currentLocation, element.href.replace(/^.*\/\//,"").replace(/\:\d+/, ""))) { + $(element).addClass('active'); + } + }); + }; + + +(function($, undefined) { + $.fn.collapsible = function(effect, options) { + var defaults = { + accordionUpSpeed: 400, + accordionDownSpeed: 400, + collapseSpeed: 400, + contentOpen: 0, + arrowRclass: 'arrow-r', + arrowDclass: 'arrow-d', + animate: true + }; + + if (typeof effect === "object") { + var settings = $.extend(defaults, effect); + } else { + var settings = $.extend(defaults, options); + } + + return this.each(function() { + if (settings.animate === false) { + settings.accordionUpSpeed = 0; + settings.accordionDownSpeed = 0; + settings.collapseSpeed = 0; + } + + var $thisEven = $(this).children(':even'); + var $thisOdd = $(this).children(':odd'); + var accord = 'accordion-active'; + + + switch (effect) { + case 'accordion-open': + /* FALLTHROUGH */ + case 'accordion': + if (effect === 'accordion-open') { + $($thisEven[settings.contentOpen]).children(':first-child').toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); + $($thisOdd[settings.contentOpen]).show().addClass(accord); + } + $($thisEven).click(function() { + if ($(this).next().attr('class') === accord) { + $(this).next().slideUp(settings.accordionUpSpeed).removeClass(accord); + $(this).children(':first-child').toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); + } else { + $($thisEven).children().removeClass(settings.arrowDclass).addClass(settings.arrowRclass); + $($thisOdd).slideUp(settings.accordionUpSpeed).removeClass(accord); + $(this).next().slideDown(settings.accordionDownSpeed).addClass(accord); + $(this).children(':first-child').toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); + } + }); + break; + case 'default-open': + /* FALLTHROUGH */ + default: + // is everything open by default or do I have an active child? + if (effect === 'default-open'|| $(this).find("a.active").length) { + $($thisEven[settings.contentOpen]).toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); + $($thisOdd[settings.contentOpen]).show(); + } + $($thisEven).click(function() { + $(this).toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); + $(this).next().slideToggle(settings.collapseSpeed); + }); + break; + } + }); + }; +})(jQuery); + From e1a2d178435267ce85a903647f907ed54153eef7 Mon Sep 17 00:00:00 2001 From: Mugur Marculescu Date: Wed, 2 Sep 2015 16:12:09 -0700 Subject: [PATCH 2/8] Moved http2 protocol into wire.html guide. --- _layouts/docs.html | 3 +-- docs/guides/wire.html | 7 ------- docs/{reference/protocol-http2.md => guides/wire.md} | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 docs/guides/wire.html rename docs/{reference/protocol-http2.md => guides/wire.md} (99%) diff --git a/_layouts/docs.html b/_layouts/docs.html index fa9a5c6d..af43d158 100644 --- a/_layouts/docs.html +++ b/_layouts/docs.html @@ -12,7 +12,7 @@
  • gRPC concepts
  • Authentication
  • Tuning RPC behaviour
  • - +
  • Wire format
  • Error handling and debugging
  • Contribution guidelines
  • @@ -75,7 +75,6 @@
  • PHP API
  • Other Reference