Initial cloud-services repo - gateway service + pkg modules

This commit is contained in:
Chris Rai
2026-01-30 23:14:52 -05:00
commit fbb820d7b3
1037 changed files with 171318 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
package towmanparklocation
import (
"sync"
"time"
"fiskerinc.com/modules/cachev2"
"fiskerinc.com/modules/db"
"fiskerinc.com/modules/logger"
"fiskerinc.com/modules/redisv2"
)
func (plt *ParkLocationTracker) VCUGearSig(vin string, newState int) {
// Fast exit if the car is not being parked
if newState != 1 {
return
}
_, ok := plt.WatchList[vin]
if !ok {
return
}
// WRITE park location to DB
// DOn't want to slow down the signal processing, so do this async
go plt.recordParkLocation(vin)
}
// Probably would be better with a channel and a worker, but this is fine for now
func (plt *ParkLocationTracker) recordParkLocation(vin string) {
// Fetch the location from redis -- how did copilot know this?
location, err := cachev2.GetVehicleLocation(vin, plt.RedisClient)
if err != nil {
logger.Err(err).Str("VIN", vin).Msg("failed to get vehicle location for park location")
return
}
// Write to DB
_, err = plt.DBClient.GetConn().Exec("INSERT INTO towman.parked_locations (vin, latitude, longitude) VALUES (?, ?, ?)", vin, location.Latitude, location.Longitude)
if err != nil {
logger.Err(err).Str("VIN", vin).Msg("failed to record park location to DB")
return
}
}
func (plt *ParkLocationTracker) UpdateVehicleList() {
dbVINS := []string{}
_, err := plt.DBClient.GetConn().Query(&dbVINS, "SELECT vin FROM towman.vehicles")
if err != nil {
logger.Err(err).Msg("failed to update parked vehicle list")
return
}
// Make anew watchmap
newWatchList := make(map[string]struct{})
for _, vin := range dbVINS {
newWatchList[vin] = struct{}{}
}
// Only need to lock before we assign the new map
plt.WatchListSync.Lock()
defer plt.WatchListSync.Unlock()
// assign watchmap
plt.WatchList = newWatchList
}
func (plt *ParkLocationTracker) IsVehicleWatched(vin string) (watched bool) {
plt.WatchListSync.RLock()
_, ok := plt.WatchList[vin]
plt.WatchListSync.RUnlock()
return ok
}
func InitParkLocationTracker(dbClient *db.DBClient, redisClient *redisv2.Connection) (plt *ParkLocationTracker) {
plt = &ParkLocationTracker{
WatchList: make(map[string]struct{}),
}
plt.DBClient = dbClient
plt.RedisClient = redisClient
go plt.SeedDaily()
return
}
// This list won't update that often
func (plt *ParkLocationTracker) SeedDaily() {
plt.UpdateVehicleList()
time.AfterFunc(time.Hour*24, plt.SeedDaily)
}
type ParkLocationTracker struct {
WatchList map[string]struct{} // VINs being tracked for parking location
DBClient *db.DBClient
RedisClient *redisv2.Connection
WatchListSync sync.RWMutex
}

View File

@@ -0,0 +1,51 @@
//go:build integration
package towmanparklocation
import (
"testing"
"fiskerinc.com/modules/db"
"fiskerinc.com/modules/redisv2"
"fiskerinc.com/modules/utils/localtests"
)
func TestParkLocation(t *testing.T){
localtests.SetTestENV_Prod(t)
ivansVin := "VCF1ZBU28PG002114"
// Add Ivan's Car to tracked vehicles
db := db.DBClient{}
_, err := db.GetConn().Exec("INSERT INTO towman.vehicles (vin) VALUES (?)", ivansVin)
if err != nil {
t.Fatalf("Failed to insert vehicle: %v", err)
}
// Remove Ivan's car from tracked vehicles
defer func() {
_, err := db.GetConn().Exec("DELETE FROM towman.vehicles WHERE vin = ?", ivansVin)
if err != nil {
t.Fatalf("Failed to delete vehicle: %v", err)
}
}()
// Send in a location to be parked
redisv2Client := redisv2.NewClient(nil)
plt := InitParkLocationTracker(&db, redisv2Client)
for x := 0; x < 5; x ++{
plt.recordParkLocation(ivansVin)
}
// Verify location is stored in parked locations
var locationRecords []MockLocationStruct
res, err := db.GetConn().Query(&locationRecords, "SELECT latitude, longitude FROM towman.parked_locations WHERE vin = ? ORDER BY created_at", ivansVin)
if err != nil {
t.Fatalf("Failed to query parked locations: %v", err)
}
if res.RowsAffected() != 5 {
t.Fatalf("Expected 5 location records, got %d", res.RowsAffected())
}
}
type MockLocationStruct struct {
Latitude float64 `redis:"latitude"`
Longitude float64 `redis:"longitude"`
}