This repository was archived by the owner on May 22, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgrpc_client.go
More file actions
97 lines (77 loc) · 3.07 KB
/
Copy pathgrpc_client.go
File metadata and controls
97 lines (77 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package grpcake
import (
"context"
"fmt"
"github.com/jhump/protoreflect/grpcreflect"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/dynamicpb"
"github.com/moneyforward/grpcake/internal/grpcdynamic"
)
// GrpcClient invokes grpc method on a remote server dynamically, without the need for
// protobuf code generation.
type GrpcClient struct {
descriptorSource DescriptorSource
client grpcdynamic.Stub
}
// NewGrpcClient ...
func NewGrpcClient(ctx context.Context, url string, descSource DescriptorSource) (*GrpcClient, error) {
conn, err := grpc.Dial(url, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, fmt.Errorf("error connecting to grpc server: %v", err)
}
client := grpcdynamic.NewStub(conn)
return &GrpcClient{descriptorSource: descSource, client: client}, nil
}
// NewGrpcClientFromReflection ...
func NewGrpcClientFromReflection(ctx context.Context, url string) (*GrpcClient, error) {
conn, err := grpc.Dial(url, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, fmt.Errorf("error connecting to grpc server: %v", err)
}
refClient := grpcreflect.NewClientV1Alpha(ctx, reflectpb.NewServerReflectionClient(conn))
reflSource := DescriptorSourceFromServer(ctx, refClient)
descSource := reflSource
client := grpcdynamic.NewStub(conn)
return &GrpcClient{
descriptorSource: descSource,
client: client,
}, nil
}
// NewGrpcClientFromProtoFiles ...
func NewGrpcClientFromProtoFiles(ctx context.Context, url string, importPaths, fileNames []string) (*GrpcClient, error) {
if len(fileNames) == 0 {
return nil, fmt.Errorf("error received empty list of files")
}
fileSource, err := DescriptorSourceFromProtoFiles(ctx, importPaths, fileNames)
if err != nil {
return nil, fmt.Errorf("failed to process proto source files: %s", err)
}
return NewGrpcClient(ctx, url, fileSource)
}
// Send ...
func (g *GrpcClient) Send(ctx context.Context, serviceName, methodName, jsonBody string) (proto.Message, error) {
serviceDescriptor, err := g.descriptorSource.FindServiceDescriptor(serviceName)
if serviceDescriptor == nil || err != nil {
return nil, fmt.Errorf("error finding service with name %s: %s", serviceName, err)
}
methodDescriptor := serviceDescriptor.Methods().ByName(protoreflect.Name(methodName))
if methodDescriptor == nil {
return nil, fmt.Errorf("error finding method with name %s", methodName)
}
reqMsg := dynamicpb.NewMessage(methodDescriptor.Input())
err = protojson.Unmarshal([]byte(jsonBody), reqMsg)
if err != nil {
return nil, fmt.Errorf("error unmarshalling json body to protobuf message: %v", err)
}
// TODO:
resMsg, err := g.client.InvokeRpc(context.Background(), methodDescriptor, reqMsg)
if err != nil {
return nil, fmt.Errorf("error sending grpc request: %v", err)
}
return resMsg, nil
}