Add depot, attendant, jetfire, optimus, ota services with kustomize overlays
This commit is contained in:
130
services/optimus/utils/filters.go
Normal file
130
services/optimus/utils/filters.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/pkg/clickhouse"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
)
|
||||
|
||||
// NewVehicleMessageFilters constructs a new VehicleMessageFilters
|
||||
// should only be called once during lifetime of a service
|
||||
func NewVehicleMessageFilters() *VehicleMessageFilters {
|
||||
return &VehicleMessageFilters{
|
||||
filters: make(map[string]*MessageFilters),
|
||||
}
|
||||
}
|
||||
|
||||
// VehicleMessageFilters maps vehicle vins to their set of filters
|
||||
type VehicleMessageFilters struct {
|
||||
filters map[string]*MessageFilters
|
||||
}
|
||||
|
||||
// NewFiltersForVehicle adds a new vehicle to the sets of filters
|
||||
func (v *VehicleMessageFilters) NewFiltersForVehicle(client clickhouse.ClientInterface, vin string) *MessageFilters {
|
||||
var f *MessageFilters
|
||||
|
||||
d, ok := v.filters[DEFAULT]
|
||||
if ok {
|
||||
f = NewMessageFiltersFromDefault(d)
|
||||
} else {
|
||||
f = NewMessageFilters()
|
||||
}
|
||||
|
||||
cFilters, err := client.RetrieveFiltersForVehicle(vin)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Send()
|
||||
}
|
||||
|
||||
f.PopulateFromClickhouse(cFilters)
|
||||
v.filters[vin] = f
|
||||
return f
|
||||
}
|
||||
|
||||
// GetFiltersForVehicle obtains filters for a vehicle
|
||||
func (v *VehicleMessageFilters) GetFiltersForVehicle(client clickhouse.ClientInterface, vin string) *MessageFilters {
|
||||
var f *MessageFilters
|
||||
var ok bool
|
||||
|
||||
if f, ok = v.filters[vin]; !ok {
|
||||
f = v.NewFiltersForVehicle(client, vin)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// SetDefaultFilters sets the default filters for vehicles to use as a base
|
||||
func (v *VehicleMessageFilters) SetDefaultFilters(filters []clickhouse.CANFilterSchema) {
|
||||
|
||||
d := NewMessageFilters()
|
||||
d.PopulateFromClickhouse(filters)
|
||||
v.filters[DEFAULT] = d
|
||||
}
|
||||
|
||||
// NewMessageFilters is a convenience function to setup a map of filters
|
||||
func NewMessageFilters() *MessageFilters {
|
||||
return &MessageFilters{
|
||||
filters: make(map[int]*MessageFilter),
|
||||
}
|
||||
}
|
||||
|
||||
// NewMessageFiltersFromDefault copies default filters to a new struct
|
||||
func NewMessageFiltersFromDefault(d *MessageFilters) *MessageFilters {
|
||||
f := NewMessageFilters()
|
||||
for id, key := range d.filters {
|
||||
f.SetMessageFilter(id, key.cycle)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// MessageFilters maps CAN IDs to MessageFilter structs
|
||||
type MessageFilters struct {
|
||||
filters map[int]*MessageFilter
|
||||
}
|
||||
|
||||
// SetMessageFilter adds an ID to the filter maps
|
||||
// cycle expects an integer in ms
|
||||
func (m *MessageFilters) SetMessageFilter(id int, cycle int) {
|
||||
m.filters[id] = &MessageFilter{cycle: cycle}
|
||||
}
|
||||
|
||||
// PopulateFromClickhouse is a helper method to populate
|
||||
// MessageFilters with filters queried from clickhouse
|
||||
func (m *MessageFilters) PopulateFromClickhouse(filters []clickhouse.CANFilterSchema) {
|
||||
for _, filter := range filters {
|
||||
m.SetMessageFilter(int(filter.ID), int(filter.Period)*1000)
|
||||
}
|
||||
}
|
||||
|
||||
// AllowMessage verifies if a message can pass through based on timestamp
|
||||
// if the message passes through calculates the timestamp for the next
|
||||
// possible message of that ID
|
||||
// if MessageFilter.Cycle is 0 it means the message should not pass through
|
||||
// if MessageFilter.Cycle is -1 it means the message should always pass through
|
||||
// if no filter is present for the ID - it will always pass through (BLACKLIST)
|
||||
func (m *MessageFilters) AllowMessage(id int, timestamp int) bool {
|
||||
filter, ok := m.filters[id]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
if filter.cycle == 0 {
|
||||
return false
|
||||
} else if filter.cycle == -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
if timestamp > filter.next {
|
||||
filter.next = timestamp + filter.cycle
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MessageFilter keeps track of message cycle rules and the next possible timestamp for a message
|
||||
// cycle and next are integers in microseconds (CANFilter data that comes in is in microseconds)
|
||||
type MessageFilter struct {
|
||||
cycle, next int
|
||||
}
|
||||
|
||||
const DEFAULT = "DEFAULT"
|
||||
113
services/optimus/utils/filters_test.go
Normal file
113
services/optimus/utils/filters_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package utils_test
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/optimus/utils"
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/clickhouse"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestNewVehicleMessageFilters(t *testing.T) {
|
||||
_ = utils.NewVehicleMessageFilters()
|
||||
}
|
||||
|
||||
func TestNewFiltersForVehicle(t *testing.T) {
|
||||
conn := &clickhouse.MockConn{ExpectedResult: testFilters}
|
||||
client := clickhouse.NewMockClient(conn)
|
||||
|
||||
vehicleFilters := utils.NewVehicleMessageFilters()
|
||||
filters := vehicleFilters.NewFiltersForVehicle(client, "TESTVIN123")
|
||||
|
||||
if filters == nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestNewFiltersForVehicle", "*MessageFilters", filters)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFiltersForVehicle(t *testing.T) {
|
||||
conn := &clickhouse.MockConn{ExpectedResult: testFilters}
|
||||
client := clickhouse.NewMockClient(conn)
|
||||
|
||||
vehicleFilters := utils.NewVehicleMessageFilters()
|
||||
filters := vehicleFilters.GetFiltersForVehicle(client, "TESTVIN123")
|
||||
|
||||
if filters == nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestGetFiltersForVehicle", "*MessageFilters", filters)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultFilters(t *testing.T) {
|
||||
vehicleFilters := utils.NewVehicleMessageFilters()
|
||||
vehicleFilters.SetDefaultFilters(testFilters)
|
||||
}
|
||||
|
||||
func TestNewMessageFilters(t *testing.T) {
|
||||
_ = utils.NewMessageFilters()
|
||||
}
|
||||
|
||||
func TestNewMessageFiltersFromDefault(t *testing.T) {
|
||||
d := utils.NewMessageFilters()
|
||||
d.SetMessageFilter(1, 1)
|
||||
|
||||
f := utils.NewMessageFiltersFromDefault(d)
|
||||
if f.AllowMessage(1, 1) != true {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestNewMessageFiltersFromDefault", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMessageFilter(t *testing.T) {
|
||||
f := utils.NewMessageFilters()
|
||||
f.SetMessageFilter(2, 2)
|
||||
}
|
||||
|
||||
func TestPopulateFromClickhouse(t *testing.T) {
|
||||
f := utils.NewMessageFilters()
|
||||
f.PopulateFromClickhouse(testFilters)
|
||||
if f.AllowMessage(1, 1) != true {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestPopulateFromClickhouse", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowMessage(t *testing.T) {
|
||||
f := utils.NewMessageFilters()
|
||||
f.PopulateFromClickhouse(testFilters)
|
||||
|
||||
if f.AllowMessage(1, 1) != true {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestAllowMessage", true, false)
|
||||
}
|
||||
|
||||
if f.AllowMessage(3, 2) != true {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestAllowMessage", true, false)
|
||||
}
|
||||
|
||||
if f.AllowMessage(3, 1) == true {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestAllowMessage", false, true)
|
||||
}
|
||||
|
||||
if f.AllowMessage(5, 1) == true {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestAllowMessage", false, true)
|
||||
}
|
||||
|
||||
if f.AllowMessage(10, 1) != true {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestAllowMessage", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
var testFilters = []clickhouse.CANFilterSchema{
|
||||
{
|
||||
ID: 1,
|
||||
Period: 2,
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
Period: 4,
|
||||
},
|
||||
{
|
||||
ID: 5,
|
||||
Period: 0,
|
||||
},
|
||||
{
|
||||
ID: 10,
|
||||
Period: -1,
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user