github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/router/client/client.go (about) 1 package client 2 3 import ( 4 "net/http" 5 "sync" 6 7 pb "github.com/tickoalcantara12/micro/v3/proto/router" 8 "github.com/tickoalcantara12/micro/v3/service/client" 9 "github.com/tickoalcantara12/micro/v3/service/context" 10 "github.com/tickoalcantara12/micro/v3/service/errors" 11 "github.com/tickoalcantara12/micro/v3/service/router" 12 ) 13 14 var ( 15 // name of the router service 16 name = "router" 17 ) 18 19 type svc struct { 20 sync.RWMutex 21 opts router.Options 22 callOpts []client.CallOption 23 router pb.RouterService 24 table *table 25 exit chan bool 26 errChan chan error 27 } 28 29 // NewRouter creates new service router and returns it 30 func NewRouter(opts ...router.Option) router.Router { 31 // get default options 32 options := router.DefaultOptions() 33 34 // apply requested options 35 for _, o := range opts { 36 o(&options) 37 } 38 39 s := &svc{ 40 opts: options, 41 router: pb.NewRouterService(name, client.DefaultClient), 42 } 43 44 // set the router address to call 45 if len(options.Address) > 0 { 46 s.callOpts = []client.CallOption{ 47 client.WithAddress(options.Address), 48 client.WithAuthToken(), 49 } 50 } 51 // set the table 52 s.table = &table{ 53 pb.NewTableService(name, client.DefaultClient), 54 s.callOpts, 55 } 56 57 return s 58 } 59 60 // Init initializes router with given options 61 func (s *svc) Init(opts ...router.Option) error { 62 s.Lock() 63 defer s.Unlock() 64 65 for _, o := range opts { 66 o(&s.opts) 67 } 68 69 return nil 70 } 71 72 // Options returns router options 73 func (s *svc) Options() router.Options { 74 s.Lock() 75 opts := s.opts 76 s.Unlock() 77 78 return opts 79 } 80 81 // Table returns routing table 82 func (s *svc) Table() router.Table { 83 return s.table 84 } 85 86 // Remote router cannot be closed 87 func (s *svc) Close() error { 88 s.Lock() 89 defer s.Unlock() 90 91 select { 92 case <-s.exit: 93 return nil 94 default: 95 close(s.exit) 96 } 97 98 return nil 99 } 100 101 // Lookup looks up routes in the routing table and returns them 102 func (s *svc) Lookup(service string, q ...router.LookupOption) ([]router.Route, error) { 103 // call the router 104 query := router.NewLookup(q...) 105 106 resp, err := s.router.Lookup(context.DefaultContext, &pb.LookupRequest{ 107 Service: service, 108 Options: &pb.LookupOptions{ 109 Address: query.Address, 110 Gateway: query.Gateway, 111 Network: query.Network, 112 Router: query.Router, 113 Link: query.Link, 114 }, 115 }, s.callOpts...) 116 117 if verr := errors.FromError(err); verr != nil && verr.Code == http.StatusNotFound { 118 return nil, router.ErrRouteNotFound 119 } else if err != nil { 120 return nil, err 121 } 122 123 routes := make([]router.Route, len(resp.Routes)) 124 for i, route := range resp.Routes { 125 routes[i] = router.Route{ 126 Service: route.Service, 127 Address: route.Address, 128 Gateway: route.Gateway, 129 Network: route.Network, 130 Link: route.Link, 131 Metric: route.Metric, 132 Metadata: route.Metadata, 133 } 134 } 135 136 return routes, nil 137 } 138 139 // Watch returns a watcher which allows to track updates to the routing table 140 func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) { 141 rsp, err := s.router.Watch(context.DefaultContext, &pb.WatchRequest{}, s.callOpts...) 142 if err != nil { 143 return nil, err 144 } 145 options := router.WatchOptions{ 146 Service: "*", 147 } 148 for _, o := range opts { 149 o(&options) 150 } 151 return newWatcher(rsp, options) 152 } 153 154 // Returns the router implementation 155 func (s *svc) String() string { 156 return "service" 157 }