Files
cloud-services/services/ota_update_go/handlers/vehicles_get.go

211 lines
5.2 KiB
Go

package handlers
import (
"net/http"
"time"
"github.com/fiskerinc/cloud-services/pkg/cache"
re "github.com/fiskerinc/cloud-services/pkg/redis"
"github.com/fiskerinc/cloud-services/pkg/utils"
"github.com/gomodule/redigo/redis"
"github.com/pkg/errors"
"otaupdate/services"
"github.com/fiskerinc/cloud-services/pkg/common"
orm "github.com/fiskerinc/cloud-services/pkg/db/queries"
"github.com/fiskerinc/cloud-services/pkg/logger"
"github.com/fiskerinc/cloud-services/pkg/loggerdataresp"
"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
"github.com/fiskerinc/cloud-services/pkg/utils/urlhelper"
"github.com/fiskerinc/cloud-services/pkg/validator"
"github.com/fiskerinc/cloud-services/pkg/utils/elptr"
)
// HandleVehiclesGet godoc
// @Summary Search cars
// @Description Returns cars filtered by id, model, year, and vin
// @Accept json
// @Produce json
// @Param Authorization header string false "Bearer <ID token>"
// @Param Api-Key header string false "<API token>"
// @Param search query string false "Text search"
// @Param vins query []string false "csv of Car vin"
// @Param model query int false "Car model"
// @Param year query string false "Car year"
// @Param online query bool false "Car status"
// @Param online_hmi query bool false "HMI status"
// @Param limit query int false "Max number of records"
// @Param offset query int false "Records offset"
// @Param order query string false "Sort on column with asc or desc"
// @Success 200 {object} common.JSONDBQueryResult{data=[]common.Car}
// @Failure 400 {object} common.JSONError "Bad request"
// @Failure 401 {object} common.JSONError "Unauthorized"
// @Failure 503 {object} common.JSONError "Service unavailable"
// @Router /vehicles [get]
func HandleVehiclesGet(w http.ResponseWriter, r *http.Request) {
var total int
c := services.GetDB().GetCars()
filter, err := parseCarsFilter(r)
if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) {
return
}
options, err := orm.ParsePageQuery(r)
if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) {
return
}
if options.Order == "" {
options.Order = "vin"
}
err = fillOnline(filter)
if loggerdataresp.BadDataErrorResp(w, err, http.StatusServiceUnavailable) {
return
}
// Do not display EU vins in the list in NA prod UI
if isNAProd() {
filter.NoEU = true
}
cars, err := c.Search(filter, options)
if loggerdataresp.BadDataErrorResp(w, err, http.StatusServiceUnavailable, loggerdataresp.PostgresNoRowsErrorCheck) {
return
}
if options.Offset == 0 && filter.VIN == "" {
total, err = c.SearchCount(filter)
if loggerdataresp.BadDataErrorResp(w, err, http.StatusServiceUnavailable) {
return
}
}
utils.RespJSON(w, http.StatusOK, common.JSONDBQueryResult{
Data: cars,
Total: total,
})
}
var vehiclesCache cache.VehicleCacher
func SetVehiclesCache(c cache.VehicleCacher) {
vehiclesCache = c
}
func GetVehiclesCache() cache.VehicleCacher {
if vehiclesCache == nil {
var err error
vehiclesCache, err = cache.NewVehiclesCache(
envtool.GetEnvDuration("VEHICLES_CACHE_TTL", 5*time.Minute),
envtool.GetEnvInt("VEHICLES_CACHE_LIMIT", 1000))
if err != nil {
logger.Error().Err(err).Send()
}
}
return vehiclesCache
}
func fillOnline(filter *common.CarSearch) error {
if filter == nil || filter.Online == nil {
return nil
}
var keys []string
if filter.Online.Online != nil && *filter.Online.Online {
keys = append(keys, re.CarSessionsKey())
}
if filter.Online.HMI != nil && *filter.Online.HMI {
keys = append(keys, re.HMISessionsKey())
}
if len(keys) == 0 {
return nil
}
vehicles, err := getOnline(keys)
if err != nil {
return errors.WithMessagef(err, "get online vehicles")
}
filter.Online.VINsOnline = vehicles
return nil
}
func getOnline(sessionKeys []string) ([]string, error) {
var onlineVehicles []string
redisCli := services.RedisClientPool().GetFromPool()
defer redisCli.Close()
batch := re.NewRedisBatchCommands()
for i := range sessionKeys {
batch.Add("SMEMBERS", sessionKeys[i])
}
vinOfVins, err := redis.Values(redisCli.ExecuteBatch(batch))
if err != nil {
return nil, errors.WithMessagef(err, "redis get multi failed for keys: %v", sessionKeys)
}
onlineVehicles = make([]string, 0)
for _, rvins := range vinOfVins {
setVehicles, err := redis.Strings(rvins, nil)
if err != nil {
return nil, errors.WithMessagef(err, "redis cast to string failed: %v", sessionKeys)
}
onlineVehicles = append(onlineVehicles, setVehicles...)
}
return onlineVehicles, nil
}
func parseCarsFilter(r *http.Request) (*common.CarSearch, error) {
qs := r.URL.Query()
filter := common.CarSearch{
Search: qs.Get("search"),
VINs: qs.Get("vins"),
Car: common.Car{
VIN: qs.Get("vin"),
Model: qs.Get("model"),
Year: urlhelper.GetQueryInt(qs, "year"),
},
}
var o *common.CarOnlineFilter
online, ok := urlhelper.GetQueryBool(qs, "online")
if ok {
if o == nil {
o = &common.CarOnlineFilter{}
}
o.Online = elptr.ElPtr(online)
}
onlineHMI, ok := urlhelper.GetQueryBool(qs, "online_hmi")
if ok {
if o == nil {
o = &common.CarOnlineFilter{}
}
o.HMI = elptr.ElPtr(onlineHMI)
}
filter.Online = o
err := validator.ValidateNonRequired(filter)
return &filter, err
}
func isNAProd() bool {
return envtool.GetEnv("IS_NA_PROD", "") != ""
}