mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-12 06:24:10 +01:00
common/helpers: move bimap and intern to separate packages
subnetmap would be a candidate too, but there are cyclic dependencies because we want diff to handle it correctly.
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Free Mobile
|
// SPDX-FileCopyrightText: 2022 Free Mobile
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
package helpers
|
// Package bimap exposes a bidirectional map structure.
|
||||||
|
package bimap
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
@@ -11,8 +12,8 @@ type Bimap[K, V comparable] struct {
|
|||||||
inverse map[V]K
|
inverse map[V]K
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBimap returns a new bimap from an existing map.
|
// New returns a new bimap from an existing map.
|
||||||
func NewBimap[K, V comparable](input map[K]V) *Bimap[K, V] {
|
func New[K, V comparable](input map[K]V) *Bimap[K, V] {
|
||||||
output := &Bimap[K, V]{
|
output := &Bimap[K, V]{
|
||||||
forward: make(map[K]V),
|
forward: make(map[K]V),
|
||||||
inverse: make(map[V]K),
|
inverse: make(map[V]K),
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Free Mobile
|
// SPDX-FileCopyrightText: 2022 Free Mobile
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
package helpers_test
|
package bimap_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
|
"akvorado/common/helpers/bimap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBimapLoadValue(t *testing.T) {
|
func TestBimapLoadValue(t *testing.T) {
|
||||||
input := helpers.NewBimap(map[int]string{
|
input := bimap.New(map[int]string{
|
||||||
1: "hello",
|
1: "hello",
|
||||||
2: "world",
|
2: "world",
|
||||||
3: "happy",
|
3: "happy",
|
||||||
@@ -38,7 +39,7 @@ func TestBimapLoadValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBimapLoadKey(t *testing.T) {
|
func TestBimapLoadKey(t *testing.T) {
|
||||||
input := helpers.NewBimap(map[int]string{
|
input := bimap.New(map[int]string{
|
||||||
1: "hello",
|
1: "hello",
|
||||||
2: "world",
|
2: "world",
|
||||||
3: "happy",
|
3: "happy",
|
||||||
@@ -65,7 +66,7 @@ func TestBimapLoadKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBimapKeys(t *testing.T) {
|
func TestBimapKeys(t *testing.T) {
|
||||||
input := helpers.NewBimap(map[int]string{
|
input := bimap.New(map[int]string{
|
||||||
1: "hello",
|
1: "hello",
|
||||||
2: "world",
|
2: "world",
|
||||||
3: "happy",
|
3: "happy",
|
||||||
@@ -80,7 +81,7 @@ func TestBimapKeys(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBimapValues(t *testing.T) {
|
func TestBimapValues(t *testing.T) {
|
||||||
input := helpers.NewBimap(map[int]string{
|
input := bimap.New(map[int]string{
|
||||||
1: "hello",
|
1: "hello",
|
||||||
2: "world",
|
2: "world",
|
||||||
3: "happy",
|
3: "happy",
|
||||||
@@ -1,55 +1,57 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Free Mobile
|
// SPDX-FileCopyrightText: 2022 Free Mobile
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
package helpers
|
// Package intern manages a pool of interned values. An interned value is
|
||||||
|
// replaced by a small int.
|
||||||
|
package intern
|
||||||
|
|
||||||
// InternValue is the interface that should be implemented by types
|
// Value is the interface that should be implemented by types
|
||||||
// used in an intern pool. Also, it should be immutable.
|
// used in an intern pool. Also, it should be immutable.
|
||||||
type InternValue[T any] interface {
|
type Value[T any] interface {
|
||||||
Hash() uint64
|
Hash() uint64
|
||||||
Equal(T) bool
|
Equal(T) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// InternReference is a reference to an interned value. 0 is not a
|
// Reference is a reference to an interned value. 0 is not a
|
||||||
// valid reference value.
|
// valid reference value.
|
||||||
type InternReference[T any] uint32
|
type Reference[T any] uint32
|
||||||
|
|
||||||
// InternPool keeps values in a pool by storing only one distinct copy
|
// Pool keeps values in a pool by storing only one distinct copy
|
||||||
// of each. Values will be referred as an uint32 (implemented as an
|
// of each. Values will be referred as an uint32 (implemented as an
|
||||||
// index).
|
// index).
|
||||||
type InternPool[T InternValue[T]] struct {
|
type Pool[T Value[T]] struct {
|
||||||
values []internValue[T]
|
values []internValue[T]
|
||||||
availableIndexes []InternReference[T]
|
availableIndexes []Reference[T]
|
||||||
valueIndexes map[uint64]InternReference[T]
|
valueIndexes map[uint64]Reference[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
// internValue is the value stored in an intern pool. It adds resource
|
// internValue is the value stored in an intern pool. It adds resource
|
||||||
// keeping to the raw value.
|
// keeping to the raw value.
|
||||||
type internValue[T InternValue[T]] struct {
|
type internValue[T Value[T]] struct {
|
||||||
next InternReference[T] // next value with the same hash
|
next Reference[T] // next value with the same hash
|
||||||
previous InternReference[T] // previous value with the same hash
|
previous Reference[T] // previous value with the same hash
|
||||||
refCount uint32
|
refCount uint32
|
||||||
|
|
||||||
value T
|
value T
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInternPool creates a new intern pool.
|
// NewPool creates a new intern pool.
|
||||||
func NewInternPool[T InternValue[T]]() *InternPool[T] {
|
func NewPool[T Value[T]]() *Pool[T] {
|
||||||
return &InternPool[T]{
|
return &Pool[T]{
|
||||||
values: make([]internValue[T], 1), // first slot is reserved
|
values: make([]internValue[T], 1), // first slot is reserved
|
||||||
availableIndexes: make([]InternReference[T], 0),
|
availableIndexes: make([]Reference[T], 0),
|
||||||
valueIndexes: make(map[uint64]InternReference[T]),
|
valueIndexes: make(map[uint64]Reference[T]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get retrieves a (copy of the) value from the intern pool using its reference.
|
// Get retrieves a (copy of the) value from the intern pool using its reference.
|
||||||
func (p *InternPool[T]) Get(ref InternReference[T]) T {
|
func (p *Pool[T]) Get(ref Reference[T]) T {
|
||||||
return p.values[ref].value
|
return p.values[ref].value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take removes a value from the intern pool. If this is the last
|
// Take removes a value from the intern pool. If this is the last
|
||||||
// used reference, it will be deleted from the pool.
|
// used reference, it will be deleted from the pool.
|
||||||
func (p *InternPool[T]) Take(ref InternReference[T]) {
|
func (p *Pool[T]) Take(ref Reference[T]) {
|
||||||
value := &p.values[ref]
|
value := &p.values[ref]
|
||||||
value.refCount--
|
value.refCount--
|
||||||
if value.refCount == 0 {
|
if value.refCount == 0 {
|
||||||
@@ -73,7 +75,7 @@ func (p *InternPool[T]) Take(ref InternReference[T]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ref returns the reference an interned value would have.
|
// Ref returns the reference an interned value would have.
|
||||||
func (p *InternPool[T]) Ref(value T) (InternReference[T], bool) {
|
func (p *Pool[T]) Ref(value T) (Reference[T], bool) {
|
||||||
hash := value.Hash()
|
hash := value.Hash()
|
||||||
if index := p.valueIndexes[hash]; index > 0 {
|
if index := p.valueIndexes[hash]; index > 0 {
|
||||||
for index > 0 {
|
for index > 0 {
|
||||||
@@ -87,7 +89,7 @@ func (p *InternPool[T]) Ref(value T) (InternReference[T], bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put adds a value to the intern pool, returning its reference.
|
// Put adds a value to the intern pool, returning its reference.
|
||||||
func (p *InternPool[T]) Put(value T) InternReference[T] {
|
func (p *Pool[T]) Put(value T) Reference[T] {
|
||||||
v := internValue[T]{
|
v := internValue[T]{
|
||||||
value: value,
|
value: value,
|
||||||
refCount: 1,
|
refCount: 1,
|
||||||
@@ -96,7 +98,7 @@ func (p *InternPool[T]) Put(value T) InternReference[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a new index
|
// Allocate a new index
|
||||||
newIndex := func() InternReference[T] {
|
newIndex := func() Reference[T] {
|
||||||
availCount := len(p.availableIndexes)
|
availCount := len(p.availableIndexes)
|
||||||
if availCount > 0 {
|
if availCount > 0 {
|
||||||
index := p.availableIndexes[availCount-1]
|
index := p.availableIndexes[availCount-1]
|
||||||
@@ -111,7 +113,7 @@ func (p *InternPool[T]) Put(value T) InternReference[T] {
|
|||||||
}
|
}
|
||||||
index := len(p.values)
|
index := len(p.values)
|
||||||
p.values = p.values[:index+1]
|
p.values = p.values[:index+1]
|
||||||
return InternReference[T](index)
|
return Reference[T](index)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have already something
|
// Check if we have already something
|
||||||
@@ -143,6 +145,6 @@ func (p *InternPool[T]) Put(value T) InternReference[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the number of elements in the pool.
|
// Len returns the number of elements in the pool.
|
||||||
func (p *InternPool[T]) Len() int {
|
func (p *Pool[T]) Len() int {
|
||||||
return len(p.values) - len(p.availableIndexes) - 1
|
return len(p.values) - len(p.availableIndexes) - 1
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Free Mobile
|
// SPDX-FileCopyrightText: 2022 Free Mobile
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
package helpers
|
package intern
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"akvorado/common/helpers"
|
||||||
|
)
|
||||||
|
|
||||||
type likeInt int
|
type likeInt int
|
||||||
|
|
||||||
@@ -11,7 +15,7 @@ func (i likeInt) Equal(j likeInt) bool { return i == j }
|
|||||||
func (i likeInt) Hash() uint64 { return uint64(i) % 10 }
|
func (i likeInt) Hash() uint64 { return uint64(i) % 10 }
|
||||||
|
|
||||||
func TestPut(t *testing.T) {
|
func TestPut(t *testing.T) {
|
||||||
p := NewInternPool[likeInt]()
|
p := NewPool[likeInt]()
|
||||||
|
|
||||||
a := p.Put(likeInt(10))
|
a := p.Put(likeInt(10))
|
||||||
b := p.Put(likeInt(10))
|
b := p.Put(likeInt(10))
|
||||||
@@ -36,7 +40,7 @@ func TestPut(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRef(t *testing.T) {
|
func TestRef(t *testing.T) {
|
||||||
p := NewInternPool[likeInt]()
|
p := NewPool[likeInt]()
|
||||||
a := p.Put(likeInt(10))
|
a := p.Put(likeInt(10))
|
||||||
b, bOK := p.Ref(likeInt(10))
|
b, bOK := p.Ref(likeInt(10))
|
||||||
c, cOK := p.Ref(likeInt(20))
|
c, cOK := p.Ref(likeInt(20))
|
||||||
@@ -55,7 +59,7 @@ func TestRef(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPutCollision(t *testing.T) {
|
func TestPutCollision(t *testing.T) {
|
||||||
p := NewInternPool[likeInt]()
|
p := NewPool[likeInt]()
|
||||||
|
|
||||||
a := p.Put(likeInt(10))
|
a := p.Put(likeInt(10))
|
||||||
b := p.Put(likeInt(20))
|
b := p.Put(likeInt(20))
|
||||||
@@ -67,7 +71,7 @@ func TestPutCollision(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTake(t *testing.T) {
|
func TestTake(t *testing.T) {
|
||||||
p := NewInternPool[likeInt]()
|
p := NewPool[likeInt]()
|
||||||
|
|
||||||
val1 := likeInt(10)
|
val1 := likeInt(10)
|
||||||
ref1 := p.Put(val1)
|
ref1 := p.Put(val1)
|
||||||
@@ -87,7 +91,7 @@ func TestTake(t *testing.T) {
|
|||||||
{value: 22, refCount: 1, previous: 2, next: 4},
|
{value: 22, refCount: 1, previous: 2, next: 4},
|
||||||
{value: 32, refCount: 1, previous: 3},
|
{value: 32, refCount: 1, previous: 3},
|
||||||
}
|
}
|
||||||
if diff := Diff(p.values, expectedValues, DiffUnexported); diff != "" {
|
if diff := helpers.Diff(p.values, expectedValues, helpers.DiffUnexported); diff != "" {
|
||||||
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +104,7 @@ func TestTake(t *testing.T) {
|
|||||||
{value: 22, refCount: 0, previous: 2, next: 4}, // free
|
{value: 22, refCount: 0, previous: 2, next: 4}, // free
|
||||||
{value: 32, refCount: 1, previous: 2},
|
{value: 32, refCount: 1, previous: 2},
|
||||||
}
|
}
|
||||||
if diff := Diff(p.values, expectedValues, DiffUnexported); diff != "" {
|
if diff := helpers.Diff(p.values, expectedValues, helpers.DiffUnexported); diff != "" {
|
||||||
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +120,7 @@ func TestTake(t *testing.T) {
|
|||||||
{value: 42, refCount: 1, previous: 4},
|
{value: 42, refCount: 1, previous: 4},
|
||||||
{value: 32, refCount: 1, previous: 2, next: 3},
|
{value: 32, refCount: 1, previous: 2, next: 3},
|
||||||
}
|
}
|
||||||
if diff := Diff(p.values, expectedValues, DiffUnexported); diff != "" {
|
if diff := helpers.Diff(p.values, expectedValues, helpers.DiffUnexported); diff != "" {
|
||||||
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +133,7 @@ func TestTake(t *testing.T) {
|
|||||||
{value: 42, refCount: 1, previous: 4},
|
{value: 42, refCount: 1, previous: 4},
|
||||||
{value: 32, refCount: 1, next: 3},
|
{value: 32, refCount: 1, next: 3},
|
||||||
}
|
}
|
||||||
if diff := Diff(p.values, expectedValues, DiffUnexported); diff != "" {
|
if diff := helpers.Diff(p.values, expectedValues, helpers.DiffUnexported); diff != "" {
|
||||||
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +146,7 @@ func TestTake(t *testing.T) {
|
|||||||
{value: 42, refCount: 1},
|
{value: 42, refCount: 1},
|
||||||
{value: 32, refCount: 0, next: 3}, // free
|
{value: 32, refCount: 0, next: 3}, // free
|
||||||
}
|
}
|
||||||
if diff := Diff(p.values, expectedValues, DiffUnexported); diff != "" {
|
if diff := helpers.Diff(p.values, expectedValues, helpers.DiffUnexported); diff != "" {
|
||||||
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +159,7 @@ func TestTake(t *testing.T) {
|
|||||||
{value: 42, refCount: 0}, // free
|
{value: 42, refCount: 0}, // free
|
||||||
{value: 32, refCount: 0, next: 3}, // free
|
{value: 32, refCount: 0, next: 3}, // free
|
||||||
}
|
}
|
||||||
if diff := Diff(p.values, expectedValues, DiffUnexported); diff != "" {
|
if diff := helpers.Diff(p.values, expectedValues, helpers.DiffUnexported); diff != "" {
|
||||||
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
t.Fatalf("p.values (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,9 +14,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/Shopify/sarama"
|
"akvorado/common/helpers/bimap"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"github.com/Shopify/sarama"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration defines how we connect to a Kafka cluster.
|
// Configuration defines how we connect to a Kafka cluster.
|
||||||
@@ -98,7 +98,7 @@ const (
|
|||||||
SASLSCRAMSHA512 // SASLSCRAMSHA512 enables SCRAM challenge with SHA512
|
SASLSCRAMSHA512 // SASLSCRAMSHA512 enables SCRAM challenge with SHA512
|
||||||
)
|
)
|
||||||
|
|
||||||
var saslAlgorithmMap = helpers.NewBimap(map[SASLMechanism]string{
|
var saslAlgorithmMap = bimap.New(map[SASLMechanism]string{
|
||||||
SASLNone: "none",
|
SASLNone: "none",
|
||||||
SASLPlainText: "plain",
|
SASLPlainText: "plain",
|
||||||
SASLSCRAMSHA256: "scram-sha256",
|
SASLSCRAMSHA256: "scram-sha256",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
package console
|
package console
|
||||||
|
|
||||||
import "akvorado/common/helpers"
|
import "akvorado/common/helpers/bimap"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
queryColumnExporterAddress queryColumn = iota + 1
|
queryColumnExporterAddress queryColumn = iota + 1
|
||||||
@@ -56,7 +56,7 @@ const (
|
|||||||
queryColumnPacketSizeBucket
|
queryColumnPacketSizeBucket
|
||||||
)
|
)
|
||||||
|
|
||||||
var queryColumnMap = helpers.NewBimap(map[queryColumn]string{
|
var queryColumnMap = bimap.New(map[queryColumn]string{
|
||||||
queryColumnExporterAddress: "ExporterAddress",
|
queryColumnExporterAddress: "ExporterAddress",
|
||||||
queryColumnExporterName: "ExporterName",
|
queryColumnExporterName: "ExporterName",
|
||||||
queryColumnExporterGroup: "ExporterGroup",
|
queryColumnExporterGroup: "ExporterGroup",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers/intern"
|
||||||
|
|
||||||
"github.com/kentik/patricia"
|
"github.com/kentik/patricia"
|
||||||
tree "github.com/kentik/patricia/generics_tree"
|
tree "github.com/kentik/patricia/generics_tree"
|
||||||
@@ -20,9 +20,9 @@ import (
|
|||||||
// rib represents the RIB.
|
// rib represents the RIB.
|
||||||
type rib struct {
|
type rib struct {
|
||||||
tree *tree.TreeV6[route]
|
tree *tree.TreeV6[route]
|
||||||
nlris *helpers.InternPool[nlri]
|
nlris *intern.Pool[nlri]
|
||||||
nextHops *helpers.InternPool[nextHop]
|
nextHops *intern.Pool[nextHop]
|
||||||
rtas *helpers.InternPool[routeAttributes]
|
rtas *intern.Pool[routeAttributes]
|
||||||
}
|
}
|
||||||
|
|
||||||
// route contains the peer (external opaque value), the NLRI, the next
|
// route contains the peer (external opaque value), the NLRI, the next
|
||||||
@@ -30,9 +30,9 @@ type rib struct {
|
|||||||
// and nlri.
|
// and nlri.
|
||||||
type route struct {
|
type route struct {
|
||||||
peer uint32
|
peer uint32
|
||||||
nlri helpers.InternReference[nlri]
|
nlri intern.Reference[nlri]
|
||||||
nextHop helpers.InternReference[nextHop]
|
nextHop intern.Reference[nextHop]
|
||||||
attributes helpers.InternReference[routeAttributes]
|
attributes intern.Reference[routeAttributes]
|
||||||
}
|
}
|
||||||
|
|
||||||
// nlri is the NLRI for the route (when combined with prefix). The
|
// nlri is the NLRI for the route (when combined with prefix). The
|
||||||
@@ -211,8 +211,8 @@ func (r *rib) flushPeer(ctx context.Context, peer uint32, min int) (int, bool) {
|
|||||||
func newRIB() *rib {
|
func newRIB() *rib {
|
||||||
return &rib{
|
return &rib{
|
||||||
tree: tree.NewTreeV6[route](),
|
tree: tree.NewTreeV6[route](),
|
||||||
nlris: helpers.NewInternPool[nlri](),
|
nlris: intern.NewPool[nlri](),
|
||||||
nextHops: helpers.NewInternPool[nextHop](),
|
nextHops: intern.NewPool[nextHop](),
|
||||||
rtas: helpers.NewInternPool[routeAttributes](),
|
rtas: intern.NewPool[routeAttributes](),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
|
"akvorado/common/helpers/bimap"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
)
|
)
|
||||||
@@ -62,7 +63,7 @@ const (
|
|||||||
ProviderBMPExceptPrivate
|
ProviderBMPExceptPrivate
|
||||||
)
|
)
|
||||||
|
|
||||||
var asnProviderMap = helpers.NewBimap(map[ASNProvider]string{
|
var asnProviderMap = bimap.New(map[ASNProvider]string{
|
||||||
ProviderFlow: "flow",
|
ProviderFlow: "flow",
|
||||||
ProviderFlowExceptPrivate: "flow-except-private",
|
ProviderFlowExceptPrivate: "flow-except-private",
|
||||||
ProviderGeoIP: "geoip",
|
ProviderGeoIP: "geoip",
|
||||||
|
|||||||
Reference in New Issue
Block a user