1
0
mirror of https://github.com/go-micro/go-micro.git synced 2025-06-18 22:17:44 +02:00

Added Entry type. Basic implementation of Router and Table

This commit is contained in:
Milos Gajdos
2019-06-09 23:09:38 +01:00
parent ad92e6821e
commit 9c57f32f58
6 changed files with 237 additions and 79 deletions

View File

@ -2,7 +2,12 @@ package router
import (
"errors"
"fmt"
"hash/fnv"
"strings"
"sync"
"github.com/olekukonko/tablewriter"
)
var (
@ -10,77 +15,151 @@ var (
ErrRouteNotFound = errors.New("route not found")
// ErrDuplicateRoute is return when route already exists
ErrDuplicateRoute = errors.New("duplicate route")
// ErrNotImplemented is returned when some functionality has not been implemented
ErrNotImplemented = errors.New("not implemented")
)
// Table is routing table
type Table interface {
// Add adds new route to the table
Add(*Entry) error
Add(Entry) error
// Remove removes route from the table
Remove(*Entry) error
Remove(Entry) error
// Update updates route in the table
Update(*Entry) error
Update(...EntryOption) error
// Lookup looks up routes in the table
Lookup(Query) ([]*Entry, error)
Lookup(Query) ([]Entry, error)
// Size returns the size of the table
Size() int
// String prints the routing table
String() string
}
// Entry is micro network routing table entry
type Entry struct {
// Addr is destination address
Addr string
// NetID is micro network ID
NetID string
// Hop is the next route hop
Hop Router
// Metric is route cost metric
Metric int
}
// table is routing table
// It maps service name to routes
type table struct {
// m stores routing table map
m map[string][]Entry
m map[string]map[uint64]Entry
sync.RWMutex
}
// NewTable creates new routing table and returns it
func NewTable() Table {
return &table{
m: make(map[string][]Entry),
m: make(map[string]map[uint64]Entry),
}
}
// Add adds new routing entry
func (t *table) Add(e *Entry) error {
return nil
func (t *table) Add(e Entry) error {
t.Lock()
defer t.Unlock()
destAddr := e.Options().DestAddr
h := fnv.New64()
h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address()))
if _, ok := t.m[destAddr]; !ok {
// create new map for DestAddr routes
t.m[destAddr] = make(map[uint64]Entry)
t.m[destAddr][h.Sum64()] = e
return nil
}
if _, ok := t.m[destAddr][h.Sum64()]; ok && e.Options().Policy == OverrideIfExists {
t.m[destAddr][h.Sum64()] = e
return nil
}
return ErrDuplicateRoute
}
// Remove removes entry from the routing table
func (t *table) Remove(e *Entry) error {
func (t *table) Remove(e Entry) error {
t.Lock()
defer t.Unlock()
destAddr := e.Options().DestAddr
h := fnv.New64()
h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address()))
if _, ok := t.m[destAddr]; !ok {
return ErrRouteNotFound
} else {
delete(t.m[destAddr], h.Sum64())
return nil
}
return nil
}
// Update updates routin entry
func (t *table) Update(e *Entry) error {
return nil
// Update updates routing entry
func (t *table) Update(opts ...EntryOption) error {
t.Lock()
defer t.Unlock()
e := NewEntry(opts...)
destAddr := e.Options().DestAddr
h := fnv.New64()
h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address()))
if _, ok := t.m[destAddr]; !ok {
return ErrRouteNotFound
}
if _, ok := t.m[destAddr][h.Sum64()]; ok {
t.m[destAddr][h.Sum64()] = e
return nil
}
return ErrRouteNotFound
}
// Lookup looks up entry in the routing table
func (t *table) Lookup(q Query) ([]*Entry, error) {
return nil, nil
func (t *table) Lookup(q Query) ([]Entry, error) {
return nil, ErrNotImplemented
}
// Size returns the size of the routing table
func (t *table) Size() int {
t.RLock()
defer t.RUnlock()
return len(t.m)
}
// String returns text representation of routing table
func (t *table) String() string {
return ""
t.RLock()
defer t.RUnlock()
// this will help us build routing table string
sb := &strings.Builder{}
// create nice table printing structure
table := tablewriter.NewWriter(sb)
table.SetHeader([]string{"Dest", "Hop", "Src", "Metric"})
var destAddr, prevAddr string
for _, entries := range t.m {
for _, entry := range entries {
destAddr = entry.Options().DestAddr
// we want to avoid printing the same dest address
if prevAddr == destAddr {
destAddr = ""
}
strEntry := []string{
destAddr,
entry.Options().Hop.Address(),
fmt.Sprintf("%d", entry.Options().SrcAddr),
fmt.Sprintf("%d", entry.Options().Metric),
}
table.Append(strEntry)
prevAddr = destAddr
}
}
return sb.String()
}