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 }