micro/router/table_watcher.go

94 lines
2.0 KiB
Go

package router
import (
"errors"
)
var (
// ErrWatcherStopped is returned when routing table watcher has been stopped
ErrWatcherStopped = errors.New("routing table watcher stopped")
)
// WatchOption is used to define what routes to watch in the table
type WatchOption func(*WatchOptions)
// Watcher defines routing table watcher interface
// Watcher returns updates to the routing table
type Watcher interface {
// Next is a blocking call that returns watch result
Next() (*Result, error)
// Stop stops watcher
Stop()
}
// Result is returned by a call to Next on the watcher.
type Result struct {
// Action is routing table action which is either of add, remove or update
Action string
// Route is table rout
Route Route
}
// Watcher options
type WatchOptions struct {
// Specify destination address to watch
DestAddr string
// Specify network to watch
Network string
}
// WatchDestAddr sets what destination to watch
// Destination is usually microservice name
func WatchDestAddr(a string) WatchOption {
return func(o *WatchOptions) {
o.DestAddr = a
}
}
// WatchNetwork sets what network to watch
func WatchNetwork(n string) WatchOption {
return func(o *WatchOptions) {
o.Network = n
}
}
type tableWatcher struct {
opts WatchOptions
resChan chan *Result
done chan struct{}
}
// TODO: this needs to be thought through properly
// Next returns the next noticed action taken on table
func (w *tableWatcher) Next() (*Result, error) {
for {
select {
case res := <-w.resChan:
switch w.opts.DestAddr {
case "*", "":
if w.opts.Network == "*" || w.opts.Network == res.Route.Options().Network {
return res, nil
}
case res.Route.Options().DestAddr:
if w.opts.Network == "*" || w.opts.Network == res.Route.Options().Network {
return res, nil
}
}
// ignore if no match is found
continue
case <-w.done:
return nil, ErrWatcherStopped
}
}
}
// Stop stops routing table watcher
func (w *tableWatcher) Stop() {
select {
case <-w.done:
return
default:
close(w.done)
}
}