package server import ( "github.com/fiskerinc/cloud-services/services/attendant/controllers" "github.com/fiskerinc/cloud-services/services/attendant/handlers" "github.com/fiskerinc/cloud-services/services/attendant/services" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/grpc/kafka_grpc" "github.com/fiskerinc/cloud-services/pkg/grpc/sms" "github.com/fiskerinc/cloud-services/pkg/kafka" "github.com/fiskerinc/cloud-services/pkg/logger" "github.com/fiskerinc/cloud-services/pkg/loggerdataresp" "github.com/fiskerinc/cloud-services/pkg/tmobile" "google.golang.org/protobuf/proto" ) // StartConsumer runs consumer and puts events into a channel for router func StartConsumer(topic, oldTopic string) { defer func() { if err := recover(); err != nil { logger.Error().Msgf("PanicConsumer %v", err) } }() events := make(chan *kafka.Message) eventsJSON := make(chan common.EventRawJSON) go routeEvents(events) go routeOldEvents(eventsJSON) logger.Info().Msgf("consumer intialized for topic: %v", topic) consumer, oldConsumer, err := services.GetKafkaConsumer() if err != nil { panic(err) } go func() { err = oldConsumer.ConsumeToChannelJson([]string{oldTopic}, eventsJSON) loggerdataresp.BadDataError(err, loggerdataresp.EofErrorCheck) }() err = consumer.ConsumeToChannel([]string{topic}, events) loggerdataresp.BadDataError(err, loggerdataresp.EofErrorCheck) } func routeEvents(events chan *kafka.Message) { db := services.GetDB() defer db.Close() sms := services.GetSMSClient() ka := services.NewKeepAwakeService() for { event := <-events var err error payload := &kafka_grpc.GRPC_AttendantPayload{} err = proto.Unmarshal(event.Value, payload) if err != nil { logger.Warn().Err(err).Send() } device, key := common.ParseDeviceKey(string(event.Key)) logger.Debug().Str("id", key).Msgf("source: %s, type: %s, handler: %s", key, device, payload.GetHandler()) switch device { case common.TRex: if payload.GetHandler() == "dtcs" { d := &common.ConsumerPayload{ Handler: payload.GetHandler(), Data: controllers.GRPCToDTCEntry(payload), } routeService(db, ka, sms, key, d) break } d, _ := common.AttendantRouteTRexPayload(payload) routeTRex(db, ka, key, d) case common.HMI: d, _ := common.AttendantRouteHMIPayload(payload) routeHMI(db, ka, key, d) case common.Mobile: d, _ := common.AttendantRouteMobilePayload(payload) routeMobile(db, key, d) case common.Service: if payload.GetHandler() == "sms_delivery_status_manifest" { d := &common.ConsumerPayload{ Handler: payload.GetHandler(), Data: tmobile.GRPCToTMessage(payload), } routeService(db, ka, sms, key, d) break } d, _ := common.AttendantRouteServicePayload(payload) routeService(db, ka, sms, key, d) default: { logger.Error().Str("id", key).Msgf("Unknown device: %s, type: %s, handler: %s", device, key, payload.GetHandler()) loggerdataresp.BadDataError(ErrInvalidDevice) } } loggerdataresp.BadDataError(err) } } func routeOldEvents(events chan common.EventRawJSON) { db := services.GetDB() defer db.Close() sms := services.GetSMSClient() ka := services.NewKeepAwakeService() for { event := <-events var p common.Payload err := p.Unmarshal(event.Payload) device, key := common.ParseDeviceKey(event.Key) payload := &common.ConsumerPayload{ Handler: p.Handler, Data: p.Data, } logger.Debug().Str("id", key).Msgf("source: %s, type: %s, handler: %s", key, device, payload.GetHandler()) switch device { case common.TRex: routeTRex(db, ka, key, payload) case common.HMI: routeHMI(db, ka, key, payload) case common.Mobile: routeMobile(db, key, payload) case common.Service: routeService(db, ka, sms, key, payload) default: { logger.Error().Str("id", key).Msgf("Unknown device: %s, type: %s, handler: %s", device, key, p.Handler) loggerdataresp.BadDataError(ErrInvalidDevice) } } loggerdataresp.BadDataError(err) } } func routeTRex(db *services.DB, ka *services.KeepAwake, id string, p common.ConsumerPayloadInterface) { // route TRex messages. Also update cloud/modules_go/kafka/topics.go var err error switch p.GetHandler() { case "car_state": err = handlers.UpdateCarState(db, id, p.GetData()) loggerdataresp.BadDataError(err) case "car_update_status", "car_update_download", "car_update_install": err = handlers.CarUpdateProgressStatus(db, ka, common.TRex, id, p.GetData()) loggerdataresp.BadDataError(err) case "get_filekeys": err = handlers.GetFileKeys(db, common.TRex, id, p.GetData()) case "dtcs": err = handlers.UploadDtc(id, p.GetData()) case "ecc_keys": err = handlers.GetAllEccKeys(db, id, p.GetData()) default: err = kafka.ErrUnhandledMessage(common.TRex, id, p.GetHandler(), string(p.GetData())) } loggerdataresp.BadDataError(err) } func routeHMI(db *services.DB, ka *services.KeepAwake, id string, p common.ConsumerPayloadInterface) { // route HMI messages. Also update cloud/modules_go/kafka/topics.go var err error switch p.GetHandler() { case "update_approve": err = handlers.ApproveUpdate(db, id, p.GetData()) case "car_update_status", "car_update_download", "car_update_install": go func() { err = handlers.CarUpdateProgressStatus(db, ka, common.HMI, id, p.GetData()) loggerdataresp.BadDataError(err) }() err = handlers.CarUpdateProgressStatus(db, ka, common.HMI, id, p.GetData()) loggerdataresp.BadDataError(err) case "get_filekeys": err = handlers.GetFileKeys(db, common.HMI, id, p.GetData()) default: err = kafka.ErrUnhandledMessage(common.HMI, id, p.GetHandler(), string(p.GetData())) } loggerdataresp.BadDataError(err) } func routeMobile(db *services.DB, id string, p common.ConsumerPayloadInterface) { // route mobile messages. Also update cloud/modules_go/kafka/topics.go var err error switch p.GetHandler() { case "update_approve": err = handlers.ApproveUpdate(db, id, p.GetData()) case "updates_get": err = handlers.GetUpdates(db, id, p.GetData()) default: err = kafka.ErrUnhandledMessage(common.Mobile, id, p.GetHandler(), string(p.GetData())) } loggerdataresp.BadDataError(err) } func routeService(db *services.DB, ka *services.KeepAwake, sms sms.SMSServiceClient, id string, p common.ConsumerPayloadInterface) { // route cloud service messages. Also update cloud/modules_go/kafka/topics.go var err error // We should switch out these strings for constants in the kafka library switch p.GetHandler() { case "send_manifest": err = handlers.SendManifest(db, ka, common.Service, id, p.GetData()) case "order_updated": err = handlers.OrderUpdated(db, sms, id, p.GetData()) case "sms_delivery_status_manifest": err = handlers.CarSendManifestSMSWakeUpCallback(db, ka, common.Service, id, p.GetData()) default: err = kafka.ErrUnhandledMessage(common.Service, id, p.GetHandler(), string(p.GetData())) } loggerdataresp.BadDataError(err) }