mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-27 11:12:19 +00:00
[TS] GRPC Implementation (#6141)
* GRPC implementation for Typescript * Fixes a couple of issues * Finished implementing the typescript support for grpc * Updated generated code * Fixes CI
This commit is contained in:
9
grpc/flatbuffers-js-grpc/package.json
Normal file
9
grpc/flatbuffers-js-grpc/package.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "flatbuffers-js-grpc",
|
||||
"version": "1.0.0",
|
||||
"author": "mustii@mmk.one",
|
||||
"dependencies": {
|
||||
"flatbuffers": "^1.12.0",
|
||||
"grpc": "^1.24.3"
|
||||
}
|
||||
}
|
||||
28
grpc/flatbuffers-js-grpc/src/client.ts
Normal file
28
grpc/flatbuffers-js-grpc/src/client.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import grpc from 'grpc';
|
||||
import { HelloRequest } from './greeter_generated';
|
||||
import { GreeterClient } from './greeter_grpc';
|
||||
import { flatbuffers } from 'flatbuffers';
|
||||
|
||||
async function main() {
|
||||
const _server = new GreeterClient('localhost:3000', grpc.credentials.createInsecure());
|
||||
const builder = new flatbuffers.Builder();
|
||||
const offset = builder.createString('mustii');
|
||||
const root = HelloRequest.createHelloRequest(builder, offset);
|
||||
builder.finish(root);
|
||||
const buffer = HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(builder.asUint8Array()));
|
||||
|
||||
_server.SayHello(buffer, (err, response) => {
|
||||
console.log(response.message());
|
||||
});
|
||||
|
||||
const data = _server.SayManyHellos(buffer, null);
|
||||
|
||||
data.on('data', (data) => {
|
||||
console.log(data.message());
|
||||
});
|
||||
data.on('end', (data) => {
|
||||
console.log('end');
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
12
grpc/flatbuffers-js-grpc/src/greeter.fbs
Normal file
12
grpc/flatbuffers-js-grpc/src/greeter.fbs
Normal file
@@ -0,0 +1,12 @@
|
||||
table HelloReply {
|
||||
message:string;
|
||||
}
|
||||
|
||||
table HelloRequest {
|
||||
name:string;
|
||||
}
|
||||
|
||||
rpc_service Greeter {
|
||||
SayHello(HelloRequest):HelloReply;
|
||||
SayManyHellos(HelloRequest):HelloReply (streaming: "server");
|
||||
}
|
||||
174
grpc/flatbuffers-js-grpc/src/greeter_generated.ts
Normal file
174
grpc/flatbuffers-js-grpc/src/greeter_generated.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
export class HelloReply {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
|
||||
bb_pos:number = 0;
|
||||
/**
|
||||
* @param number i
|
||||
* @param flatbuffers.ByteBuffer bb
|
||||
* @returns HelloReply
|
||||
*/
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):HelloReply {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.ByteBuffer bb
|
||||
* @param HelloReply= obj
|
||||
* @returns HelloReply
|
||||
*/
|
||||
static getRootAsHelloReply(bb:flatbuffers.ByteBuffer, obj?:HelloReply):HelloReply {
|
||||
return (obj || new HelloReply()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.ByteBuffer bb
|
||||
* @param HelloReply= obj
|
||||
* @returns HelloReply
|
||||
*/
|
||||
static getSizePrefixedRootAsHelloReply(bb:flatbuffers.ByteBuffer, obj?:HelloReply):HelloReply {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new HelloReply()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Encoding= optionalEncoding
|
||||
* @returns string|Uint8Array|null
|
||||
*/
|
||||
message():string|null
|
||||
message(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
message(optionalEncoding?:any):string|Uint8Array|null {
|
||||
var offset = this.bb!.__offset(this.bb_pos, 4);
|
||||
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Builder builder
|
||||
*/
|
||||
static startHelloReply(builder:flatbuffers.Builder) {
|
||||
builder.startObject(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Builder builder
|
||||
* @param flatbuffers.Offset messageOffset
|
||||
*/
|
||||
static addMessage(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, messageOffset, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Builder builder
|
||||
* @returns flatbuffers.Offset
|
||||
*/
|
||||
static endHelloReply(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
var offset = builder.endObject();
|
||||
return offset;
|
||||
};
|
||||
|
||||
static createHelloReply(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
HelloReply.startHelloReply(builder);
|
||||
HelloReply.addMessage(builder, messageOffset);
|
||||
return HelloReply.endHelloReply(builder);
|
||||
}
|
||||
|
||||
serialize():Uint8Array {
|
||||
return this.bb!.bytes();
|
||||
}
|
||||
|
||||
static deserialize(buffer: Uint8Array):HelloReply {
|
||||
return HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(buffer))
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
export class HelloRequest {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
|
||||
bb_pos:number = 0;
|
||||
/**
|
||||
* @param number i
|
||||
* @param flatbuffers.ByteBuffer bb
|
||||
* @returns HelloRequest
|
||||
*/
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):HelloRequest {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.ByteBuffer bb
|
||||
* @param HelloRequest= obj
|
||||
* @returns HelloRequest
|
||||
*/
|
||||
static getRootAsHelloRequest(bb:flatbuffers.ByteBuffer, obj?:HelloRequest):HelloRequest {
|
||||
return (obj || new HelloRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.ByteBuffer bb
|
||||
* @param HelloRequest= obj
|
||||
* @returns HelloRequest
|
||||
*/
|
||||
static getSizePrefixedRootAsHelloRequest(bb:flatbuffers.ByteBuffer, obj?:HelloRequest):HelloRequest {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new HelloRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Encoding= optionalEncoding
|
||||
* @returns string|Uint8Array|null
|
||||
*/
|
||||
name():string|null
|
||||
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
name(optionalEncoding?:any):string|Uint8Array|null {
|
||||
var offset = this.bb!.__offset(this.bb_pos, 4);
|
||||
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Builder builder
|
||||
*/
|
||||
static startHelloRequest(builder:flatbuffers.Builder) {
|
||||
builder.startObject(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Builder builder
|
||||
* @param flatbuffers.Offset nameOffset
|
||||
*/
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, nameOffset, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flatbuffers.Builder builder
|
||||
* @returns flatbuffers.Offset
|
||||
*/
|
||||
static endHelloRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
var offset = builder.endObject();
|
||||
return offset;
|
||||
};
|
||||
|
||||
static createHelloRequest(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
HelloRequest.startHelloRequest(builder);
|
||||
HelloRequest.addName(builder, nameOffset);
|
||||
return HelloRequest.endHelloRequest(builder);
|
||||
}
|
||||
|
||||
serialize():Uint8Array {
|
||||
return this.bb!.bytes();
|
||||
}
|
||||
|
||||
static deserialize(buffer: Uint8Array):HelloRequest {
|
||||
return HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(buffer))
|
||||
}
|
||||
}
|
||||
54
grpc/flatbuffers-js-grpc/src/greeter_grpc.d.ts
vendored
Normal file
54
grpc/flatbuffers-js-grpc/src/greeter_grpc.d.ts
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***
|
||||
import { flatbuffers } from 'flatbuffers';
|
||||
import * as Greeter_fbs from './greeter_generated';
|
||||
|
||||
import * as grpc from 'grpc';
|
||||
|
||||
interface IGreeterService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
|
||||
SayHello: IGreeterService_ISayHello;
|
||||
SayManyHellos: IGreeterService_ISayManyHellos;
|
||||
}
|
||||
interface IGreeterService_ISayHello extends grpc.MethodDefinition<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply> {
|
||||
path: string; // /Greeter/SayHello
|
||||
requestStream: boolean; // false
|
||||
responseStream: boolean; // false
|
||||
requestSerialize: grpc.serialize<Greeter_fbs.HelloRequest>;
|
||||
requestDeserialize: grpc.deserialize<Greeter_fbs.HelloRequest>;
|
||||
responseSerialize: grpc.serialize<Greeter_fbs.HelloReply>;
|
||||
responseDeserialize: grpc.deserialize<Greeter_fbs.HelloReply>;
|
||||
}
|
||||
|
||||
interface IGreeterService_ISayManyHellos extends grpc.MethodDefinition<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply> {
|
||||
path: string; // /Greeter/SayManyHellos
|
||||
requestStream: boolean; // false
|
||||
responseStream: boolean; // true
|
||||
requestSerialize: grpc.serialize<Greeter_fbs.HelloRequest>;
|
||||
requestDeserialize: grpc.deserialize<Greeter_fbs.HelloRequest>;
|
||||
responseSerialize: grpc.serialize<Greeter_fbs.HelloReply>;
|
||||
responseDeserialize: grpc.deserialize<Greeter_fbs.HelloReply>;
|
||||
}
|
||||
|
||||
|
||||
export const GreeterService: IGreeterService;
|
||||
|
||||
export interface IGreeterServer {
|
||||
SayHello: grpc.handleUnaryCall<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply>;
|
||||
SayManyHellos: grpc.handleServerStreamingCall<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply>;
|
||||
}
|
||||
|
||||
export interface IGreeterClient {
|
||||
SayHello(request: Greeter_fbs.HelloRequest, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
|
||||
SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
|
||||
SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
|
||||
SayManyHellos(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
|
||||
SayManyHellos(request: Greeter_fbs.HelloRequest, options: Partial<grpc.CallOptions>): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
|
||||
}
|
||||
|
||||
export class GreeterClient extends grpc.Client implements IGreeterClient {
|
||||
constructor(address: string, credentials: grpc.ChannelCredentials, options?: object); public SayHello(request: Greeter_fbs.HelloRequest, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
|
||||
public SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
|
||||
public SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
|
||||
public SayManyHellos(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
|
||||
public SayManyHellos(request: Greeter_fbs.HelloRequest, options: Partial<grpc.CallOptions>): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
|
||||
}
|
||||
|
||||
55
grpc/flatbuffers-js-grpc/src/greeter_grpc.js
Normal file
55
grpc/flatbuffers-js-grpc/src/greeter_grpc.js
Normal file
@@ -0,0 +1,55 @@
|
||||
// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***
|
||||
import { flatbuffers } from 'flatbuffers';
|
||||
import * as Greeter_fbs from './greeter_generated';
|
||||
|
||||
var grpc = require('grpc');
|
||||
|
||||
function serialize_HelloReply(buffer_args) {
|
||||
if (!(buffer_args instanceof Greeter_fbs.HelloReply)) {
|
||||
throw new Error('Expected argument of type Greeter_fbs.HelloReply');
|
||||
}
|
||||
return buffer_args.serialize();
|
||||
}
|
||||
|
||||
function deserialize_HelloReply(buffer) {
|
||||
return Greeter_fbs.HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(buffer))
|
||||
}
|
||||
|
||||
|
||||
function serialize_HelloRequest(buffer_args) {
|
||||
if (!(buffer_args instanceof Greeter_fbs.HelloRequest)) {
|
||||
throw new Error('Expected argument of type Greeter_fbs.HelloRequest');
|
||||
}
|
||||
return buffer_args.serialize();
|
||||
}
|
||||
|
||||
function deserialize_HelloRequest(buffer) {
|
||||
return Greeter_fbs.HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(buffer))
|
||||
}
|
||||
|
||||
|
||||
var GreeterService = exports.GreeterService = {
|
||||
SayHello: {
|
||||
path: '/Greeter/SayHello',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: flatbuffers.ByteBuffer,
|
||||
responseType: Greeter_fbs.HelloReply,
|
||||
requestSerialize: serialize_HelloRequest,
|
||||
requestDeserialize: deserialize_HelloRequest,
|
||||
responseSerialize: serialize_HelloReply,
|
||||
responseDeserialize: deserialize_HelloReply,
|
||||
},
|
||||
SayManyHellos: {
|
||||
path: '/Greeter/SayManyHellos',
|
||||
requestStream: false,
|
||||
responseStream: true,
|
||||
requestType: flatbuffers.ByteBuffer,
|
||||
responseType: Greeter_fbs.HelloReply,
|
||||
requestSerialize: serialize_HelloRequest,
|
||||
requestDeserialize: deserialize_HelloRequest,
|
||||
responseSerialize: serialize_HelloReply,
|
||||
responseDeserialize: deserialize_HelloReply,
|
||||
},
|
||||
};
|
||||
exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService);
|
||||
40
grpc/flatbuffers-js-grpc/src/server.ts
Normal file
40
grpc/flatbuffers-js-grpc/src/server.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import grpc from 'grpc';
|
||||
import { HelloReply, HelloRequest } from './greeter_generated';
|
||||
import { IGreeterServer, GreeterService } from './greeter_grpc';
|
||||
import { flatbuffers } from 'flatbuffers';
|
||||
|
||||
class GreeterServer implements IGreeterServer {
|
||||
|
||||
SayHello(call: grpc.ServerUnaryCall<HelloRequest>, callback: grpc.sendUnaryData<HelloReply>): void {
|
||||
console.log(`${call.request.name()}`);
|
||||
const builder = new flatbuffers.Builder();
|
||||
const offset = builder.createString(`welcome ${call.request.name()}`);
|
||||
const root = HelloReply.createHelloReply(builder, offset);
|
||||
builder.finish(root);
|
||||
callback(null, HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array())));
|
||||
}
|
||||
|
||||
async SayManyHellos(call: grpc.ServerWritableStream<HelloRequest>): Promise<void> {
|
||||
const name = call.request.name();
|
||||
console.log(`${call.request.name()} saying hi in different langagues`);
|
||||
['Hi', 'Hallo', 'Ciao'].forEach(element => {
|
||||
const builder = new flatbuffers.Builder();
|
||||
const offset = builder.createString(`${element} ${name}`);
|
||||
const root = HelloReply.createHelloReply(builder, offset);
|
||||
builder.finish(root);
|
||||
call.write(HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array())))
|
||||
});
|
||||
call.end();
|
||||
}
|
||||
}
|
||||
|
||||
function serve(): void {
|
||||
const PORT = 3000;
|
||||
const server = new grpc.Server();
|
||||
server.addService<IGreeterServer>(GreeterService, new GreeterServer());
|
||||
console.log(`Listening on ${PORT}`);
|
||||
server.bind(`localhost:${PORT}`, grpc.ServerCredentials.createInsecure());
|
||||
server.start();
|
||||
}
|
||||
|
||||
serve();
|
||||
17
grpc/flatbuffers-js-grpc/tsconfig.json
Normal file
17
grpc/flatbuffers-js-grpc/tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"outDir": "./dist",
|
||||
"allowJs": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"strictNullChecks": false,
|
||||
"esModuleInterop": true,
|
||||
"baseUrl": "./",
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
}
|
||||
}
|
||||
@@ -105,3 +105,19 @@ cc_library(
|
||||
"//:flatbuffers",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ts_generator",
|
||||
srcs = [
|
||||
"ts_generator.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"ts_generator.h",
|
||||
":common_headers",
|
||||
],
|
||||
include_prefix = "src/compiler",
|
||||
strip_include_prefix = "/grpc/src/compiler",
|
||||
deps = [
|
||||
"//:flatbuffers",
|
||||
],
|
||||
)
|
||||
@@ -229,11 +229,13 @@ void GenerateServerProtocol(const grpc_generator::Service *service,
|
||||
printer->Print("}\n\n");
|
||||
|
||||
printer->Print(vars, "$ACCESS$ extension $ServiceQualifiedName$Provider {\n");
|
||||
printer->Print("\n");
|
||||
printer->Print(vars,
|
||||
"\tvar serviceName: String { return "
|
||||
"\tvar serviceName: Substring { return "
|
||||
"\"$PATH$$ServiceName$\" }\n");
|
||||
printer->Print("\n");
|
||||
printer->Print(
|
||||
"\tfunc handleMethod(_ methodName: String, callHandlerContext: "
|
||||
"\tfunc handleMethod(_ methodName: Substring, callHandlerContext: "
|
||||
"CallHandlerContext) -> GRPCCallHandler? {\n");
|
||||
printer->Print("\t\tswitch methodName {\n");
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
|
||||
455
grpc/src/compiler/ts_generator.cc
Normal file
455
grpc/src/compiler/ts_generator.cc
Normal file
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* Copyright 2020 Google Inc. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE: The following implementation is a translation for the Swift-grpc
|
||||
* generator since flatbuffers doesnt allow plugins for now. if an issue arises
|
||||
* please open an issue in the flatbuffers repository. This file should always
|
||||
* be maintained according to the Swift-grpc repository
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
#include "flatbuffers/util.h"
|
||||
#include "src/compiler/schema_interface.h"
|
||||
#include "src/compiler/ts_generator.h"
|
||||
|
||||
namespace grpc_ts_generator {
|
||||
|
||||
// MARK: - Shared code
|
||||
|
||||
void GenerateImports(grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary,
|
||||
const bool grpc_var_import) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(
|
||||
"// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***\n");
|
||||
printer->Print("import { flatbuffers } from 'flatbuffers';\n");
|
||||
printer->Print(vars,
|
||||
"import * as $FBSFile$ from './$Filename$_generated';\n");
|
||||
printer->Print("\n");
|
||||
if (grpc_var_import)
|
||||
printer->Print("var grpc = require('grpc');\n");
|
||||
else
|
||||
printer->Print("import * as grpc from 'grpc';\n");
|
||||
printer->Print("\n");
|
||||
}
|
||||
|
||||
// MARK: - Generate Main GRPC Code
|
||||
|
||||
void GetStreamType(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
auto client_streaming = method->ClientStreaming() || method->BidiStreaming();
|
||||
auto server_streaming = method->ServerStreaming() || method->BidiStreaming();
|
||||
vars["ClientStreaming"] = client_streaming ? "true" : "false";
|
||||
vars["ServerStreaming"] = server_streaming ? "true" : "false";
|
||||
printer->Print(vars, "requestStream: $ClientStreaming$,\n");
|
||||
printer->Print(vars, "responseStream: $ServerStreaming$,\n");
|
||||
}
|
||||
|
||||
void GenerateSerializeMethod(grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(vars, "function serialize_$Type$(buffer_args) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "if (!(buffer_args instanceof $FBSFile$.$Type$)) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(
|
||||
vars, "throw new Error('Expected argument of type $FBSFile$.$Type$');\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
printer->Print(vars, "return buffer_args.serialize();\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
|
||||
void GenerateDeserializeMethod(
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(vars, "function deserialize_$Type$(buffer) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars,
|
||||
"return $FBSFile$.$Type$.getRootAs$Type$(new "
|
||||
"flatbuffers.ByteBuffer(buffer))\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
|
||||
void GenerateMethods(const grpc_generator::Service *service,
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
|
||||
std::set<grpc::string> generated_functions;
|
||||
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
auto method = service->method(it);
|
||||
auto output = method->get_output_type_name();
|
||||
auto input = method->get_input_type_name();
|
||||
|
||||
if (generated_functions.find(output) == generated_functions.end()) {
|
||||
generated_functions.insert(output);
|
||||
vars["Type"] = output;
|
||||
GenerateSerializeMethod(printer, &vars);
|
||||
GenerateDeserializeMethod(printer, &vars);
|
||||
}
|
||||
printer->Print("\n");
|
||||
if (generated_functions.find(input) == generated_functions.end()) {
|
||||
generated_functions.insert(input);
|
||||
vars["Type"] = input;
|
||||
GenerateSerializeMethod(printer, &vars);
|
||||
GenerateDeserializeMethod(printer, &vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateService(const grpc_generator::Service *service,
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
vars["NAME"] = service->name() + "Service";
|
||||
|
||||
printer->Print(vars, "var $NAME$ = exports.$NAME$ = {\n");
|
||||
printer->Indent();
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
auto method = service->method(it);
|
||||
vars["MethodName"] = method->name();
|
||||
vars["Output"] = method->get_output_type_name();
|
||||
vars["Input"] = method->get_input_type_name();
|
||||
printer->Print(vars, "$MethodName$: {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "path: '/$PATH$$ServiceName$/$MethodName$',\n");
|
||||
GetStreamType(printer, &*method, &vars);
|
||||
printer->Print(vars, "requestType: flatbuffers.ByteBuffer,\n");
|
||||
printer->Print(vars, "responseType: $FBSFile$.$Output$,\n");
|
||||
printer->Print(vars, "requestSerialize: serialize_$Input$,\n");
|
||||
printer->Print(vars, "requestDeserialize: deserialize_$Input$,\n");
|
||||
printer->Print(vars, "responseSerialize: serialize_$Output$,\n");
|
||||
printer->Print(vars, "responseDeserialize: deserialize_$Output$,\n");
|
||||
printer->Outdent();
|
||||
printer->Print("},\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("};\n");
|
||||
printer->Print(vars,
|
||||
"exports.$ServiceName$Client = "
|
||||
"grpc.makeGenericClientConstructor($NAME$);");
|
||||
}
|
||||
|
||||
grpc::string Generate(grpc_generator::File *file,
|
||||
const grpc_generator::Service *service,
|
||||
const grpc::string &filename) {
|
||||
grpc::string output;
|
||||
std::map<grpc::string, grpc::string> vars;
|
||||
|
||||
vars["PATH"] = file->package();
|
||||
|
||||
if (!file->package().empty()) { vars["PATH"].append("."); }
|
||||
|
||||
vars["ServiceName"] = service->name();
|
||||
vars["FBSFile"] = service->name() + "_fbs";
|
||||
vars["Filename"] = filename;
|
||||
auto printer = file->CreatePrinter(&output);
|
||||
|
||||
GenerateImports(&*printer, &vars, true);
|
||||
GenerateMethods(service, &*printer, &vars);
|
||||
GenerateService(service, &*printer, &vars);
|
||||
return output;
|
||||
}
|
||||
|
||||
// MARK: - Generate Interface
|
||||
|
||||
void FillInterface(grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(
|
||||
vars,
|
||||
"interface I$ServiceName$Service_I$MethodName$ extends "
|
||||
"grpc.MethodDefinition<$FBSFile$.$INPUT$, $FBSFile$.$OUTPUT$> {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "path: string; // /$PATH$$ServiceName$/$MethodName$\n");
|
||||
printer->Print(vars, "requestStream: boolean; // $ClientStreaming$\n");
|
||||
printer->Print(vars, "responseStream: boolean; // $ServerStreaming$\n");
|
||||
printer->Print(vars,
|
||||
"requestSerialize: grpc.serialize<$FBSFile$.$INPUT$>;\n");
|
||||
printer->Print(vars,
|
||||
"requestDeserialize: grpc.deserialize<$FBSFile$.$INPUT$>;\n");
|
||||
printer->Print(vars,
|
||||
"responseSerialize: grpc.serialize<$FBSFile$.$OUTPUT$>;\n");
|
||||
printer->Print(
|
||||
vars, "responseDeserialize: grpc.deserialize<$FBSFile$.$OUTPUT$>;\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void GenerateInterfaces(const grpc_generator::Service *service,
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
auto method = service->method(it);
|
||||
auto client_streaming =
|
||||
method->ClientStreaming() || method->BidiStreaming();
|
||||
auto server_streaming =
|
||||
method->ServerStreaming() || method->BidiStreaming();
|
||||
vars["ClientStreaming"] = client_streaming ? "true" : "false";
|
||||
vars["ServerStreaming"] = server_streaming ? "true" : "false";
|
||||
vars["MethodName"] = method->name();
|
||||
vars["INPUT"] = method->get_input_type_name();
|
||||
vars["OUTPUT"] = method->get_output_type_name();
|
||||
FillInterface(printer, &vars);
|
||||
printer->Print("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateExportedInterface(
|
||||
const grpc_generator::Service *service, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(vars, "export interface I$ServiceName$Server {\n");
|
||||
printer->Indent();
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
auto method = service->method(it);
|
||||
vars["Name"] = method->name();
|
||||
vars["INPUT"] = method->get_input_type_name();
|
||||
vars["OUTPUT"] = method->get_output_type_name();
|
||||
if (method->BidiStreaming()) {
|
||||
printer->Print(vars,
|
||||
"$Name$: grpc.handleBidiStreamingCall<$FBSFile$.$INPUT$, "
|
||||
"$FBSFile$.$OUTPUT$>;\n");
|
||||
continue;
|
||||
}
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(vars,
|
||||
"$Name$: grpc.handleUnaryCall<$FBSFile$.$INPUT$, "
|
||||
"$FBSFile$.$OUTPUT$>;\n");
|
||||
continue;
|
||||
}
|
||||
if (method->ClientStreaming()) {
|
||||
printer->Print(
|
||||
vars,
|
||||
"$Name$: grpc.handleClientStreamingCall<$FBSFile$.$INPUT$, "
|
||||
"$FBSFile$.$OUTPUT$>;\n");
|
||||
continue;
|
||||
}
|
||||
if (method->ServerStreaming()) {
|
||||
printer->Print(
|
||||
vars,
|
||||
"$Name$: grpc.handleServerStreamingCall<$FBSFile$.$INPUT$, "
|
||||
"$FBSFile$.$OUTPUT$>;\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void GenerateMainInterface(const grpc_generator::Service *service,
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(
|
||||
vars,
|
||||
"interface I$ServiceName$Service extends "
|
||||
"grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {\n");
|
||||
printer->Indent();
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
auto method = service->method(it);
|
||||
vars["MethodName"] = method->name();
|
||||
printer->Print(vars,
|
||||
"$MethodName$: I$ServiceName$Service_I$MethodName$;\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
GenerateInterfaces(service, printer, &vars);
|
||||
printer->Print("\n");
|
||||
printer->Print(vars,
|
||||
"export const $ServiceName$Service: I$ServiceName$Service;\n");
|
||||
printer->Print("\n");
|
||||
GenerateExportedInterface(service, printer, &vars);
|
||||
}
|
||||
|
||||
grpc::string GenerateMetaData() { return "metadata: grpc.Metadata"; }
|
||||
|
||||
grpc::string GenerateOptions() { return "options: Partial<grpc.CallOptions>"; }
|
||||
|
||||
void GenerateUnaryClientInterface(
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
grpc::string main = "$ISPUBLIC$$MethodName$(request: $FBSFile$.$INPUT$, ";
|
||||
grpc::string callback =
|
||||
"callback: (error: grpc.ServiceError | null, response: "
|
||||
"$FBSFile$.$OUTPUT$) => void): grpc.ClientUnaryCall;\n";
|
||||
auto meta_data = GenerateMetaData() + ", ";
|
||||
auto options = GenerateOptions() + ", ";
|
||||
printer->Print(vars, (main + callback).c_str());
|
||||
printer->Print(vars, (main + meta_data + callback).c_str());
|
||||
printer->Print(vars, (main + meta_data + options + callback).c_str());
|
||||
}
|
||||
|
||||
void GenerateClientWriteStreamInterface(
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
grpc::string main = "$ISPUBLIC$$MethodName$(";
|
||||
grpc::string callback =
|
||||
"callback: (error: grpc.ServiceError | null, response: "
|
||||
"$FBSFile$.$INPUT$) => void): "
|
||||
"grpc.ClientWritableStream<$FBSFile$.$OUTPUT$>;\n";
|
||||
auto meta_data = GenerateMetaData() + ", ";
|
||||
auto options = GenerateOptions() + ", ";
|
||||
printer->Print(vars, (main + callback).c_str());
|
||||
printer->Print(vars, (main + meta_data + callback).c_str());
|
||||
printer->Print(vars, (main + options + callback).c_str());
|
||||
printer->Print(vars, (main + meta_data + options + callback).c_str());
|
||||
}
|
||||
|
||||
void GenerateClientReadableStreamInterface(
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
grpc::string main = "$ISPUBLIC$$MethodName$(request: $FBSFile$.$INPUT$, ";
|
||||
grpc::string end_function =
|
||||
"): grpc.ClientReadableStream<$FBSFile$.$OUTPUT$>;\n";
|
||||
auto meta_data = GenerateMetaData();
|
||||
auto options = GenerateOptions();
|
||||
printer->Print(vars, (main + meta_data + end_function).c_str());
|
||||
printer->Print(vars, (main + options + end_function).c_str());
|
||||
}
|
||||
|
||||
void GenerateDepluxStreamInterface(
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
grpc::string main = "$ISPUBLIC$$MethodName$(";
|
||||
grpc::string end_function =
|
||||
"): grpc.ClientDuplexStream<$FBSFile$.$INPUT$, $FBSFile$.$OUTPUT$>;\n";
|
||||
auto meta_data = GenerateMetaData();
|
||||
auto options = GenerateOptions();
|
||||
printer->Print(vars, (main + end_function).c_str());
|
||||
printer->Print(vars, (main + options + end_function).c_str());
|
||||
printer->Print(vars, (main + meta_data +
|
||||
", options?: Partial<grpc.CallOptions>" + end_function)
|
||||
.c_str());
|
||||
}
|
||||
|
||||
void GenerateClientInterface(const grpc_generator::Service *service,
|
||||
grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(vars, "export interface I$ServiceName$Client {\n");
|
||||
printer->Indent();
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
auto method = service->method(it);
|
||||
vars["MethodName"] = method->name();
|
||||
vars["INPUT"] = method->get_input_type_name();
|
||||
vars["OUTPUT"] = method->get_output_type_name();
|
||||
vars["ISPUBLIC"] = "";
|
||||
|
||||
if (method->NoStreaming()) {
|
||||
GenerateUnaryClientInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
if (method->BidiStreaming()) {
|
||||
GenerateDepluxStreamInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method->ClientStreaming()) {
|
||||
GenerateClientWriteStreamInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method->ServerStreaming()) {
|
||||
GenerateClientReadableStreamInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void GenerateClientClassInterface(
|
||||
const grpc_generator::Service *service, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> *dictonary) {
|
||||
auto vars = *dictonary;
|
||||
printer->Print(vars,
|
||||
"export class $ServiceName$Client extends grpc.Client "
|
||||
"implements I$ServiceName$Client {\n");
|
||||
printer->Indent();
|
||||
printer->Print(
|
||||
"constructor(address: string, credentials: grpc.ChannelCredentials, "
|
||||
"options?: object);");
|
||||
for (auto it = 0; it < service->method_count(); it++) {
|
||||
auto method = service->method(it);
|
||||
vars["MethodName"] = method->name();
|
||||
vars["INPUT"] = method->get_input_type_name();
|
||||
vars["OUTPUT"] = method->get_output_type_name();
|
||||
vars["ISPUBLIC"] = "public ";
|
||||
if (method->NoStreaming()) {
|
||||
GenerateUnaryClientInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
if (method->BidiStreaming()) {
|
||||
GenerateDepluxStreamInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method->ClientStreaming()) {
|
||||
GenerateClientWriteStreamInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method->ServerStreaming()) {
|
||||
GenerateClientReadableStreamInterface(printer, &vars);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
grpc::string GenerateInterface(grpc_generator::File *file,
|
||||
const grpc_generator::Service *service,
|
||||
const grpc::string &filename) {
|
||||
grpc::string output;
|
||||
|
||||
std::set<grpc::string> generated_functions;
|
||||
std::map<grpc::string, grpc::string> vars;
|
||||
|
||||
vars["PATH"] = file->package();
|
||||
|
||||
if (!file->package().empty()) { vars["PATH"].append("."); }
|
||||
|
||||
vars["ServiceName"] = service->name();
|
||||
vars["FBSFile"] = service->name() + "_fbs";
|
||||
vars["Filename"] = filename;
|
||||
auto printer = file->CreatePrinter(&output);
|
||||
|
||||
GenerateImports(&*printer, &vars, false);
|
||||
GenerateMainInterface(service, &*printer, &vars);
|
||||
printer->Print("\n");
|
||||
GenerateClientInterface(service, &*printer, &vars);
|
||||
printer->Print("\n");
|
||||
GenerateClientClassInterface(service, &*printer, &vars);
|
||||
return output;
|
||||
}
|
||||
} // namespace grpc_ts_generator
|
||||
61
grpc/src/compiler/ts_generator.h
Normal file
61
grpc/src/compiler/ts_generator.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2020, 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 <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "src/compiler/config.h"
|
||||
#include "src/compiler/schema_interface.h"
|
||||
|
||||
#ifndef GRPC_CUSTOM_STRING
|
||||
# include <string>
|
||||
# define GRPC_CUSTOM_STRING std::string
|
||||
#endif
|
||||
|
||||
namespace grpc {
|
||||
|
||||
typedef GRPC_CUSTOM_STRING string;
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
namespace grpc_ts_generator {
|
||||
grpc::string Generate(grpc_generator::File *file,
|
||||
const grpc_generator::Service *service,
|
||||
const grpc::string &filename);
|
||||
|
||||
grpc::string GenerateInterface(grpc_generator::File *file,
|
||||
const grpc_generator::Service *service,
|
||||
const grpc::string &filename);
|
||||
} // namespace grpc_ts_generator
|
||||
|
||||
Reference in New Issue
Block a user