package immobilizershared import ( "context" "encoding/json" "time" "fiskerinc.com/modules/logger" "fiskerinc.com/modules/redisv2" ) // Grabs all the vehicle statuses from redis func ReadVehicleStatuses(connection *redisv2.Connection) (results map[string]ImmobilizeTrack, err error) { res := connection.HGetAll(context.Background(), IMMOBILIZER_HASHSET_NAME) tempMap, err := res.Result() if err != nil { logger.Err(err).Stack().Str("function", "ReadVehicleStatuses").Msg("Immobilizer Error") return } results = make(map[string]ImmobilizeTrack) for key, value := range tempMap { tempTrack := ImmobilizeTrack{} err = json.Unmarshal([]byte(value), &tempTrack) if err != nil { logger.Err(err).Stack().Str("function", "ReadVehicleStatuses").Msg("Immobilizer Error") continue } results[key] = tempTrack } return } // WE want to update redis with the fact a car is immobilized, so start with modifying redis, then sending a publish event // This kind of specification per function is sort of silly, probably will want to change in the future func UpdateCarImmobilized(vin string, connection *redisv2.Connection) (err error) { err = SetVehicleImmobilized(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarImmobilized").Msg("Immobilizer Error") return } err = PublishVehicleImmobilized(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarImmobilized").Msg("Immobilizer Error") return } return } func UpdateCarImmobilizing(vin string, connection *redisv2.Connection) (err error) { err = SetVehicleImmobilizing(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarImmobilizing").Msg("Immobilizer Error") return } err = PublishVehicleImmobilizing(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarImmobilizing").Msg("Immobilizer Error") return } return } func UpdateCarMobilized(vin string, connection *redisv2.Connection) (err error) { err = SetVehicleMobilized(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarMobilized").Msg("Immobilizer Error") return } err = PublishVehicleMobilized(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarMobilized").Msg("Immobilizer Error") return } return } func UpdateCarMobilizing(vin string, connection *redisv2.Connection) (err error) { err = SetVehicleMobilizing(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarMobilizing").Msg("Immobilizer Error") return } err = PublishVehicleMobilizing(vin, connection) if err != nil { logger.Err(err).Stack().Str("function", "UpdateCarMobilizing").Msg("Immobilizer Error") return } return } // Might not need to call these directly // Publishing the fact the car is now mobilized. Ditto's will remove the car from their containers func PublishVehicleMobilized(vin string, connection *redisv2.Connection) (err error) { return PublishVehicleMobilizationChange(RedisImmobilizerMsg{VIN: vin, State: STATE_MOBILIZED}, connection) } func PublishVehicleMobilizing(vin string, connection *redisv2.Connection) (err error) { return PublishVehicleMobilizationChange(RedisImmobilizerMsg{VIN: vin, State: STATE_MOBILIZING}, connection) } func PublishVehicleImmobilized(vin string, connection *redisv2.Connection) (err error) { return PublishVehicleMobilizationChange(RedisImmobilizerMsg{VIN: vin, State: STATE_IMMOBILIZED}, connection) } // Publish the fact we are trying to immobile the vehicle func PublishVehicleImmobilizing(vin string, connection *redisv2.Connection) (err error) { return PublishVehicleMobilizationChange(RedisImmobilizerMsg{VIN: vin, State: STATE_IMMOBILIZING}, connection) } func PublishVehicleMobilizationChange(msg RedisImmobilizerMsg, connection *redisv2.Connection) (err error) { // I think the int that is returned is the number of subscribers res := connection.Publish(context.Background(), IMMOBILIZER_PUBSUB_CHANNEL, msg) err = res.Err() return } // These all modify the redis data store, which acts as a database for the cars that are immobilized func SetVehicleMobilized(vin string, connection *redisv2.Connection) (err error) { // Instead of using HSET, we are deleting the car from the immobilized stats line. Keeps the redis store smaller res := connection.HDel(context.Background(), IMMOBILIZER_HASHSET_NAME, vin) err = res.Err() if err != nil { logger.Err(err).Stack().Str("function", "SetVehicleMobilized").Msg("Immobilizer Error") } return } func SetVehicleMobilizing(vin string, connection *redisv2.Connection) (err error) { return setVehicleMobilizationChange(vin, ImmobilizeTrack{State: STATE_MOBILIZING}, connection) } func SetVehicleImmobilized(vin string, connection *redisv2.Connection) (err error) { return setVehicleMobilizationChange(vin, ImmobilizeTrack{State: STATE_IMMOBILIZED}, connection) } // Set the fact we are trying to immobile the vehicle func SetVehicleImmobilizing(vin string, connection *redisv2.Connection) (err error) { return setVehicleMobilizationChange(vin, ImmobilizeTrack{State: STATE_IMMOBILIZING}, connection) } // CHANGE func setVehicleMobilizationChange(vin string, msg ImmobilizeTrack, connection *redisv2.Connection) (err error) { // I think the int that is returned is the number of subscribers res := connection.HSet(context.Background(), IMMOBILIZER_HASHSET_NAME, vin, msg) err = res.Err() if err != nil { logger.Err(err).Stack().Str("function", "setVehicleMobilizationChange").Msg("Immobilizer Error") return } return } const IMMOBILIZER_PUBSUB_CHANNEL = "immobilizer" const IMMOBILIZER_HASHSET_NAME = "immobilizer" type ImmobilizeTrack struct { State ImmobilizeState // IDK, do we need the time we tried? We probably need a timer thing CreatedAt *time.Time UpdatedAt *time.Time } // For redis serialization func (it ImmobilizeTrack) MarshalBinary() ([]byte, error) { return json.Marshal(it) } func (it ImmobilizeTrack) UnmarshalBinary(data []byte) error { return json.Unmarshal(data, &it) } type ImmobilizeState int var ( STATE_IMMOBILIZED ImmobilizeState = 0 // Car officially immobilized STATE_IMMOBILIZING ImmobilizeState = 1 // Trying to immobilize car STATE_MOBILIZING ImmobilizeState = 2 // Trying to mobilize the car STATE_MOBILIZED ImmobilizeState = 3 // Car is mobilized, although not stored in redis or ditto, is used to communicate the change has been made ) func (i ImmobilizeState) String()(string){ switch i{ case STATE_IMMOBILIZED: return "STATE_IMMOBILIZED" case STATE_IMMOBILIZING: return "STATE_IMMOBILIZING" case STATE_MOBILIZING: return "STATE_MOBILIZING" case STATE_MOBILIZED: return "STATE_MOBILIZED" } return "missing" } type RedisImmobilizerMsg struct { VIN string // VIN that we are modifying State ImmobilizeState // How we are changing said state, which will affect how listening ditto's will manage } func (rim RedisImmobilizerMsg) MarshalBinary() ([]byte, error) { return json.Marshal(rim) } func (rim RedisImmobilizerMsg) UnmarshalBinary(data []byte) error { return json.Unmarshal(data, &rim) }