mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
cbb4aed0b4
full diff: https://github.com/containerd/ttrpc/compare/v1.0.2...v1.1.0 - client: Handle sending/receiving in separate goroutines - Return Unimplemented when services or methods are not implemented - go.mod: sirupsen/logrus v1.7.0 - go.mod: update dependencies - go.mod: github.com/gogo/protobuf v1.3.2 - go.mod: google.golang.org/grpc v1.27.1 - go.mod: google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 - go.mod: github.com/prometheus/procfs v0.6.0 - replace pkg/errors - Rename branch from master to main - Use GitHub Actions for CI - Make "go test" and "go build" work on macOS - Add protoc-gen-go-ttrpc Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
166 lines
4 KiB
Go
166 lines
4 KiB
Go
/*
|
|
Copyright The containerd 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.
|
|
*/
|
|
|
|
package ttrpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"unsafe"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
type Method func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error)
|
|
|
|
type ServiceDesc struct {
|
|
Methods map[string]Method
|
|
|
|
// TODO(stevvooe): Add stream support.
|
|
}
|
|
|
|
type serviceSet struct {
|
|
services map[string]ServiceDesc
|
|
interceptor UnaryServerInterceptor
|
|
}
|
|
|
|
func newServiceSet(interceptor UnaryServerInterceptor) *serviceSet {
|
|
return &serviceSet{
|
|
services: make(map[string]ServiceDesc),
|
|
interceptor: interceptor,
|
|
}
|
|
}
|
|
|
|
func (s *serviceSet) register(name string, methods map[string]Method) {
|
|
if _, ok := s.services[name]; ok {
|
|
panic(fmt.Errorf("duplicate service %v registered", name))
|
|
}
|
|
|
|
s.services[name] = ServiceDesc{
|
|
Methods: methods,
|
|
}
|
|
}
|
|
|
|
func (s *serviceSet) call(ctx context.Context, serviceName, methodName string, p []byte) ([]byte, *status.Status) {
|
|
p, err := s.dispatch(ctx, serviceName, methodName, p)
|
|
st, ok := status.FromError(err)
|
|
if !ok {
|
|
st = status.New(convertCode(err), err.Error())
|
|
}
|
|
|
|
return p, st
|
|
}
|
|
|
|
func (s *serviceSet) dispatch(ctx context.Context, serviceName, methodName string, p []byte) ([]byte, error) {
|
|
method, err := s.resolve(serviceName, methodName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
unmarshal := func(obj interface{}) error {
|
|
switch v := obj.(type) {
|
|
case proto.Message:
|
|
if err := proto.Unmarshal(p, v); err != nil {
|
|
return status.Errorf(codes.Internal, "ttrpc: error unmarshalling payload: %v", err.Error())
|
|
}
|
|
default:
|
|
return status.Errorf(codes.Internal, "ttrpc: error unsupported request type: %T", v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
info := &UnaryServerInfo{
|
|
FullMethod: fullPath(serviceName, methodName),
|
|
}
|
|
|
|
resp, err := s.interceptor(ctx, unmarshal, info, method)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if isNil(resp) {
|
|
return nil, errors.New("ttrpc: marshal called with nil")
|
|
}
|
|
|
|
switch v := resp.(type) {
|
|
case proto.Message:
|
|
r, err := proto.Marshal(v)
|
|
if err != nil {
|
|
return nil, status.Errorf(codes.Internal, "ttrpc: error marshaling payload: %v", err.Error())
|
|
}
|
|
|
|
return r, nil
|
|
default:
|
|
return nil, status.Errorf(codes.Internal, "ttrpc: error unsupported response type: %T", v)
|
|
}
|
|
}
|
|
|
|
func (s *serviceSet) resolve(service, method string) (Method, error) {
|
|
srv, ok := s.services[service]
|
|
if !ok {
|
|
return nil, status.Errorf(codes.Unimplemented, "service %v", service)
|
|
}
|
|
|
|
mthd, ok := srv.Methods[method]
|
|
if !ok {
|
|
return nil, status.Errorf(codes.Unimplemented, "method %v", method)
|
|
}
|
|
|
|
return mthd, nil
|
|
}
|
|
|
|
// convertCode maps stdlib go errors into grpc space.
|
|
//
|
|
// This is ripped from the grpc-go code base.
|
|
func convertCode(err error) codes.Code {
|
|
switch err {
|
|
case nil:
|
|
return codes.OK
|
|
case io.EOF:
|
|
return codes.OutOfRange
|
|
case io.ErrClosedPipe, io.ErrNoProgress, io.ErrShortBuffer, io.ErrShortWrite, io.ErrUnexpectedEOF:
|
|
return codes.FailedPrecondition
|
|
case os.ErrInvalid:
|
|
return codes.InvalidArgument
|
|
case context.Canceled:
|
|
return codes.Canceled
|
|
case context.DeadlineExceeded:
|
|
return codes.DeadlineExceeded
|
|
}
|
|
switch {
|
|
case os.IsExist(err):
|
|
return codes.AlreadyExists
|
|
case os.IsNotExist(err):
|
|
return codes.NotFound
|
|
case os.IsPermission(err):
|
|
return codes.PermissionDenied
|
|
}
|
|
return codes.Unknown
|
|
}
|
|
|
|
func fullPath(service, method string) string {
|
|
return "/" + path.Join(service, method)
|
|
}
|
|
|
|
func isNil(resp interface{}) bool {
|
|
return (*[2]uintptr)(unsafe.Pointer(&resp))[1] == 0
|
|
}
|