gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/router/table.go (about) 1 package router 2 3 import ( 4 "errors" 5 "sync" 6 "time" 7 8 "github.com/google/uuid" 9 "gitee.com/liuxuezhan/go-micro-v1.18.0/util/log" 10 ) 11 12 var ( 13 // ErrRouteNotFound is returned when no route was found in the routing table 14 ErrRouteNotFound = errors.New("route not found") 15 // ErrDuplicateRoute is returned when the route already exists 16 ErrDuplicateRoute = errors.New("duplicate route") 17 ) 18 19 // table is an in-memory routing table 20 type table struct { 21 sync.RWMutex 22 // routes stores service routes 23 routes map[string]map[uint64]Route 24 // watchers stores table watchers 25 watchers map[string]*tableWatcher 26 } 27 28 // newtable creates a new routing table and returns it 29 func newTable(opts ...Option) *table { 30 return &table{ 31 routes: make(map[string]map[uint64]Route), 32 watchers: make(map[string]*tableWatcher), 33 } 34 } 35 36 // sendEvent sends events to all subscribed watchers 37 func (t *table) sendEvent(e *Event) { 38 t.RLock() 39 defer t.RUnlock() 40 41 for _, w := range t.watchers { 42 select { 43 case w.resChan <- e: 44 case <-w.done: 45 } 46 } 47 } 48 49 // Create creates new route in the routing table 50 func (t *table) Create(r Route) error { 51 service := r.Service 52 sum := r.Hash() 53 54 t.Lock() 55 defer t.Unlock() 56 57 // check if there are any routes in the table for the route destination 58 if _, ok := t.routes[service]; !ok { 59 t.routes[service] = make(map[uint64]Route) 60 } 61 62 // add new route to the table for the route destination 63 if _, ok := t.routes[service][sum]; !ok { 64 t.routes[service][sum] = r 65 log.Debugf("Router emitting %s for route: %s", Create, r.Address) 66 go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r}) 67 return nil 68 } 69 70 return ErrDuplicateRoute 71 } 72 73 // Delete deletes the route from the routing table 74 func (t *table) Delete(r Route) error { 75 service := r.Service 76 sum := r.Hash() 77 78 t.Lock() 79 defer t.Unlock() 80 81 if _, ok := t.routes[service]; !ok { 82 return ErrRouteNotFound 83 } 84 85 if _, ok := t.routes[service][sum]; !ok { 86 return ErrRouteNotFound 87 } 88 89 delete(t.routes[service], sum) 90 log.Debugf("Router emitting %s for route: %s", Delete, r.Address) 91 go t.sendEvent(&Event{Type: Delete, Timestamp: time.Now(), Route: r}) 92 93 return nil 94 } 95 96 // Update updates routing table with the new route 97 func (t *table) Update(r Route) error { 98 service := r.Service 99 sum := r.Hash() 100 101 t.Lock() 102 defer t.Unlock() 103 104 // check if the route destination has any routes in the table 105 if _, ok := t.routes[service]; !ok { 106 t.routes[service] = make(map[uint64]Route) 107 } 108 109 if _, ok := t.routes[service][sum]; !ok { 110 t.routes[service][sum] = r 111 log.Debugf("Router emitting %s for route: %s", Update, r.Address) 112 go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r}) 113 return nil 114 } 115 116 // just update the route, but dont emit Update event 117 t.routes[service][sum] = r 118 119 return nil 120 } 121 122 // List returns a list of all routes in the table 123 func (t *table) List() ([]Route, error) { 124 t.RLock() 125 defer t.RUnlock() 126 127 var routes []Route 128 for _, rmap := range t.routes { 129 for _, route := range rmap { 130 routes = append(routes, route) 131 } 132 } 133 134 return routes, nil 135 } 136 137 // isMatch checks if the route matches given query options 138 func isMatch(route Route, address, gateway, network, router string) bool { 139 // matches the values provided 140 match := func(a, b string) bool { 141 if a == "*" || a == b { 142 return true 143 } 144 return false 145 } 146 147 // a simple struct to hold our values 148 type compare struct { 149 a string 150 b string 151 } 152 153 // compare the following values 154 values := []compare{ 155 {gateway, route.Gateway}, 156 {network, route.Network}, 157 {router, route.Router}, 158 {address, route.Address}, 159 } 160 161 for _, v := range values { 162 // attempt to match each value 163 if !match(v.a, v.b) { 164 return false 165 } 166 } 167 168 return true 169 } 170 171 // findRoutes finds all the routes for given network and router and returns them 172 func findRoutes(routes map[uint64]Route, address, gateway, network, router string) []Route { 173 var results []Route 174 for _, route := range routes { 175 if isMatch(route, address, gateway, network, router) { 176 results = append(results, route) 177 } 178 } 179 return results 180 } 181 182 // Lookup queries routing table and returns all routes that match the lookup query 183 func (t *table) Query(q ...QueryOption) ([]Route, error) { 184 t.RLock() 185 defer t.RUnlock() 186 187 // create new query options 188 opts := NewQuery(q...) 189 190 if opts.Service != "*" { 191 if _, ok := t.routes[opts.Service]; !ok { 192 return nil, ErrRouteNotFound 193 } 194 return findRoutes(t.routes[opts.Service], opts.Address, opts.Gateway, opts.Network, opts.Router), nil 195 } 196 197 results := make([]Route, 0, len(t.routes)) 198 // search through all destinations 199 for _, routes := range t.routes { 200 results = append(results, findRoutes(routes, opts.Address, opts.Gateway, opts.Network, opts.Router)...) 201 } 202 203 return results, nil 204 } 205 206 // Watch returns routing table entry watcher 207 func (t *table) Watch(opts ...WatchOption) (Watcher, error) { 208 // by default watch everything 209 wopts := WatchOptions{ 210 Service: "*", 211 } 212 213 for _, o := range opts { 214 o(&wopts) 215 } 216 217 w := &tableWatcher{ 218 id: uuid.New().String(), 219 opts: wopts, 220 resChan: make(chan *Event, 10), 221 done: make(chan struct{}), 222 } 223 224 // when the watcher is stopped delete it 225 go func() { 226 <-w.done 227 t.Lock() 228 delete(t.watchers, w.id) 229 t.Unlock() 230 }() 231 232 // save the watcher 233 t.Lock() 234 t.watchers[w.id] = w 235 t.Unlock() 236 237 return w, nil 238 }