github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/registry/handler/handler.go (about)

     1  package handler
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	pb "github.com/tickoalcantara12/micro/v3/proto/registry"
     8  	"github.com/tickoalcantara12/micro/v3/service"
     9  	"github.com/tickoalcantara12/micro/v3/service/errors"
    10  	log "github.com/tickoalcantara12/micro/v3/service/logger"
    11  	"github.com/tickoalcantara12/micro/v3/service/registry"
    12  	"github.com/tickoalcantara12/micro/v3/service/registry/util"
    13  	"github.com/tickoalcantara12/micro/v3/util/auth/namespace"
    14  )
    15  
    16  type Registry struct {
    17  	// service id
    18  	ID string
    19  	// the event
    20  	Event *service.Event
    21  }
    22  
    23  func ActionToEventType(action string) registry.EventType {
    24  	switch action {
    25  	case "create":
    26  		return registry.Create
    27  	case "delete":
    28  		return registry.Delete
    29  	default:
    30  		return registry.Update
    31  	}
    32  }
    33  
    34  func (r *Registry) publishEvent(action string, service *pb.Service) error {
    35  	// TODO: timestamp should be read from received event
    36  	// Right now registry.Result does not contain timestamp
    37  	event := &pb.Event{
    38  		Id:        r.ID,
    39  		Type:      pb.EventType(ActionToEventType(action)),
    40  		Timestamp: time.Now().UnixNano(),
    41  		Service:   service,
    42  	}
    43  
    44  	log.Debugf("publishing event %s for action %s", event.Id, action)
    45  
    46  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    47  	defer cancel()
    48  
    49  	return r.Event.Publish(ctx, event)
    50  }
    51  
    52  // GetService from the registry with the name requested
    53  func (r *Registry) GetService(ctx context.Context, req *pb.GetRequest, rsp *pb.GetResponse) error {
    54  	// parse the options
    55  	var options registry.GetOptions
    56  	if req.Options != nil && len(req.Options.Domain) > 0 {
    57  		options.Domain = req.Options.Domain
    58  	} else {
    59  		options.Domain = registry.DefaultDomain
    60  	}
    61  
    62  	// authorize the request. Non admins can also do this
    63  	publicNS := namespace.Public(registry.DefaultDomain)
    64  	if err := namespace.Authorize(ctx, options.Domain, "registry.Registry.GetService", publicNS); err != nil {
    65  		return err
    66  	}
    67  
    68  	// get the services in the namespace
    69  	services, err := registry.DefaultRegistry.GetService(req.Service, registry.GetDomain(options.Domain))
    70  	if err == registry.ErrNotFound || len(services) == 0 {
    71  		return errors.NotFound("registry.Registry.GetService", registry.ErrNotFound.Error())
    72  	} else if err != nil {
    73  		return errors.InternalServerError("registry.Registry.GetService", err.Error())
    74  	}
    75  
    76  	// serialize the response
    77  	rsp.Services = make([]*pb.Service, len(services))
    78  	for i, srv := range services {
    79  		rsp.Services[i] = util.ToProto(srv)
    80  	}
    81  
    82  	return nil
    83  }
    84  
    85  // Register a service
    86  func (r *Registry) Register(ctx context.Context, req *pb.Service, rsp *pb.EmptyResponse) error {
    87  	var opts []registry.RegisterOption
    88  	var domain string
    89  
    90  	// parse the options
    91  	if req.Options != nil && req.Options.Ttl > 0 {
    92  		ttl := time.Duration(req.Options.Ttl) * time.Second
    93  		opts = append(opts, registry.RegisterTTL(ttl))
    94  	}
    95  	if req.Options != nil && len(req.Options.Domain) > 0 {
    96  		domain = req.Options.Domain
    97  	} else {
    98  		domain = registry.DefaultDomain
    99  	}
   100  	opts = append(opts, registry.RegisterDomain(domain))
   101  
   102  	// authorize the request
   103  	if err := namespace.AuthorizeAdmin(ctx, domain, "registry.Registry.Register"); err != nil {
   104  		return err
   105  	}
   106  
   107  	// register the service
   108  	if err := registry.DefaultRegistry.Register(util.ToService(req), opts...); err != nil {
   109  		return errors.InternalServerError("registry.Registry.Register", err.Error())
   110  	}
   111  
   112  	// publish the event
   113  	go r.publishEvent("create", req)
   114  
   115  	return nil
   116  }
   117  
   118  // Deregister a service
   119  func (r *Registry) Deregister(ctx context.Context, req *pb.Service, rsp *pb.EmptyResponse) error {
   120  	// parse the options
   121  	var domain string
   122  	if req.Options != nil && len(req.Options.Domain) > 0 {
   123  		domain = req.Options.Domain
   124  	} else {
   125  		domain = registry.DefaultDomain
   126  	}
   127  
   128  	// authorize the request
   129  	if err := namespace.AuthorizeAdmin(ctx, domain, "registry.Registry.Deregister"); err != nil {
   130  		return err
   131  	}
   132  
   133  	// deregister the service
   134  	if err := registry.DefaultRegistry.Deregister(util.ToService(req), registry.DeregisterDomain(domain)); err != nil {
   135  		return errors.InternalServerError("registry.Registry.Deregister", err.Error())
   136  	}
   137  
   138  	// publish the event
   139  	go r.publishEvent("delete", req)
   140  
   141  	return nil
   142  }
   143  
   144  // ListServices returns all the services
   145  func (r *Registry) ListServices(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
   146  	// parse the options
   147  	var domain string
   148  	if req.Options != nil && len(req.Options.Domain) > 0 {
   149  		domain = req.Options.Domain
   150  	} else {
   151  		domain = registry.DefaultDomain
   152  	}
   153  
   154  	// authorize the request. Non admins can also do this
   155  	publicNS := namespace.Public(registry.DefaultDomain)
   156  	if err := namespace.Authorize(ctx, domain, "registry.Registry.ListServices", publicNS); err != nil {
   157  		return err
   158  	}
   159  
   160  	// list the services from the registry
   161  	services, err := registry.DefaultRegistry.ListServices(registry.ListDomain(domain))
   162  	if err != nil {
   163  		return errors.InternalServerError("registry.Registry.ListServices", err.Error())
   164  	}
   165  
   166  	// serialize the response
   167  	rsp.Services = make([]*pb.Service, len(services))
   168  	for i, srv := range services {
   169  		rsp.Services[i] = util.ToProto(srv)
   170  	}
   171  
   172  	return nil
   173  }
   174  
   175  // Watch a service for changes
   176  func (r *Registry) Watch(ctx context.Context, req *pb.WatchRequest, rsp pb.Registry_WatchStream) error {
   177  	// parse the options
   178  	var domain string
   179  	if req.Options != nil && len(req.Options.Domain) > 0 {
   180  		domain = req.Options.Domain
   181  	} else {
   182  		domain = registry.DefaultDomain
   183  	}
   184  
   185  	// authorize the request
   186  	publicNS := namespace.Public(registry.DefaultDomain)
   187  	if err := namespace.Authorize(ctx, domain, "registry.Registry.Watch", publicNS); err != nil {
   188  		return err
   189  	}
   190  
   191  	// setup the watcher
   192  	watcher, err := registry.DefaultRegistry.Watch(registry.WatchService(req.Service), registry.WatchDomain(domain))
   193  	if err != nil {
   194  		return errors.InternalServerError("registry.Registry.Watch", err.Error())
   195  	}
   196  
   197  	for {
   198  		next, err := watcher.Next()
   199  		if err != nil {
   200  			return errors.InternalServerError("registry.Registry.Watch", err.Error())
   201  		}
   202  
   203  		err = rsp.Send(&pb.Result{
   204  			Action:  next.Action,
   205  			Service: util.ToProto(next.Service),
   206  		})
   207  		if err != nil {
   208  			return errors.InternalServerError("registry.Registry.Watch", err.Error())
   209  		}
   210  	}
   211  }