/
fuel_api_service.go
139 lines (119 loc) · 4.23 KB
/
fuel_api_service.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package gateways
import (
"fmt"
"io"
"net/http"
"strings"
"github.com/DIMO-Network/device-definitions-api/internal/config"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/tidwall/gjson"
)
//go:generate mockgen -source fuel_api_service.go -destination mocks/fuel_api_service_mock.go -package mocks
type FuelAPIService interface {
FetchDeviceImages(mk, mdl string, yr int, prodID int, prodFormat int) (FuelDeviceImages, error)
}
// fuelAPIService client
type fuelAPIService struct {
VehicleURL string
ImageURL string
Key string
log *zerolog.Logger
}
func NewFuelAPIService(settings *config.Settings, logger *zerolog.Logger) FuelAPIService {
return &fuelAPIService{
VehicleURL: settings.FuelAPIVehiclesEndpoint,
ImageURL: settings.FuelAPIImagesEndpoint,
Key: settings.FuelAPIKey,
log: logger,
}
}
func (fs *fuelAPIService) FetchDeviceImages(mk, mdl string, yr int, prodID int, prodFormat int) (FuelDeviceImages, error) {
notExactImage := false // if we pull image where year doesn't match
// search for exact MMY image
img, err := fs.imageRequest(mk, mdl, yr, prodID, prodFormat)
if err != nil {
return FuelDeviceImages{}, err
}
// search for model and make (remove year)
if !img.validURL {
img, err = fs.imageRequest(mk, mdl, 0, prodID, prodFormat)
if err != nil {
return FuelDeviceImages{}, err
}
notExactImage = true
// search for model and first work of make
// ex: Wrangler Sport -> Wrangler
if !img.validURL {
m := strings.Split(mdl, " ")
img, err = fs.imageRequest(mk, m[0], 0, prodID, prodFormat)
if err != nil {
return FuelDeviceImages{}, err
}
}
}
if !img.validURL {
fs.log.Log().Msgf("request for device image unsuccessful: %s %s %d", mk, mdl, yr)
return FuelDeviceImages{}, errors.New("request for device image unsuccessful")
}
img.NotExactImage = notExactImage
return img, nil
}
func (fs *fuelAPIService) imageRequest(mk, mdl string, yr int, prodID int, prodFormat int) (FuelDeviceImages, error) {
vehicleReqURL := fmt.Sprintf("?year=%d&make=%s&model=%s&api_key=%s", yr, mk, mdl, fs.Key)
vehicleResp, err := http.Get(fs.VehicleURL + vehicleReqURL)
if err != nil {
return FuelDeviceImages{}, err
}
if vehicleResp.StatusCode >= 400 {
fs.log.Info().Msgf("bad request status: %d", vehicleResp.StatusCode)
return FuelDeviceImages{}, errors.New("unable to fetch vehicle data: bad requset")
}
vehicleData, err := io.ReadAll(vehicleResp.Body)
if err != nil {
return FuelDeviceImages{}, err
}
vehicleID := gjson.Get(string(vehicleData), "0.id").Str
imageReqURL := fmt.Sprintf("/%s?api_key=%s&productID=%d&productFormatIDs=%d", vehicleID, fs.Key, prodID, prodFormat)
imageResp, err := http.Get(fs.ImageURL + imageReqURL)
if err != nil {
return FuelDeviceImages{}, err
}
if imageResp.StatusCode >= 400 {
fs.log.Info().Msgf("bad request status: %d", imageResp.StatusCode)
return FuelDeviceImages{}, errors.New("unable to fetch image: bad requset")
}
response, err := io.ReadAll(imageResp.Body)
if err != nil {
return FuelDeviceImages{}, err
}
imageData := string(response)
width := gjson.Get(imageData, "products.0.productFormats.0.width").Int()
height := gjson.Get(imageData, "products.0.productFormats.0.height").Int()
angle := gjson.Get(imageData, "products.0.productFormats.0.angle").String()
img := FuelDeviceImages{FuelAPIID: vehicleID, Width: int(width), Height: int(height), Angle: angle, Images: make([]FuelImage, 0)}
gjson.Get(imageData, "products.0.productFormats.0.assets").ForEach(func(_ gjson.Result, value gjson.Result) bool {
imageURL := value.Get("url").Str
color := value.Get("shotCode.color.simple_name").Str
img.Images = append(img.Images, FuelImage{SourceURL: imageURL, Color: color})
if !img.validURL && imageURL != "" {
img.validURL = true
}
return true
})
return img, nil
}
type FuelDeviceImages struct {
FuelAPIID string `boil:"fuelID"`
Width int `boil:"width"`
Height int `boil:"height"`
Angle string `boil:"angle"`
Images []FuelImage `boil:"images"`
validURL bool
// use to track if we used a different year image and could not find this one
NotExactImage bool
}
type FuelImage struct {
SourceURL string `boil:"sourceURL"`
Color string `boil:"color"`
}