jrouter/route.go

96 lines
1.7 KiB
Go

package main
import (
"fmt"
"sync"
"time"
"github.com/sfiera/multitalk/pkg/ddp"
)
const maxRouteAge = 10 * time.Minute // TODO: confirm
type Route struct {
Extended bool
NetStart ddp.Network
NetEnd ddp.Network
Peer *peer
Distance uint8
LastSeen time.Time
}
type RoutingTable struct {
mu sync.Mutex
routes map[*Route]struct{}
}
func NewRoutingTable() *RoutingTable {
return &RoutingTable{
routes: make(map[*Route]struct{}),
}
}
func (rt *RoutingTable) LookupRoute(network ddp.Network) *Route {
rt.mu.Lock()
defer rt.mu.Unlock()
var bestRoute *Route
for r := range rt.routes {
if r.Peer == nil {
continue
}
if network < r.NetStart || network > r.NetEnd {
continue
}
if time.Since(r.LastSeen) > maxRouteAge {
continue
}
if bestRoute == nil {
bestRoute = r
continue
}
if r.Distance < bestRoute.Distance {
bestRoute = r
}
}
return bestRoute
}
func (rt *RoutingTable) UpsertRoute(extended bool, netStart, netEnd ddp.Network, peer *peer, metric uint8) error {
if netStart > netEnd {
return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd)
}
// TODO: handle the Update part of "Upsert"
r := &Route{
Extended: extended,
NetStart: netStart,
NetEnd: netEnd,
Peer: peer,
Distance: metric,
LastSeen: time.Now(),
}
rt.mu.Lock()
defer rt.mu.Unlock()
rt.routes[r] = struct{}{}
return nil
}
func (rt *RoutingTable) ValidRoutes() []*Route {
rt.mu.Lock()
defer rt.mu.Unlock()
valid := make([]*Route, 0, len(rt.routes))
for r := range rt.routes {
if r.Peer == nil {
continue
}
if time.Since(r.LastSeen) > maxRouteAge {
continue
}
valid = append(valid, r)
}
return valid
}