From Hunt Framework 3.4, a new component named GRPC is added, which provides a convenient way for programming with RPC.
You should have already installed the tools needed to generate client and server interface code – if you haven’t, see the here.
Our first step (as you’ll know from the Introduction to gRPC) is to define the gRPC service and the method request and response types using protocol buffers. For the complete .proto file, see helloworld.proto.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Sends another greeting
rpc SayGoodBye (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;
}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 D plugin. This is similar to what we did in the grpc-dlang.
From the protos directory, run the following command:
protoc --plugin=/usr/local/bin/protoc-gen-d --d_out=../source -I ./ helloworld.proto
protoc --plugin=protoc-gen-grpc=/usr/local/bin/grpc_dlang_plugin -I ./ --grpc_out=../source/helloworld helloworld.protoRunning this command generates the following files in the helloworld directory:
helloworld.d, which contains all the protocol buffer code to populate, serialize, and retrieve request and response message types.helloworldrpc.d, which contains the following: An interface type (or stub) for clients to call with the methods defined in theGreeterservice. An interface type for servers to implement, also with the methods defined in theGreeterservice.
In the source directory, create a file named GreeterImpl.d:
module GreeterImpl;
import hunt.logging;
import helloworld.helloworld;
import helloworld.helloworldrpc;
import grpc;
class GreeterImpl : GreeterBase {
override Status SayHello(HelloRequest request, ref HelloReply reply) {
reply.message = "Hello " ~ request.name;
tracef("request: %s, reply: %s", request.name, reply.message);
return Status.OK;
}
override Status SayGoodBye(HelloRequest request, ref HelloReply reply) {
reply.message = "Bye " ~ request.name;
tracef("request: %s, reply: %s", request.name, reply.message);
return Status.OK;
}
}Open the configuration file application.conf for your Hunt Framework application, and add the settings.
# gRPC
grpc.server.enabled = true
grpc.server.host = 127.0.0.1
grpc.server.port = 50051
grpc.server.workerThreads = 4Open the main file of the Hunt application:
import hunt.framework;
import GreeterImpl;
void main(string[] args) {
app.booting(() {
app.grpc.server.register( new GreeterImpl());
});
}In this section, we’ll look at creating a D client for our Greeter service.
In the configuration file application.conf, you can add some settings for one or more gRPC clients:
grpc.clientChannels[0].name = ch1
grpc.clientChannels[0].host = 127.0.0.1
grpc.clientChannels[0].port = 50051
grpc.clientChannels[0].timeout = 15000
grpc.clientChannels[1].name = ch2
grpc.clientChannels[1].host = 127.0.0.1
grpc.clientChannels[1].port = 50052
grpc.clientChannels[1].timeout = 15000Then you can use the channel name to get one gRPC client.
To call service methods, we first need to create a gRPC channel to communicate with the server. Once the gRPC channel is setup, we need a client stub to perform RPCs. We get it by creating a GreeterClient instance which is provided by the helloworld package generated from the example .proto file. Here is the complete example client code.
import hunt.logging;
import grpc;
import helloworld.helloworld;
import helloworld.helloworldrpc;
class IndexController : Controller {
mixin MakeController;
@Action
string testGrpc() {
string[string] queryParameters = request.queries();
string channelName = request.queries()["channel"];
try {
Channel channel = app.grpc.getChannel(channelName);
scope(exit) {
channel.destroy();
}
GreeterClient client = new GreeterClient(channel);
HelloRequest request = new HelloRequest();
request.name = "Hunt";
HelloReply replyHello = client.SayHello(request);
tracef("++++++++++++++++%s", replyHello.message);
HelloReply replyBye = client.SayGoodBye(request);
tracef("++++++++++++++++%s", replyBye.message);
return channelName ~ " passed";
} catch(Exception ex) {
return ex.msg;
}
}
}-
Build the Hunt Framework application, and run the server.
2021-Feb-07 14:57:26.399074 | 15835 | info | register.__lambda1 | gRPC server started at 0.0.0.0:50051. | ../../hunt-framework/source/hunt/framework/provider/GrpcServiceProvider.d:41
-
Visit the server in the browser or
curl.$ curl 'http://127.0.0.1:8080/grpc?channel=ch1'
You’ll see output in the server's terminal like this:
2021-Feb-07 14:57:41.59891 | 15854 | trace | GreeterImpl.SayHello | request: Hunt, reply: Hello Hunt | source/GreeterImpl.d:15
2021-02-07 14:57:41 (15892) [debug] testGrpc - ++++++++++++++++Hello Hunt - source/app/controller/IndexController.d:788
2021-Feb-07 14:57:41.6429258 | 15854 | trace | GreeterImpl.SayGoodBye | request: Hunt, reply: Bye Hunt | source/GreeterImpl.d:21
2021-02-07 14:57:41 (15892) [debug] testGrpc - ++++++++++++++++Bye Hunt - source/app/controller/IndexController.d:791