refactored decoders for reusability
This commit is contained in:
parent
9d7611916b
commit
18a4b67748
16
pkg/decoders/maps.go
Normal file
16
pkg/decoders/maps.go
Normal file
@ -0,0 +1,16 @@
|
||||
package decoders
|
||||
|
||||
// MapGet retrievs a key from an expected map
|
||||
// it falls back if the input is not a map
|
||||
// or the key was not found.
|
||||
func MapGet(m interface{}, key string, fallback interface{}) interface{} {
|
||||
smap, ok := m.(map[string]interface{})
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
val, ok := smap[key]
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return val
|
||||
}
|
85
pkg/decoders/types.go
Normal file
85
pkg/decoders/types.go
Normal file
@ -0,0 +1,85 @@
|
||||
package decoders
|
||||
|
||||
// Decode interfaces into expected types
|
||||
// with a fallback.
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// String asserts a string, provided a default
|
||||
func String(value interface{}, fallback string) string {
|
||||
sval, ok := value.(string)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return sval
|
||||
}
|
||||
|
||||
// StringList decodes a list of strings
|
||||
func StringList(data interface{}) []string {
|
||||
list := []string{}
|
||||
ldata, ok := data.([]interface{})
|
||||
if !ok {
|
||||
return []string{}
|
||||
}
|
||||
for _, e := range ldata {
|
||||
s, ok := e.(string)
|
||||
if ok {
|
||||
list = append(list, s)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// IntList decodes a list of integers
|
||||
func IntList(data interface{}) []int {
|
||||
list := []int{}
|
||||
sdata := StringList(data)
|
||||
for _, e := range sdata {
|
||||
val, _ := strconv.Atoi(e)
|
||||
list = append(list, val)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Int decodes an integer value
|
||||
func Int(value interface{}, fallback int) int {
|
||||
fval, ok := value.(float64)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return int(fval)
|
||||
}
|
||||
|
||||
// Bool decodes a boolean value
|
||||
func Bool(value interface{}, fallback bool) bool {
|
||||
val, ok := value.(bool)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Duration decodes a time.Duration
|
||||
func Duration(value interface{}, fallback time.Duration) time.Duration {
|
||||
val, ok := value.(time.Duration)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// TimeUTC returns the time expecting an UTC timestamp
|
||||
func TimeUTC(value interface{}, fallback time.Time) time.Time {
|
||||
sval := String(value, "")
|
||||
if sval == "" {
|
||||
return fallback
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339Nano, sval)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return t
|
||||
}
|
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
"github.com/alice-lg/alice-lg/pkg/decoders"
|
||||
)
|
||||
|
||||
// Convert server time string to time
|
||||
@ -136,9 +137,9 @@ func parseBirdwatcherStatus(bird ClientResponse, config Config) (api.Status, err
|
||||
LastReboot: lastReboot,
|
||||
LastReconfig: lastReconfig,
|
||||
Backend: "bird",
|
||||
Version: mustString(birdStatus["version"], "unknown"),
|
||||
Message: mustString(birdStatus["message"], "unknown"),
|
||||
RouterId: mustString(birdStatus["router_id"], "unknown"),
|
||||
Version: decoders.String(birdStatus["version"], "unknown"),
|
||||
Message: decoders.String(birdStatus["message"], "unknown"),
|
||||
RouterId: decoders.String(birdStatus["router_id"], "unknown"),
|
||||
}
|
||||
|
||||
return status, nil
|
||||
@ -162,7 +163,7 @@ func parseNeighbours(bird ClientResponse, config Config) (api.Neighbours, error)
|
||||
routes := protocol["routes"].(map[string]interface{})
|
||||
|
||||
uptime := parseRelativeServerTime(protocol["state_changed"], config)
|
||||
lastError := mustString(protocol["last_error"], "")
|
||||
lastError := decoders.String(protocol["last_error"], "")
|
||||
|
||||
routesReceived := float64(0)
|
||||
if routes != nil {
|
||||
@ -177,17 +178,17 @@ func parseNeighbours(bird ClientResponse, config Config) (api.Neighbours, error)
|
||||
neighbour := &api.Neighbour{
|
||||
Id: protocolId,
|
||||
|
||||
Address: mustString(protocol["neighbor_address"], "error"),
|
||||
Asn: mustInt(protocol["neighbor_as"], 0),
|
||||
Address: decoders.String(protocol["neighbor_address"], "error"),
|
||||
Asn: decoders.Int(protocol["neighbor_as"], 0),
|
||||
State: strings.ToLower(
|
||||
mustString(protocol["state"], "unknown")),
|
||||
Description: mustString(protocol["description"], "no description"),
|
||||
decoders.String(protocol["state"], "unknown")),
|
||||
Description: decoders.String(protocol["description"], "no description"),
|
||||
|
||||
RoutesReceived: mustInt(routesReceived, 0),
|
||||
RoutesAccepted: mustInt(routes["imported"], 0),
|
||||
RoutesFiltered: mustInt(routes["filtered"], 0),
|
||||
RoutesExported: mustInt(routes["exported"], 0), //TODO protocol_exported?
|
||||
RoutesPreferred: mustInt(routes["preferred"], 0),
|
||||
RoutesReceived: decoders.Int(routesReceived, 0),
|
||||
RoutesAccepted: decoders.Int(routes["imported"], 0),
|
||||
RoutesFiltered: decoders.Int(routes["filtered"], 0),
|
||||
RoutesExported: decoders.Int(routes["exported"], 0), //TODO protocol_exported?
|
||||
RoutesPreferred: decoders.Int(routes["preferred"], 0),
|
||||
|
||||
Uptime: uptime,
|
||||
LastError: lastError,
|
||||
@ -218,7 +219,7 @@ func parseNeighboursShort(bird ClientResponse, config Config) (api.NeighboursSta
|
||||
|
||||
neighbour := &api.NeighbourStatus{
|
||||
Id: protocolId,
|
||||
State: mustString(protocol["state"], "unknown"),
|
||||
State: decoders.String(protocol["state"], "unknown"),
|
||||
Since: uptime,
|
||||
}
|
||||
|
||||
@ -238,18 +239,18 @@ func parseRouteBgpInfo(data interface{}) api.BgpInfo {
|
||||
return api.BgpInfo{}
|
||||
}
|
||||
|
||||
asPath := mustIntList(bgpData["as_path"])
|
||||
asPath := decoders.IntList(bgpData["as_path"])
|
||||
communities := parseBgpCommunities(bgpData["communities"])
|
||||
largeCommunities := parseBgpCommunities(bgpData["large_communities"])
|
||||
extCommunities := parseExtBgpCommunities(bgpData["ext_communities"])
|
||||
|
||||
localPref, _ := strconv.Atoi(mustString(bgpData["local_pref"], "0"))
|
||||
med, _ := strconv.Atoi(mustString(bgpData["med"], "0"))
|
||||
localPref, _ := strconv.Atoi(decoders.String(bgpData["local_pref"], "0"))
|
||||
med, _ := strconv.Atoi(decoders.String(bgpData["med"], "0"))
|
||||
|
||||
bgp := api.BgpInfo{
|
||||
Origin: mustString(bgpData["origin"], "unknown"),
|
||||
Origin: decoders.String(bgpData["origin"], "unknown"),
|
||||
AsPath: asPath,
|
||||
NextHop: mustString(bgpData["next_hop"], "unknown"),
|
||||
NextHop: decoders.String(bgpData["next_hop"], "unknown"),
|
||||
LocalPref: localPref,
|
||||
Med: med,
|
||||
Communities: communities,
|
||||
@ -312,18 +313,18 @@ func parseRoutesData(birdRoutes []interface{}, config Config) api.Routes {
|
||||
rdata := data.(map[string]interface{})
|
||||
|
||||
age := parseRelativeServerTime(rdata["age"], config)
|
||||
rtype := mustStringList(rdata["type"])
|
||||
rtype := decoders.StringList(rdata["type"])
|
||||
bgpInfo := parseRouteBgpInfo(rdata["bgp"])
|
||||
|
||||
route := &api.Route{
|
||||
Id: mustString(rdata["network"], "unknown"),
|
||||
NeighbourId: mustString(rdata["from_protocol"], "unknown neighbour"),
|
||||
Id: decoders.String(rdata["network"], "unknown"),
|
||||
NeighbourId: decoders.String(rdata["from_protocol"], "unknown neighbour"),
|
||||
|
||||
Network: mustString(rdata["network"], "unknown net"),
|
||||
Interface: mustString(rdata["interface"], "unknown interface"),
|
||||
Gateway: mustString(rdata["gateway"], "unknown gateway"),
|
||||
Metric: mustInt(rdata["metric"], -1),
|
||||
Primary: mustBool(rdata["primary"], false),
|
||||
Network: decoders.String(rdata["network"], "unknown net"),
|
||||
Interface: decoders.String(rdata["interface"], "unknown interface"),
|
||||
Gateway: decoders.String(rdata["gateway"], "unknown gateway"),
|
||||
Metric: decoders.Int(rdata["metric"], -1),
|
||||
Primary: decoders.Bool(rdata["primary"], false),
|
||||
Age: age,
|
||||
Type: rtype,
|
||||
Bgp: bgpInfo,
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
"github.com/alice-lg/alice-lg/pkg/decoders"
|
||||
)
|
||||
|
||||
type MultiTableBirdwatcher struct {
|
||||
@ -238,7 +239,7 @@ func (self *MultiTableBirdwatcher) fetchRequiredRoutes(neighborId string) (*api.
|
||||
importedRoutes := api.Routes{}
|
||||
if len(receivedRoutes) > 0 {
|
||||
peer := receivedRoutes[0].Gateway
|
||||
learntFrom := mustString(receivedRoutes[0].Details["learnt_from"], peer)
|
||||
learntFrom := decoders.String(receivedRoutes[0].Details["learnt_from"], peer)
|
||||
|
||||
filteredRoutes = self.filterRoutesByPeerOrLearntFrom(filteredRoutes, peer, learntFrom)
|
||||
importedRoutes = self.filterRoutesByDuplicates(receivedRoutes, filteredRoutes)
|
||||
@ -506,7 +507,7 @@ func (self *MultiTableBirdwatcher) AllRoutes() (*api.RoutesResponse, error) {
|
||||
protocolsBgp := self.filterProtocolsBgp(birdProtocols)
|
||||
for protocolId, protocolsData := range protocolsBgp["protocols"].(map[string]interface{}) {
|
||||
peer := protocolsData.(map[string]interface{})["neighbor_address"].(string)
|
||||
learntFrom := mustString(protocolsData.(map[string]interface{})["learnt_from"], peer)
|
||||
learntFrom := decoders.String(protocolsData.(map[string]interface{})["learnt_from"], peer)
|
||||
|
||||
// Fetch filtered routes
|
||||
_, filtered, err := self.fetchFilteredRoutes(protocolId)
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
"github.com/alice-lg/alice-lg/pkg/decoders"
|
||||
)
|
||||
|
||||
type SingleTableBirdwatcher struct {
|
||||
@ -119,7 +120,7 @@ func (self *SingleTableBirdwatcher) fetchRequiredRoutes(neighborId string) (*api
|
||||
importedRoutes := api.Routes{}
|
||||
if len(receivedRoutes) > 0 {
|
||||
peer := receivedRoutes[0].Gateway
|
||||
learntFrom := mustString(receivedRoutes[0].Details["learnt_from"], peer)
|
||||
learntFrom := decoders.String(receivedRoutes[0].Details["learnt_from"], peer)
|
||||
|
||||
filteredRoutes = self.filterRoutesByPeerOrLearntFrom(filteredRoutes, peer, learntFrom)
|
||||
importedRoutes = self.filterRoutesByDuplicates(receivedRoutes, filteredRoutes)
|
||||
|
@ -1,61 +0,0 @@
|
||||
package birdwatcher
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
/*
|
||||
* Types helper for parser
|
||||
*/
|
||||
|
||||
// Assert string, provide default
|
||||
func mustString(value interface{}, fallback string) string {
|
||||
sval, ok := value.(string)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return sval
|
||||
}
|
||||
|
||||
// Assert list of strings
|
||||
func mustStringList(data interface{}) []string {
|
||||
list := []string{}
|
||||
ldata, ok := data.([]interface{})
|
||||
if !ok {
|
||||
return []string{}
|
||||
}
|
||||
for _, e := range ldata {
|
||||
s, ok := e.(string)
|
||||
if ok {
|
||||
list = append(list, s)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Convert list of strings to int
|
||||
func mustIntList(data interface{}) []int {
|
||||
list := []int{}
|
||||
sdata := mustStringList(data)
|
||||
for _, e := range sdata {
|
||||
val, _ := strconv.Atoi(e)
|
||||
list = append(list, val)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func mustInt(value interface{}, fallback int) int {
|
||||
fval, ok := value.(float64)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return int(fval)
|
||||
}
|
||||
|
||||
func mustBool(value interface{}, fallback bool) bool {
|
||||
val, ok := value.(bool)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
return val
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user