Add depot, attendant, jetfire, optimus, ota services with kustomize overlays

This commit is contained in:
Chris Rai
2026-01-31 15:35:07 -05:00
parent a0ec642ca1
commit 9a5cb2f547
404 changed files with 38817 additions and 16 deletions

View File

@@ -0,0 +1,113 @@
package services
import (
"bytes"
"encoding/json"
"net/http"
"sync"
"time"
"github.com/fiskerinc/cloud-services/pkg/common"
"github.com/fiskerinc/cloud-services/pkg/logger"
"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
"github.com/go-pg/pg/v10"
"github.com/pkg/errors"
)
var (
certService CertServiceInterface
certOnce sync.Once
)
func GetCertService() CertServiceInterface {
certOnce.Do(func() {
if certService != nil {
return
}
certService = NewCertService()
})
return certService
}
func SetCertService(cs CertServiceInterface) {
certService = cs
}
func NewCertService() CertServiceInterface {
return &CertService{
certURL: envtool.GetEnv("CERT_URL", "REPLACE_ME"),
certAPIToken: envtool.GetEnv("CERTIFICATE_API_KEY", "REPLACE_ME"),
}
}
type CertServiceInterface interface {
CheckCertificateNeedsRenewal(vin string, certType string) (bool, error)
RenewCertificate(vin string, certType string) (*common.Certificate, error)
}
type CertService struct {
certURL string
certAPIToken string
}
func (cs *CertService) CheckCertificateNeedsRenewal(vin string, certType string) (bool, error) {
logger.Debug().Msg("checking " + certType + " cert for vin " + vin)
cert, err := GetDB().GetCertificates().SelectMostRecent(vin, certType)
if err != nil && !errors.Is(err, pg.ErrNoRows) {
return false, err
}
if cert == nil {
logger.Debug().Msg("no existing " + certType + " cert to renew for vin " + vin)
return false, nil
}
var daysBeforeExp = 183 // six months
switch certType {
case common.CertTBOX:
daysBeforeExp = envtool.GetEnvInt("TBOX_CERT_RENEW_DAYS_BEFORE_EXP", daysBeforeExp)
case common.CertICC:
daysBeforeExp = envtool.GetEnvInt("ICC_CERT_RENEW_DAYS_BEFORE_EXP", daysBeforeExp)
}
logger.Debug().Msg("checking validity of " + certType + " cert with serial number " + cert.SerialNumber + " for vin " + vin)
return cert.IsExpiredOrInvalidAtTime(time.Now(), daysBeforeExp)
}
func (cs *CertService) RenewCertificate(vin string, certType string) (*common.Certificate, error) {
logger.Debug().Msg("renewing " + certType + " cert for vin " + vin)
jsonBytes, err := json.Marshal(common.CertificateRenewRequest{
Type: certType,
CommonName: vin,
})
if err != nil {
return nil, err
}
request, err := http.NewRequest(http.MethodPost, cs.certURL+"renew", bytes.NewReader(jsonBytes))
if err != nil {
return nil, err
}
request.Header.Add("Api-Key", cs.certAPIToken)
resp, err := http.DefaultClient.Do(request)
if err != nil {
return nil, errors.WithStack(err)
}
if resp.StatusCode != http.StatusOK {
return nil, errors.New("renew " + certType + " certificate returned " + resp.Status + " for vin " + vin)
}
defer resp.Body.Close()
var cert common.Certificate
err = json.NewDecoder(resp.Body).Decode(&cert)
if err != nil {
return nil, err
}
return &cert, err
}

View File

@@ -0,0 +1,170 @@
package services
import (
"sync"
"github.com/fiskerinc/cloud-services/pkg/common"
"github.com/fiskerinc/cloud-services/pkg/db"
q "github.com/fiskerinc/cloud-services/pkg/db/queries"
"github.com/fiskerinc/cloud-services/pkg/logger"
)
var (
dbOnce sync.Once
dbInstance *DB
)
type DB struct {
client *db.DBClient
cars q.CarsInterface
carVersionsLog q.CarVersionsLogInterface
certificates q.CertificatesInterface
updateManifest q.UpdateManifestsInterface
updateManifestSUMSVersions q.SUMSVersionsInterface
onceClient sync.Once
onceCars sync.Once
onceCarVersionsLog sync.Once
onceCertificates sync.Once
onceUpdateManifest sync.Once
onceUpdateManifestSUMSVersions sync.Once
}
func GetDB() *DB {
dbOnce.Do(func() {
if dbInstance != nil {
return
}
logger.Info().Msg("init DB instance")
dbInstance = &DB{}
})
return dbInstance
}
func SetDB(db *DB) {
if dbInstance != nil {
dbInstance.Close()
}
dbInstance = db
}
func (d *DB) GetDBClient() *db.DBClient {
d.onceClient.Do(func() {
if d.client != nil {
return
}
logger.Info().Msg("init DBClient instance")
client := &db.DBClient{}
err := client.InitSchema([]interface{}{
(*common.UpdateManifest)(nil),
(*common.CarUpdate)(nil),
(*common.CarToDriver)(nil),
(*common.CarSetting)(nil),
(*common.SUMSVersion)(nil),
})
if err != nil {
logger.Error().Err(err).Send()
}
d.client = client
})
return d.client
}
func (d *DB) SetDBClient(client *db.DBClient) {
if d.client != nil {
d.client.Close()
}
d.client = client
}
func (d *DB) Close() {
if d.client == nil {
return
}
d.client.Close()
}
///----------
func (d *DB) GetCars() q.CarsInterface {
d.onceCars.Do(func() {
if d.cars != nil {
return
}
instance := &q.Cars{}
instance.SetClient(d.GetDBClient())
d.cars = instance
})
return d.cars
}
func (d *DB) SetCars(cars q.CarsInterface) {
d.cars = cars
}
func (d *DB) GetCarVersionsLog() q.CarVersionsLogInterface {
d.onceCarVersionsLog.Do(func() {
if d.carVersionsLog != nil {
return
}
instance := &q.CarVersionsLog{}
instance.SetClient(d.GetDBClient())
d.carVersionsLog = instance
})
return d.carVersionsLog
}
func (d *DB) SetCarVersionsLog(log q.CarVersionsLogInterface) {
d.carVersionsLog = log
}
func (d *DB) GetCertificates() q.CertificatesInterface {
d.onceCertificates.Do(func() {
if d.certificates != nil {
return
}
logger.Debug().Msg("Init Certificates instance")
certificates := &q.Certificates{}
certificates.SetClient(d.GetDBClient())
d.certificates = certificates
})
return d.certificates
}
func (d *DB) SetCertificates(certificates q.CertificatesInterface) {
d.certificates = certificates
}
func (d *DB) GetUpdateManifests() q.UpdateManifestsInterface {
d.onceUpdateManifest.Do(func() {
if d.updateManifest != nil {
return
}
logger.Debug().Msg("Init UpdateManifest instance")
updateManifest := q.NewUpdateManifest(nil)
updateManifest.SetClient(d.GetDBClient())
d.updateManifest = updateManifest
})
return d.updateManifest
}
func (d *DB) SetUpdateManifests(updateManifest q.UpdateManifestsInterface) {
d.updateManifest = updateManifest
}
func (d *DB) GetUpdateManifestSUMSVersions() q.SUMSVersionsInterface {
d.onceUpdateManifestSUMSVersions.Do(func() {
if d.updateManifestSUMSVersions != nil {
return
}
instance := &q.SUMSVersions{}
instance.SetClient(d.GetDBClient())
d.updateManifestSUMSVersions = instance
})
return d.updateManifestSUMSVersions
}
func (d *DB) SetUpdateManifestVersions(umv q.SUMSVersionsInterface) {
d.updateManifestSUMSVersions = umv
}

View File

@@ -0,0 +1,23 @@
package services
import (
"sync"
"github.com/fiskerinc/cloud-services/pkg/digitaltwin"
)
// There is no need to recreate the digital twin sender every time we send a digital twin
// so keeping a reference here
var sendDigitalTwin *digitaltwin.SendDigitalTwin
var sendDigitalTwinOnce sync.Once
func GetSendDigitalTwin()(*digitaltwin.SendDigitalTwin){
sendDigitalTwinOnce.Do(func(){
if sendDigitalTwin == nil {
notSureWhyIcantTakeAddress := digitaltwin.NewSendDigitalTwin(RedisClientPool(), GetDB().GetCars())
sendDigitalTwin = &notSureWhyIcantTakeAddress
}
})
return sendDigitalTwin
}

View File

@@ -0,0 +1,36 @@
package services
import (
"sync"
"github.com/fiskerinc/cloud-services/pkg/kafka"
"github.com/fiskerinc/cloud-services/pkg/logger"
)
const serviceName = "depot"
const oldServiceName = "old-depot"
var consumer kafka.ConsumerInterface
var oldConsumer kafka.ConsumerInterface
var consumerOnce sync.Once
// GetKafkaConsumer returns singleton instance of kafka consumer
func GetKafkaConsumer() (kafka.ConsumerInterface, kafka.ConsumerInterface, error) {
var err error
consumerOnce.Do(func() {
consumer, err = kafka.NewConsumer(serviceName)
if err != nil {
logger.Error().Err(err).Send()
}
oldConsumer, err = kafka.NewConsumer(oldServiceName)
if err != nil {
logger.Error().Err(err).Send()
}
})
if err != nil {
return consumer, oldConsumer, err
}
return consumer, oldConsumer, nil
}

View File

@@ -0,0 +1,72 @@
package services
import (
"context"
"sync"
"time"
"github.com/fiskerinc/cloud-services/pkg/mongo"
"github.com/pkg/errors"
"github.com/sony/gobreaker"
)
var (
clientlock sync.Mutex
client mongo.Client
cb *gobreaker.CircuitBreaker
)
func init() {
cb = gobreaker.NewCircuitBreaker(
gobreaker.Settings{
Timeout: 10 * time.Second,
Interval: 15 * time.Minute,
},
)
}
// GetMongoClient returns singleton instance of mongo client
func GetMongoClient() (mongo.Client, error) {
err := ping()
if err != nil {
return initMongoClient()
}
return client, nil
}
func initMongoClient() (mongo.Client, error) {
clientlock.Lock()
defer clientlock.Unlock()
var err error
client, err = mongo.NewClient(mongo.StandardDB)
if err != nil {
return nil, err
}
_, _ = cb.Execute(func() (interface{}, error) {
err = ping()
return nil, err
})
return client, errors.WithStack(err)
}
func ping() error {
if client == nil {
return errors.New("client is nil")
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
return client.Ping(ctx)
}
// SetMongoClient is supposed to be used for tests.
func SetMongoClient(cl mongo.Client) {
client = cl
}
// db.dtc_lookup.aggregate({"$match": {"ecuName": "TBOX", "DtcUniqueId": "V2.6.0"}}, {"$unwind": "$dtcData.DtcList"}, {"$match": {"dtcData.DtcList.TroubleCodeHex":"D77F16"}}, {"$project":{"_id": 0, "Obj": "$dtcData.DtcList"}})

View File

@@ -0,0 +1,28 @@
package services
import (
"sync"
"github.com/fiskerinc/cloud-services/pkg/redis"
)
var (
clientPoolOnce sync.Once
clientPool redis.ClientPoolInterface
)
func RedisClientPool() redis.ClientPoolInterface {
clientPoolOnce.Do(func() {
if clientPool != nil {
return
}
clientPool = redis.NewClientPool()
})
return clientPool
}
func SetRedisClientPool(cp redis.ClientPoolInterface) {
clientPool = cp
}

View File

@@ -0,0 +1,42 @@
package services
import (
"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
"github.com/fiskerinc/cloud-services/pkg/logger"
"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"sync"
)
var smsClient sms.SMSServiceClient
var smsClientOnce sync.Once
func newSmsClient() {
logger.Info().Msg("Init SMS client")
target := fmt.Sprintf("%s:%s",
envtool.GetEnv("SMS_HOST", "sms"),
envtool.GetEnv("SMS_PORT", "8077"))
c, err := grpc.Dial(target, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
logger.Error().Err(err).Send()
}
smsClient = sms.NewSMSServiceClient(c)
}
func GetSMSClient() sms.SMSServiceClient {
smsClientOnce.Do(func() {
if smsClient != nil {
return
}
newSmsClient()
})
return smsClient
}
func SetSmsClient(c sms.SMSServiceClient) {
smsClient = c
}