Skip to content

Commit

Permalink
Merge pull request #13 from join-com/client-integration
Browse files Browse the repository at this point in the history
Client integration
  • Loading branch information
castarco authored Apr 15, 2021
2 parents 1691e90 + 6cb8aa2 commit 82f4f62
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 48 deletions.
110 changes: 105 additions & 5 deletions internal/generator/runer_generate_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,54 @@ import (

func (r *Runner) generateTypescriptServiceDefinitions(generatedFileStream *protogen.GeneratedFile, protoFile *protogen.File) {
for _, serviceSpec := range protoFile.Proto.GetService() {
r.generateTypescriptServiceImplementationInterface(generatedFileStream, serviceSpec)
r.generateTypescriptServiceDefinition(generatedFileStream, serviceSpec)
r.generateTypescriptClient(generatedFileStream, serviceSpec)
}
}

func (r *Runner) generateTypescriptServiceImplementationInterface(generatedFileStream *protogen.GeneratedFile, serviceSpec *descriptorpb.ServiceDescriptorProto) {
r.P(generatedFileStream, "export interface I"+strcase.ToCamel(serviceSpec.GetName())+"ServiceImplementation {")
r.indentLevel += 2

for _, methodSpec := range serviceSpec.GetMethod() {
clientStream := methodSpec.GetClientStreaming()
serverStream := methodSpec.GetServerStreaming()

inputTypeName := methodSpec.GetInputType()
inputInterface := r.getEnumOrMessageTypeName(inputTypeName, true)

outputTypeName := methodSpec.GetOutputType()
outputInterface := r.getEnumOrMessageTypeName(outputTypeName, true)

if !clientStream && !serverStream {
r.P(generatedFileStream, methodSpec.GetName()+": grpc.handleUnaryCall<"+inputInterface+", "+outputInterface+">")
} else if clientStream && serverStream {
r.P(generatedFileStream, methodSpec.GetName()+": grpc.handleBidiStreamingCall<"+inputInterface+", "+outputInterface+">")
} else if clientStream {
r.P(generatedFileStream, methodSpec.GetName()+": grpc.handleClientStreamingCall<"+inputInterface+", "+outputInterface+">")
} else { //if serverStream {
r.P(generatedFileStream, methodSpec.GetName()+": grpc.handleServerStreamingCall<"+inputInterface+", "+outputInterface+">")
}
}

r.indentLevel -= 2
r.P(generatedFileStream, "}\n")
}

func (r *Runner) generateTypescriptServiceDefinition(generatedFileStream *protogen.GeneratedFile, serviceSpec *descriptorpb.ServiceDescriptorProto) {
r.P(generatedFileStream, "export const "+strcase.ToLowerCamel(serviceSpec.GetName())+"ServiceDefinition = {")
r.P(generatedFileStream, "export const "+strcase.ToLowerCamel(serviceSpec.GetName())+"ServiceDefinition: grpc.ServiceDefinition<I"+strcase.ToCamel(serviceSpec.GetName())+"ServiceImplementation> = {")
r.indentLevel += 2

for _, methodSpec := range serviceSpec.GetMethod() {
r.generateTypescriptServiceMethod(generatedFileStream, serviceSpec, methodSpec)
r.generateTypescriptServiceDefinitionMethod(generatedFileStream, serviceSpec, methodSpec)
}

r.indentLevel -= 2
r.P(generatedFileStream, "}\n")
}

func (r *Runner) generateTypescriptServiceMethod(generatedFileStream *protogen.GeneratedFile, serviceSpec *descriptorpb.ServiceDescriptorProto, methodSpec *descriptorpb.MethodDescriptorProto) {
func (r *Runner) generateTypescriptServiceDefinitionMethod(generatedFileStream *protogen.GeneratedFile, serviceSpec *descriptorpb.ServiceDescriptorProto, methodSpec *descriptorpb.MethodDescriptorProto) {
methodName := methodSpec.GetName()

r.P(generatedFileStream, methodName+": {")
Expand All @@ -42,16 +73,85 @@ func (r *Runner) generateTypescriptServiceMethod(generatedFileStream *protogen.G
inputClass := r.getEnumOrMessageTypeName(inputTypeName, false)
r.P(
generatedFileStream,
"requestSerialize: (request: "+inputInterface+") => "+inputClass+".encodePatched(request).finish(),",
"requestSerialize: (request: "+inputInterface+") => "+inputClass+".encodePatched(request).finish() as Buffer,",
)
r.P(generatedFileStream, "requestDeserialize: "+inputClass+".decodePatched,")

outputTypeName := methodSpec.GetOutputType()
outputInterface := r.getEnumOrMessageTypeName(outputTypeName, true)
outputClass := r.getEnumOrMessageTypeName(outputTypeName, false)
r.P(generatedFileStream, "responseSerialize: (response: "+outputInterface+") => "+outputClass+".encodePatched(response).finish(),")
r.P(generatedFileStream, "responseSerialize: (response: "+outputInterface+") => "+outputClass+".encodePatched(response).finish() as Buffer,")
r.P(generatedFileStream, "responseDeserialize: "+outputClass+".decodePatched,")

r.indentLevel -= 2
r.P(generatedFileStream, "},")
}

func (r *Runner) generateTypescriptClient(generatedFileStream *protogen.GeneratedFile, serviceSpec *descriptorpb.ServiceDescriptorProto) {
r.P(
generatedFileStream,
"export class "+strcase.ToCamel(serviceSpec.GetName())+"Client",
"extends joinGRPC.Client<grpc.ServiceDefinition<I"+strcase.ToCamel(serviceSpec.GetName())+"ServiceImplementation>> ",
"implements joinGRPC.IExtendedClient<I"+strcase.ToCamel(serviceSpec.GetName())+"ServiceImplementation> {",
)
r.indentLevel += 2

for _, methodSpec := range serviceSpec.GetMethod() {
r.generateTypescriptClientMethod(generatedFileStream, serviceSpec, methodSpec)
}

r.indentLevel -= 2
r.P(generatedFileStream, "}\n")
}

func (r *Runner) generateTypescriptClientMethod(generatedFileStream *protogen.GeneratedFile, serviceSpec *descriptorpb.ServiceDescriptorProto, methodSpec *descriptorpb.MethodDescriptorProto) {
// Function's Signature
methodName := strcase.ToCamel(methodSpec.GetName())
r.P(generatedFileStream, "public "+methodName+"(")
r.indentLevel += 2

inputTypeName := methodSpec.GetInputType()
inputInterface := r.getEnumOrMessageTypeName(inputTypeName, true)
outputTypeName := methodSpec.GetOutputType()
outputInterface := r.getEnumOrMessageTypeName(outputTypeName, true)

clientStream := methodSpec.GetClientStreaming()
serverStrean := methodSpec.GetServerStreaming()

if !clientStream {
r.P(generatedFileStream, "request: "+inputInterface+",")
}

r.P(generatedFileStream,
"metadata?: Record<string, string>,",
"options?: grpc.CallOptions,",
)

var returnType string
if clientStream && serverStrean {
returnType = "grpc.ClientDuplexStream<" + inputInterface + ", " + outputInterface + ">"
} else if !clientStream && !serverStrean {
returnType = "joinGRPC.IUnaryRequest<" + outputInterface + ">"
} else if clientStream {
returnType = "joinGRPC.IClientStreamRequest<" + inputInterface + ", " + outputInterface + ">"
} else { // if serverStream
returnType = "grpc.ClientReadableStream<" + outputInterface + ">"
}

r.indentLevel -= 2
r.P(generatedFileStream, "): "+returnType+" {")
r.indentLevel += 2

if clientStream && serverStrean {
r.P(generatedFileStream, "return this.makeBidiStreamRequest('"+methodName+"', metadata, options)")
} else if !clientStream && !serverStrean {
r.P(generatedFileStream, "return this.makeUnaryRequest('"+methodName+"', request, metadata, options)")
} else if clientStream {
r.P(generatedFileStream, "return this.makeClientStreamRequest('"+methodName+"', metadata, options)")
} else { // if serverStream
r.P(generatedFileStream, "return this.makeServerStreamRequest('"+methodName+"', request, metadata, options)")
}

r.indentLevel -= 2
r.P(generatedFileStream, "}\n")
}
14 changes: 10 additions & 4 deletions internal/generator/runner_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ func (r *Runner) generateTypescriptFile(protoFile *protogen.File, generatedFileS
// TODO: Generate comment with version, in order to improve traceability & debugging experience
generatedFileStream.P("// GENERATED CODE -- DO NOT EDIT!\n")

r.generateTypescriptImports(protoFile.Desc.Path(), protoFile.Proto.GetDependency(), generatedFileStream)
r.generateTypescriptImports(protoFile, generatedFileStream)
r.generateTypescriptNamespace(generatedFileStream, protoFile)
}

func (r *Runner) generateTypescriptImports(currentSourcePath string, importSourcePaths []string, generatedFileStream *protogen.GeneratedFile) {
func (r *Runner) generateTypescriptImports(protoFile *protogen.File, generatedFileStream *protogen.GeneratedFile) {
currentSourcePath := protoFile.Desc.Path()
importSourcePaths := protoFile.Proto.GetDependency()

// Generic imports
generatedFileStream.P("// import * as joinGRPC from '@join-com/grpc'") // TODO: Remove comment when import is used
generatedFileStream.P("// import * as nodeTrace from '@join-com/node-trace'") // TODO: Remove comment when import is used
if len(protoFile.Proto.GetService()) > 0 {
generatedFileStream.P("// import * as nodeTrace from '@join-com/node-trace'") // TODO: Remove comment when import is used
generatedFileStream.P("import * as joinGRPC from '@join-com/grpc'")
generatedFileStream.P("import { grpc } from '@join-com/grpc'")
}
generatedFileStream.P("import * as protobufjs from 'protobufjs/light'")
generatedFileStream.P("")

Expand Down
84 changes: 74 additions & 10 deletions tests/__tests__/v2/generated/Test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// GENERATED CODE -- DO NOT EDIT!

// import * as joinGRPC from '@join-com/grpc'
// import * as nodeTrace from '@join-com/node-trace'
import * as joinGRPC from '@join-com/grpc'
import { grpc } from '@join-com/grpc'
import * as protobufjs from 'protobufjs/light'

import { GoogleProtobuf } from './google/protobuf/Timestamp'
Expand Down Expand Up @@ -413,50 +414,113 @@ export namespace Foo {
}
}

export const usersServiceDefinition = {
export interface IUsersServiceImplementation {
Find: grpc.handleUnaryCall<IRequest, Common_Common.IOtherPkgMessage>
FindClientStream: grpc.handleClientStreamingCall<
IRequest,
Common_Common.IOtherPkgMessage
>
FindServerStream: grpc.handleServerStreamingCall<
IRequest,
Common_Common.IOtherPkgMessage
>
FindBidiStream: grpc.handleBidiStreamingCall<
IRequest,
Common_Common.IOtherPkgMessage
>
}

export const usersServiceDefinition: grpc.ServiceDefinition<IUsersServiceImplementation> = {
Find: {
path: '/foo.Users/Find',
requestStream: false,
responseStream: false,
requestSerialize: (request: IRequest) =>
Request.encodePatched(request).finish(),
Request.encodePatched(request).finish() as Buffer,
requestDeserialize: Request.decodePatched,
responseSerialize: (response: Common_Common.IOtherPkgMessage) =>
Common_Common.OtherPkgMessage.encodePatched(response).finish(),
Common_Common.OtherPkgMessage.encodePatched(
response
).finish() as Buffer,
responseDeserialize: Common_Common.OtherPkgMessage.decodePatched,
},
FindClientStream: {
path: '/foo.Users/FindClientStream',
requestStream: true,
responseStream: false,
requestSerialize: (request: IRequest) =>
Request.encodePatched(request).finish(),
Request.encodePatched(request).finish() as Buffer,
requestDeserialize: Request.decodePatched,
responseSerialize: (response: Common_Common.IOtherPkgMessage) =>
Common_Common.OtherPkgMessage.encodePatched(response).finish(),
Common_Common.OtherPkgMessage.encodePatched(
response
).finish() as Buffer,
responseDeserialize: Common_Common.OtherPkgMessage.decodePatched,
},
FindServerStream: {
path: '/foo.Users/FindServerStream',
requestStream: false,
responseStream: true,
requestSerialize: (request: IRequest) =>
Request.encodePatched(request).finish(),
Request.encodePatched(request).finish() as Buffer,
requestDeserialize: Request.decodePatched,
responseSerialize: (response: Common_Common.IOtherPkgMessage) =>
Common_Common.OtherPkgMessage.encodePatched(response).finish(),
Common_Common.OtherPkgMessage.encodePatched(
response
).finish() as Buffer,
responseDeserialize: Common_Common.OtherPkgMessage.decodePatched,
},
FindBidiStream: {
path: '/foo.Users/FindBidiStream',
requestStream: true,
responseStream: true,
requestSerialize: (request: IRequest) =>
Request.encodePatched(request).finish(),
Request.encodePatched(request).finish() as Buffer,
requestDeserialize: Request.decodePatched,
responseSerialize: (response: Common_Common.IOtherPkgMessage) =>
Common_Common.OtherPkgMessage.encodePatched(response).finish(),
Common_Common.OtherPkgMessage.encodePatched(
response
).finish() as Buffer,
responseDeserialize: Common_Common.OtherPkgMessage.decodePatched,
},
}

export class UsersClient
extends joinGRPC.Client<grpc.ServiceDefinition<IUsersServiceImplementation>>
implements joinGRPC.IExtendedClient<IUsersServiceImplementation> {
public Find(
request: IRequest,
metadata?: Record<string, string>,
options?: grpc.CallOptions
): joinGRPC.IUnaryRequest<Common_Common.IOtherPkgMessage> {
return this.makeUnaryRequest('Find', request, metadata, options)
}

public FindClientStream(
metadata?: Record<string, string>,
options?: grpc.CallOptions
): joinGRPC.IClientStreamRequest<IRequest, Common_Common.IOtherPkgMessage> {
return this.makeClientStreamRequest('FindClientStream', metadata, options)
}

public FindServerStream(
request: IRequest,
metadata?: Record<string, string>,
options?: grpc.CallOptions
): grpc.ClientReadableStream<Common_Common.IOtherPkgMessage> {
return this.makeServerStreamRequest(
'FindServerStream',
request,
metadata,
options
)
}

public FindBidiStream(
metadata?: Record<string, string>,
options?: grpc.CallOptions
): grpc.ClientDuplexStream<IRequest, Common_Common.IOtherPkgMessage> {
return this.makeBidiStreamRequest('FindBidiStream', metadata, options)
}
}
}
2 changes: 0 additions & 2 deletions tests/__tests__/v2/generated/common/Common.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// GENERATED CODE -- DO NOT EDIT!

// import * as joinGRPC from '@join-com/grpc'
// import * as nodeTrace from '@join-com/node-trace'
import * as protobufjs from 'protobufjs/light'

// eslint-disable-next-line @typescript-eslint/no-namespace
Expand Down
2 changes: 0 additions & 2 deletions tests/__tests__/v2/generated/common/Extra.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// GENERATED CODE -- DO NOT EDIT!

// import * as joinGRPC from '@join-com/grpc'
// import * as nodeTrace from '@join-com/node-trace'
import * as protobufjs from 'protobufjs/light'

import { GoogleProtobuf } from '../google/protobuf/Timestamp'
Expand Down
2 changes: 0 additions & 2 deletions tests/__tests__/v2/generated/google/protobuf/Timestamp.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// GENERATED CODE -- DO NOT EDIT!

// import * as joinGRPC from '@join-com/grpc'
// import * as nodeTrace from '@join-com/node-trace'
import * as protobufjs from 'protobufjs/light'

// eslint-disable-next-line @typescript-eslint/no-namespace
Expand Down
2 changes: 1 addition & 1 deletion tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"dependencies": {
"@join-com/gcloud-logger-trace": "^0.1.17",
"@join-com/grpc": "^0.1.0",
"@join-com/grpc": "^0.1.1",
"@join-com/grpc-ts": "^2.0.2",
"grpc": "^1.24.6",
"protobufjs": "^6.10.2"
Expand Down
Loading

0 comments on commit 82f4f62

Please sign in to comment.