summaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/containerd/ttrpc/services.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/containerd/ttrpc/services.go')
-rw-r--r--vendor/github.com/containerd/ttrpc/services.go150
1 files changed, 150 insertions, 0 deletions
diff --git a/vendor/github.com/containerd/ttrpc/services.go b/vendor/github.com/containerd/ttrpc/services.go
new file mode 100644
index 000000000..e90963825
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/services.go
@@ -0,0 +1,150 @@
+/*
+ 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"
+ "io"
+ "os"
+ "path"
+
+ "github.com/gogo/protobuf/proto"
+ "github.com/pkg/errors"
+ "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
+}
+
+func newServiceSet() *serviceSet {
+ return &serviceSet{
+ services: make(map[string]ServiceDesc),
+ }
+}
+
+func (s *serviceSet) register(name string, methods map[string]Method) {
+ if _, ok := s.services[name]; ok {
+ panic(errors.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 unmarshaling payload: %v", err.Error())
+ }
+ default:
+ return status.Errorf(codes.Internal, "ttrpc: error unsupported request type: %T", v)
+ }
+ return nil
+ }
+
+ resp, err := method(ctx, unmarshal)
+ if err != nil {
+ return nil, err
+ }
+
+ 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.NotFound, "service %v", service)
+ }
+
+ mthd, ok := srv.Methods[method]
+ if !ok {
+ return nil, status.Errorf(codes.NotFound, "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)
+}