
By defining a concrete, non-protobuf type for the events interface, we can completely decouple it from the grpc packages that are expensive at runtime. This does requires some allocation cost for converting between types, but the saving for the size of the shim are worth it. Signed-off-by: Stephen J Day <stephen.day@docker.com>
93 lines
2.2 KiB
Go
93 lines
2.2 KiB
Go
package events
|
|
|
|
import (
|
|
api "github.com/containerd/containerd/api/services/events/v1"
|
|
"github.com/containerd/containerd/errdefs"
|
|
"github.com/containerd/containerd/events"
|
|
"github.com/containerd/containerd/events/exchange"
|
|
"github.com/containerd/containerd/plugin"
|
|
ptypes "github.com/gogo/protobuf/types"
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/net/context"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
func init() {
|
|
plugin.Register(&plugin.Registration{
|
|
Type: plugin.GRPCPlugin,
|
|
ID: "events",
|
|
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
|
|
return NewService(ic.Events), nil
|
|
},
|
|
})
|
|
}
|
|
|
|
type service struct {
|
|
events *exchange.Exchange
|
|
}
|
|
|
|
// NewService returns the GRPC events server
|
|
func NewService(events *exchange.Exchange) api.EventsServer {
|
|
return &service{events: events}
|
|
}
|
|
|
|
func (s *service) Register(server *grpc.Server) error {
|
|
api.RegisterEventsServer(server, s)
|
|
return nil
|
|
}
|
|
|
|
func (s *service) Publish(ctx context.Context, r *api.PublishRequest) (*ptypes.Empty, error) {
|
|
if err := s.events.Publish(ctx, r.Topic, r.Event); err != nil {
|
|
return nil, errdefs.ToGRPC(err)
|
|
}
|
|
|
|
return &ptypes.Empty{}, nil
|
|
}
|
|
|
|
func (s *service) Forward(ctx context.Context, r *api.ForwardRequest) (*ptypes.Empty, error) {
|
|
if err := s.events.Forward(ctx, fromProto(r.Envelope)); err != nil {
|
|
return nil, errdefs.ToGRPC(err)
|
|
}
|
|
|
|
return &ptypes.Empty{}, nil
|
|
}
|
|
|
|
func (s *service) Subscribe(req *api.SubscribeRequest, srv api.Events_SubscribeServer) error {
|
|
ctx, cancel := context.WithCancel(srv.Context())
|
|
defer cancel()
|
|
|
|
eventq, errq := s.events.Subscribe(ctx, req.Filters...)
|
|
for {
|
|
select {
|
|
case ev := <-eventq:
|
|
if err := srv.Send(toProto(ev)); err != nil {
|
|
return errors.Wrapf(err, "failed sending event to subscriber")
|
|
}
|
|
case err := <-errq:
|
|
if err != nil {
|
|
return errors.Wrapf(err, "subscription error")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func toProto(env *events.Envelope) *api.Envelope {
|
|
return &api.Envelope{
|
|
Timestamp: env.Timestamp,
|
|
Namespace: env.Namespace,
|
|
Topic: env.Topic,
|
|
Event: env.Event,
|
|
}
|
|
}
|
|
|
|
func fromProto(env *api.Envelope) *events.Envelope {
|
|
return &events.Envelope{
|
|
Timestamp: env.Timestamp,
|
|
Namespace: env.Namespace,
|
|
Topic: env.Topic,
|
|
Event: env.Event,
|
|
}
|
|
}
|