我正在使用 Buf 的connect-go库来实现 gRPC 服务器。
许多 gRPC 调用对时间敏感,因此它们包含一个字段,客户端使用该字段发送其当前时间戳。服务器将客户端时间戳与本地时间戳进行比较,并返回它们之间的差异。这是.proto定义中的示例:
service EventService {
// Start performing a task
rpc Start (StartRequest) returns (StartResponse);
}
message StartRequest {
int64 location_id = 1;
int64 task_id = 2;
Location user_latlng = 3;
google.protobuf.Timestamp now_on_device = 4;
}
message StartResponse {
TaskPerformanceInfo info = 1;
google.protobuf.Duration device_offset = 2;
}
因为我已经为几个 RPC 方法实现了这个,所以我想看看我是否可以使用拦截器来处理它,所以我不需要确保它在所有单独的 RPC 方法实现中都被处理。
由于protoc-gen-go编译器为字段定义 getter 的方式,检查请求消息是否包含now_on_device字段很容易通过定义接口和使用类型断言来完成:
type hasNowOnDevice interface {
GetNowOnDevice() *timestamppb.Timestamp
}
if reqWithNow, ok := req.Any().(hasNowOnDevice); ok {
// ...
}
这使得大部分拦截器非常容易编写:
func MakeDeviceTimeInterceptor() func(connect.UnaryFunc) connect.UnaryFunc {
return connect.UnaryInterceptorFunc(
func(next connect.UnaryFunc) connect.UnaryFunc {
return connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
now := time.Now().UTC()
ctxa := context.WithValue(ctx, CurrentTimestampKey{}, now)
var deviceTimeOffset time.Duration
// If the protobuf message has a `NowOnDevice` field, use it
// to get the difference betweent the device time and server time.
if reqWithNow, ok := req.Any().(hasNowOnDevice); ok {
deviceTime := reqWithNow.GetNowOnDevice().AsTime()
deviceTimeOffset = now.Sub(deviceTime)
ctxa = context.WithValue(ctxa, DeviceTimeDiffKey{}, deviceTimeOffset)
}
res, err := next(ctxa, req)
// TODO: How do I modify the response here?
return res, err
})
},
)
}
我遇到的问题(如上面评论中所述)是如何修改响应。
扬帆大鱼
LEATH
相关分类