Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/helloworld/static_codegen_es/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This is the static code generation variant of the Hello World. Code in these examples is pre-generated using protoc and the Node gRPC protoc plugin, and the generated code can be found in various `*_pb.js` files. The command line sequence for generating those files is as follows (assuming that `protoc` and `grpc_node_plugin` are present, and starting in the directory which contains this README.md file):

```sh
cd ../protos
npm install -g grpc-tools @bufbuild/protoc-gen-es
grpc_tools_node_protoc --es_out=target=js,js_import_style=legacy_commonjs:../helloworld/static_codegen_es/ --grpc_out=grpc_js,runtime=bufbuild-protobuf:../helloworld/static_codegen_es/ helloworld.proto
```
52 changes: 52 additions & 0 deletions examples/helloworld/static_codegen_es/greeter_client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

var parseArgs = require('minimist');
var messages = require('./helloworld_pb');
var services = require('./helloworld_grpc_pb');

var grpc = require('@grpc/grpc-js');
var { create } = require('@bufbuild/protobuf');

function main() {
var argv = parseArgs(process.argv.slice(2), {
string: 'target'
});
var target;
if (argv.target) {
target = argv.target;
} else {
target = 'localhost:50051';
}
var client = new services.GreeterClient(target,
grpc.credentials.createInsecure());
var user;
if (argv._.length > 0) {
user = argv._[0];
} else {
user = 'world';
}
var request = create(messages.HelloRequestSchema, {
name: user,
});
client.sayHello(request, function(err, response) {
console.log('Greeting:', response.message);
});
}

main();
50 changes: 50 additions & 0 deletions examples/helloworld/static_codegen_es/greeter_server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

var messages = require('./helloworld_pb');
var services = require('./helloworld_grpc_pb');

var grpc = require('@grpc/grpc-js');
var { create } = require('@bufbuild/protobuf');

/**
* Implements the SayHello RPC method.
*/
function sayHello(call, callback) {
var reply = create(messages.HelloReplySchema, {
message: 'Hello ' + call.request.name,
});
callback(null, reply);
}

/**
* Starts an RPC server that receives requests for the Greeter service at the
* sample server port
*/
function main() {
var server = new grpc.Server();
server.addService(services.GreeterService, {sayHello: sayHello});
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), (err, port) => {
if (err != null) {
return console.error(err);
}
console.log(`gRPC listening on ${port}`)
});
}

main();
73 changes: 73 additions & 0 deletions examples/helloworld/static_codegen_es/helloworld_grpc_pb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// GENERATED CODE -- DO NOT EDIT!

// Original file comments:
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
'use strict';
var grpc = require('@grpc/grpc-js');
var proto = require('@bufbuild/protobuf');
var helloworld_pb = require('./helloworld_pb.js');

function serialize_helloworld_HelloReply(arg) {
if (!proto.isMessage(arg, helloworld_pb.HelloReplySchema)) {
throw new Error('Expected argument of type helloworld.HelloReply');
}
return Buffer.from(proto.toBinary(helloworld_pb.HelloReplySchema, arg));
}

function deserialize_helloworld_HelloReply(buffer_arg) {
return proto.fromBinary(helloworld_pb.HelloReplySchema, new Uint8Array(buffer_arg));
}

function serialize_helloworld_HelloRequest(arg) {
if (!proto.isMessage(arg, helloworld_pb.HelloRequestSchema)) {
throw new Error('Expected argument of type helloworld.HelloRequest');
}
return Buffer.from(proto.toBinary(helloworld_pb.HelloRequestSchema, arg));
}

function deserialize_helloworld_HelloRequest(buffer_arg) {
return proto.fromBinary(helloworld_pb.HelloRequestSchema, new Uint8Array(buffer_arg));
}


// The greeting service definition.
var GreeterService = exports.GreeterService = {
// Sends a greeting
sayHello: {
path: '/helloworld.Greeter/SayHello',
requestStream: false,
responseStream: false,
requestType: helloworld_pb.HelloRequestSchema,
responseType: helloworld_pb.HelloReplySchema,
requestSerialize: serialize_helloworld_HelloRequest,
requestDeserialize: deserialize_helloworld_HelloRequest,
responseSerialize: serialize_helloworld_HelloReply,
responseDeserialize: deserialize_helloworld_HelloReply,
},
sayHelloStreamReply: {
path: '/helloworld.Greeter/SayHelloStreamReply',
requestStream: false,
responseStream: true,
requestType: helloworld_pb.HelloRequestSchema,
responseType: helloworld_pb.HelloReplySchema,
requestSerialize: serialize_helloworld_HelloRequest,
requestDeserialize: deserialize_helloworld_HelloRequest,
responseSerialize: serialize_helloworld_HelloReply,
responseDeserialize: deserialize_helloworld_HelloReply,
},
};

exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService, 'Greeter');
56 changes: 56 additions & 0 deletions examples/helloworld/static_codegen_es/helloworld_pb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// @generated by protoc-gen-es v2.7.0 with parameter "target=js,js_import_style=legacy_commonjs"
// @generated from file helloworld.proto (package helloworld, syntax proto3)
/* eslint-disable */

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

const { fileDesc, messageDesc, serviceDesc } = require("@bufbuild/protobuf/codegenv2");

/**
* Describes the file helloworld.proto.
*/
const file_helloworld = /*@__PURE__*/
fileDesc("ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVzdBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEoCTKWAQoHR3JlZXRlchI+CghTYXlIZWxsbxIYLmhlbGxvd29ybGQuSGVsbG9SZXF1ZXN0GhYuaGVsbG93b3JsZC5IZWxsb1JlcGx5IgASSwoTU2F5SGVsbG9TdHJlYW1SZXBseRIYLmhlbGxvd29ybGQuSGVsbG9SZXF1ZXN0GhYuaGVsbG93b3JsZC5IZWxsb1JlcGx5IgAwAUI2Chtpby5ncnBjLmV4YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXYgZwcm90bzM");

/**
* Describes the message helloworld.HelloRequest.
* Use `create(HelloRequestSchema)` to create a new message.
*/
const HelloRequestSchema = /*@__PURE__*/
messageDesc(file_helloworld, 0);

/**
* Describes the message helloworld.HelloReply.
* Use `create(HelloReplySchema)` to create a new message.
*/
const HelloReplySchema = /*@__PURE__*/
messageDesc(file_helloworld, 1);

/**
* The greeting service definition.
*
* @generated from service helloworld.Greeter
*/
const Greeter = /*@__PURE__*/
serviceDesc(file_helloworld, 0);


exports.file_helloworld = file_helloworld;
exports.HelloRequestSchema = HelloRequestSchema;
exports.HelloReplySchema = HelloReplySchema;
exports.Greeter = Greeter;
1 change: 1 addition & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"@grpc/proto-loader": "^0.6.0",
"async": "^1.5.2",
"google-protobuf": "^3.0.0",
"@bufbuild/protobuf": "^2.7.0",
"@grpc/grpc-js": "^1.10.2",
"@grpc/grpc-js-xds": "^1.10.0",
"@grpc/reflection": "^1.0.0",
Expand Down
79 changes: 70 additions & 9 deletions packages/grpc-tools/src/node_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,27 @@ grpc::string MessageIdentifierName(const grpc::string& name) {
return grpc_generator::StringReplace(name, ".", "_");
}

grpc::string NodeObjectPath(const Descriptor* descriptor) {
grpc::string NodeObjectPath(const Descriptor* descriptor, const grpc::string& runtime) {
grpc::string module_alias = ModuleAlias(descriptor->file()->name());
if (runtime == "bufbuild-protobuf" && descriptor->file()->name().find("google/protobuf") == 0) {
module_alias = "wkt";
}
grpc::string name = descriptor->full_name();
grpc_generator::StripPrefix(&name, descriptor->file()->package() + ".");
if (runtime == "bufbuild-protobuf") {
name += "Schema";
}
return module_alias + "." + name;
}

// Prints out the message serializer and deserializer functions
void PrintMessageTransformer(const Descriptor* descriptor, Printer* out,
// Prints out the message serializer and deserializer functions for google-protobuf.
void PrintGoogleProtobufMessageTransformer(const Descriptor* descriptor, Printer* out,
const Parameters& params) {
map<grpc::string, grpc::string> template_vars;
grpc::string full_name = descriptor->full_name();
template_vars["identifier_name"] = MessageIdentifierName(full_name);
template_vars["name"] = full_name;
template_vars["node_name"] = NodeObjectPath(descriptor);
template_vars["node_name"] = NodeObjectPath(descriptor, params.runtime);
// Print the serializer
out->Print(template_vars, "function serialize_$identifier_name$(arg) {\n");
out->Indent();
Expand All @@ -153,15 +159,59 @@ void PrintMessageTransformer(const Descriptor* descriptor, Printer* out,
out->Print("}\n\n");
}

void PrintMethod(const MethodDescriptor* method, Printer* out) {
// Prints out the message serializer and deserializer functions for bufbuild-protobuf.
void PrintBufbuildProtobufMessageTransformer(const Descriptor* descriptor, Printer* out,
const Parameters& params) {
map<grpc::string, grpc::string> template_vars;
grpc::string full_name = descriptor->full_name();
template_vars["identifier_name"] = MessageIdentifierName(full_name);
template_vars["name"] = full_name;
template_vars["node_name"] = NodeObjectPath(descriptor, params.runtime);
// Print the serializer
out->Print(template_vars, "function serialize_$identifier_name$(arg) {\n");
out->Indent();
if (!params.omit_serialize_instanceof) {
out->Print(template_vars, "if (!proto.isMessage(arg, $node_name$)) {\n");
out->Indent();
out->Print(template_vars,
"throw new Error('Expected argument of type $name$');\n");
out->Outdent();
out->Print("}\n");
}
out->Print(template_vars, "return Buffer.from(proto.toBinary($node_name$, arg));\n");
out->Outdent();
out->Print("}\n\n");

// Print the deserializer
out->Print(template_vars,
"function deserialize_$identifier_name$(buffer_arg) {\n");
out->Indent();
out->Print(
template_vars,
"return proto.fromBinary($node_name$, new Uint8Array(buffer_arg));\n");
out->Outdent();
out->Print("}\n\n");
}

// Prints out the message serializer and deserializer functions
void PrintMessageTransformer(const Descriptor* descriptor, Printer* out,
const Parameters& params) {
if (params.runtime == "bufbuild-protobuf") {
PrintBufbuildProtobufMessageTransformer(descriptor, out, params);
} else {
PrintGoogleProtobufMessageTransformer(descriptor, out, params);
}
}

void PrintMethod(const MethodDescriptor* method, Printer* out, const Parameters& params) {
const Descriptor* input_type = method->input_type();
const Descriptor* output_type = method->output_type();
map<grpc::string, grpc::string> vars;
vars["service_name"] = method->service()->full_name();
vars["name"] = method->name();
vars["input_type"] = NodeObjectPath(input_type);
vars["input_type"] = NodeObjectPath(input_type, params.runtime);
vars["input_type_id"] = MessageIdentifierName(input_type->full_name());
vars["output_type"] = NodeObjectPath(output_type);
vars["output_type"] = NodeObjectPath(output_type, params.runtime);
vars["output_type_id"] = MessageIdentifierName(output_type->full_name());
vars["client_stream"] = method->client_streaming() ? "true" : "false";
vars["server_stream"] = method->server_streaming() ? "true" : "false";
Expand Down Expand Up @@ -198,7 +248,7 @@ void PrintService(const ServiceDescriptor* service, Printer* out,
grpc_generator::LowercaseFirstLetter(service->method(i)->name());
out->PrintRaw(GetNodeComments(service->method(i), true).c_str());
out->Print("$method_name$: ", "method_name", method_name);
PrintMethod(service->method(i), out);
PrintMethod(service->method(i), out, params);
out->Print(",\n");
out->PrintRaw(GetNodeComments(service->method(i), false).c_str());
}
Expand All @@ -218,14 +268,25 @@ void PrintImports(const FileDescriptor* file, Printer* out,
grpc::string package = params.grpc_js ? "@grpc/grpc-js" : "grpc";
out->Print("var grpc = require('$package$');\n", "package", package);
}
if (params.runtime == "bufbuild-protobuf") {
out->Print("var proto = require('@bufbuild/protobuf');\n");
}
if (file->message_type_count() > 0) {
grpc::string file_path =
GetRelativePath(file->name(), GetJSMessageFilename(file->name()));
out->Print("var $module_alias$ = require('$file_path$');\n", "module_alias",
ModuleAlias(file->name()), "file_path", file_path);
}

bool imports_wkt = false;
for (int i = 0; i < file->dependency_count(); i++) {
if (params.runtime == "bufbuild-protobuf" && file->dependency(i)->name().find("google/protobuf") == 0) {
// WKTs are provided by the runtime from a single location.
if (!imports_wkt) {
out->Print("var wkt = require('@bufbuild/protobuf/wkt');");
imports_wkt = true;
}
continue;
}
grpc::string file_path = GetRelativePath(
file->name(), GetJSMessageFilename(file->dependency(i)->name()));
out->Print("var $module_alias$ = require('$file_path$');\n", "module_alias",
Expand Down
2 changes: 2 additions & 0 deletions packages/grpc-tools/src/node_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct Parameters {
bool grpc_js;
// Omit instanceof check for messages in serialize methods
bool omit_serialize_instanceof;
// Runtime to use for protobuf serialization (default: "google-protobuf", "bufbuild-protobuf" for @bufbuild/protobuf)
grpc::string runtime;
};

grpc::string GenerateFile(const grpc::protobuf::FileDescriptor* file,
Expand Down
Loading