Files
mysubaru/client.go
Alex Savin 48b7379770
All checks were successful
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Successful in 23s
Continue work on the Climate Settings
2025-05-29 15:20:44 -04:00

662 lines
24 KiB
Go

package mysubaru
import (
"encoding/json"
"fmt"
"io"
"log/slog"
"sync"
"time"
"git.savin.nyc/alex/mysubaru/config"
"github.com/Jeffail/gabs/v2"
"resty.dev/v3"
)
// Client .
type Client struct {
credentials config.Credentials
httpClient *resty.Client
country string // USA | CA
updateInterval int // 7200
fetchInterval int // 360
currentVin string
listOfVins []string
isAuthenticated bool
isRegistered bool
logger *slog.Logger
sync.RWMutex
}
// auth .
func (c *Client) auth() []byte {
params := map[string]string{
"env": "cloudprod",
"deviceType": "android",
"loginUsername": c.credentials.Username,
"password": c.credentials.Password,
"deviceId": c.credentials.DeviceID,
"passwordToken": "",
"selectedVin": "",
"pushToken": ""}
reqURL := MOBILE_API_VERSION + apiURLs["API_LOGIN"]
resp := c.execute(reqURL, POST, params, "", false)
c.logger.Debug("AUTH HTTP OUTPUT", "body", string([]byte(resp)))
return resp
}
// GET
// https://www.mysubaru.com/profile/verifyDeviceName.json?clientId=2574212&deviceName=Alex%20Google%20Pixel%204%20XL
// RESP: true/false
// POST
// https://www.mysubaru.com/profile/editDeviceName.json?clientId=2574212&deviceName=Alex%20Google%20Pixel%204%20XL
// clientId: 2574212
// deviceName: Alex Google Pixel 4 XL
// RESP: true/false
// GET
// https://www.mysubaru.com/listMyDevices.json
// {"success":true,"dataName":"authorizedDevices","data":[{"telematicsClientDeviceKey":2574212,"deviceType":"android","deviceName":"Alex Google Pixel 4 XL","createdDate":"2019-11-29T20:32:21.000+0000","modifiedDate":"2020-06-08T17:48:22.000+0000"},{"telematicsClientDeviceKey":4847533,"deviceName":"Home Assistant: Added 2021-03-03","createdDate":"2021-03-03T20:53:44.000+0000","modifiedDate":"2021-03-03T20:53:47.000+0000"},{"telematicsClientDeviceKey":7222995,"deviceType":"android","deviceName":"Alex Google Pixel 6 Pro","createdDate":"2021-10-28T15:27:36.000+0000","modifiedDate":"2021-10-28T15:27:58.000+0000"},{"telematicsClientDeviceKey":8207130,"deviceName":"Mac/iOS Chrome","createdDate":"2021-12-21T21:19:40.000+0000","modifiedDate":"2021-12-21T21:19:40.000+0000"}]}
// {"success":true,"dataName":"authorizedDevices","data":[{"telematicsClientDeviceKey":2574212,"deviceType":"android","deviceName":"Alex Google Pixel 4 XL","createdDate":"2019-11-29T20:32:21.000+0000","modifiedDate":"2020-06-08T17:48:22.000+0000"},{"telematicsClientDeviceKey":4847533,"deviceName":"Home Assistant: Added 2021-03-03","createdDate":"2021-03-03T20:53:44.000+0000","modifiedDate":"2021-03-03T20:53:47.000+0000"},{"telematicsClientDeviceKey":7222995,"deviceType":"android","deviceName":"Alex Google Pixel 6 Pro","createdDate":"2021-10-28T15:27:36.000+0000","modifiedDate":"2021-10-28T15:27:58.000+0000"},{"telematicsClientDeviceKey":8210723,"deviceName":"Hassio Golang Integration","createdDate":"2021-12-22T01:38:43.000+0000","modifiedDate":"2021-12-22T01:38:43.000+0000"},{"telematicsClientDeviceKey":8207130,"deviceName":"Mac/iOS Chrome","createdDate":"2021-12-21T21:19:40.000+0000","modifiedDate":"2021-12-21T21:19:40.000+0000"}]}
// registerDevice .
func (c *Client) registerDevice() bool {
// c.httpClient.
// SetBaseURL(WEB_API_SERVER[c.country]).
// R().
// SetFormData(map[string]string{
// "username": c.credentials.username,
// "password": c.credentials.password,
// "deviceId": c.credentials.deviceId,
// }).
// Post(apiURLs["WEB_API_LOGIN"])
params := map[string]string{
"username": c.credentials.Username,
"password": c.credentials.Password,
"deviceId": c.credentials.DeviceID}
reqURL := WEB_API_SERVER[c.country] + apiURLs["WEB_API_LOGIN"]
c.execute(reqURL, POST, params, "", true)
// Authorizing device via web API
// c.httpClient.
// SetBaseURL(WEB_API_SERVER[c.country]).
// R().
// SetQueryParams(map[string]string{
// "deviceId": c.credentials.deviceId,
// }).
// Get(apiURLs["WEB_API_AUTHORIZE_DEVICE"])
params = map[string]string{
"deviceId": c.credentials.DeviceID}
reqURL = WEB_API_SERVER[c.country] + apiURLs["WEB_API_AUTHORIZE_DEVICE"]
c.execute(reqURL, GET, params, "", false)
return c.setDeviceName()
}
// setDeviceName .
func (c *Client) setDeviceName() bool {
params := map[string]string{
"deviceId": c.credentials.DeviceID,
"deviceName": c.credentials.DeviceName}
reqURL := WEB_API_SERVER[c.country] + apiURLs["WEB_API_NAME_DEVICE"]
c.execute(reqURL, GET, params, "", false)
return true
}
// listDevices .
func (c *Client) listDevices() {
// Accept: application/json, text/javascript, */*; q=0.01
// Accept-Encoding: gzip, deflate, br
// Accept-Language: en-US,en;q=0.9,ru;q=0.8
// Connection: keep-alive
// Cookie: ORA_OTD_JROUTE=ozLwELf5jS-NHQ2CKZorOFfRgb8uo6lL; soa-visitor=12212021VHWnkqERZYThWe87TLUhr2Db; AMCVS_94001C8B532957140A490D4D%40AdobeOrg=1; mys-referringCodes=7~direct~; s_cc=true; AMCVS_subarucom%40AdobeOrg=1; style=null; s_pv=login.html; AMCV_subarucom%40AdobeOrg=-1124106680%7CMCIDTS%7C18988%7CMCMID%7C81535064704660726005836131001032500276%7CMCAID%7CNONE%7CMCOPTOUT-1640567559s%7CNONE%7CvVersion%7C5.2.0; AMCV_94001C8B532957140A490D4D%40AdobeOrg=-1124106680%7CMCIDTS%7C18988%7CMCMID%7C76913534164341455390435376071204508177%7CMCAID%7CNONE%7CMCOPTOUT-1640567559s%7CNONE%7CvVersion%7C5.2.0; s_sq=subarumysubarucwpprod%3D%2526c.%2526a.%2526activitymap.%2526page%253Dlogin.html%2526link%253DLog%252520In%2526region%253DloginForm%2526pageIDType%253D1%2526.activitymap%2526.a%2526.c%2526pid%253Dlogin.html%2526pidt%253D1%2526oid%253DLog%252520In%2526oidt%253D3%2526ot%253DSUBMIT; JSESSIONID=9685CFEB7888A0E6E25239D559E3B580; X-Oracle-BMC-LBS-Route=89e3283ece707e8a0ba4850e1a622122e039fd3d27da03a11a2ff120e313e9b656c62fd8a7c42ae8061a49ad6e1caf63a49d7befe4ad2a0194b0aeca
// Host: www.mysubaru.com
// Referer: https://www.mysubaru.com/profile/authorizedDevices.html
// User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
// X-Requested-With: XMLHttpRequest
resp, err := c.httpClient.
SetBaseURL(WEB_API_SERVER[c.country]).
R().
EnableTrace().
Get(apiURLs["WEB_API_LIST_DEVICES"])
// Explore response object
fmt.Println("Response Info:")
fmt.Println(" Error :", err)
fmt.Println(" Status Code:", resp.StatusCode())
fmt.Println(" Status :", resp.Status())
fmt.Println(" Proto :", resp.Proto())
fmt.Println(" Time :", resp.Duration())
fmt.Println(" Received At:", resp.ReceivedAt())
// fmt.Println(" Body :\n", resp)
fmt.Println()
// Explore trace info
fmt.Println("Request Trace Info:")
ti := resp.Request.TraceInfo()
fmt.Println(" DNSLookup :", ti.DNSLookup)
fmt.Println(" ConnTime :", ti.ConnTime)
fmt.Println(" TCPConnTime :", ti.TCPConnTime)
fmt.Println(" TLSHandshake :", ti.TLSHandshake)
fmt.Println(" ServerTime :", ti.ServerTime)
fmt.Println(" ResponseTime :", ti.ResponseTime)
fmt.Println(" TotalTime :", ti.TotalTime)
fmt.Println(" IsConnReused :", ti.IsConnReused)
fmt.Println(" IsConnWasIdle :", ti.IsConnWasIdle)
fmt.Println(" ConnIdleTime :", ti.ConnIdleTime)
fmt.Println(" RequestAttempt:", ti.RequestAttempt)
fmt.Println(" RemoteAddr :", ti.RemoteAddr)
// c.logger.Debug("LIST DEVICES OUTPUT", "body", string([]byte(resp.Body())))
// c.httpClient.SetBaseURL(WEB_API_SERVER[c.country]).SetCookies(c.cookies)
// reqURL := apiURLs["WEB_API_LIST_DEVICES"]
// resp := c.execute(reqURL, GET, map[string]string{}, "", false)
// if isResponseSuccessfull(resp) {
// logger.Debugf("LIST DEVICES OUTPUT >> %v\n", string(resp))
// }
}
// validateSession .
func (c *Client) validateSession() bool {
// {
// "success": true,
// "errorCode": null,
// "dataName": null,
// "data": null
// }
reqURL := MOBILE_API_VERSION + apiURLs["API_VALIDATE_SESSION"]
resp := c.execute(reqURL, GET, map[string]string{}, "", false)
if !c.isResponseSuccessfull(resp) {
return false
}
// result = False
// js_resp = await self.__open(API_VALIDATE_SESSION, GET)
// _LOGGER.debug(pprint.pformat(js_resp))
// if js_resp["success"]:
// if vin != self._current_vin:
// # API call for VIN that is not the current remote context.
// _LOGGER.debug("Switching Subaru API vehicle context to: %s", vin)
// if await self._select_vehicle(vin):
// result = True
// else:
// result = True
// if result is False:
// await self._authenticate(vin)
// # New session cookie. Must call selectVehicle.json before any other API call.
// if await self._select_vehicle(vin):
// result = True
c.logger.Debug("session validation", "body", string([]byte(resp)))
return true
}
// New function creates a New MySubaru client
func New(config *config.Config) (*Client, error) {
client := &Client{
credentials: config.MySubaru.Credentials,
country: config.MySubaru.Region,
updateInterval: 7200,
fetchInterval: 360,
logger: config.Logger,
}
httpClient := resty.New()
httpClient.
SetBaseURL(MOBILE_API_SERVER[client.country]).
SetHeaders(map[string]string{
"User-Agent": "Mozilla/5.0 (Linux; Android 10; Android SDK built for x86 Build/QSR1.191030.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36",
"Origin": "file://",
"X-Requested-With": MOBILE_APP[client.country],
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate",
"Accept": "*/*"})
client.httpClient = httpClient
resp := client.auth()
respParsed, err := gabs.ParseJSON(resp)
if err != nil {
client.logger.Error("error while parsing json", "request", "auth", "error", err.Error())
}
if client.isResponseSuccessfull(resp) {
client.logger.Debug("Client authentication successful", "isRegistered", respParsed.Path("data.deviceRegistered").Data().(bool))
client.isAuthenticated = true
client.isRegistered = respParsed.Path("data.deviceRegistered").Data().(bool)
} else {
error, _ := respParsed.Path("errorCode").Data().(string)
switch {
case error == apiErrors["ERROR_INVALID_ACCOUNT"]:
client.logger.Debug("Invalid account")
case error == apiErrors["ERROR_INVALID_CREDENTIALS"]:
client.logger.Debug("Client authentication failed")
case error == apiErrors["ERROR_PASSWORD_WARNING"]:
client.logger.Debug("Multiple Password Failures.")
default:
client.logger.Debug("Uknown error")
}
}
if !client.isRegistered {
client.registerDevice()
}
// TODO: create a list of the car with currently present data
client.logger.Debug("parcing cars assigned to the account", "quantity", len(respParsed.Path("data.vehicles").Children()))
for _, vehicle := range respParsed.Path("data.vehicles").Children() {
client.logger.Debug("parsing car", "vin", vehicle.Path("vin").Data().(string))
client.listOfVins = append(client.listOfVins, vehicle.Path("vin").Data().(string))
}
client.currentVin = respParsed.Path("data.vehicles.0.vin").Data().(string)
return client, nil
}
func (c *Client) SelectVehicle(vin string) VehicleData {
// API > json > dataName > vehicle
if vin == "" {
vin = c.currentVin
}
vinCheck(vin)
params := map[string]string{
"vin": vin,
"_": timestamp()}
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
resp := c.execute(reqURL, GET, params, "", false)
var vData VehicleData
respParsed, err := gabs.ParseJSON([]byte(resp))
if err != nil {
panic(err)
}
c.logger.Debug("http request output", "request", "SelectVehicle", "body", respParsed)
vdString := respParsed.Path("data").String()
json.Unmarshal([]byte(vdString), &vData)
// resp := c.execute(reqURL, GET, params, "", false)
// logger.Debugf("SELECT VEHICLE OUTPUT >> %v\n", string([]byte(resp)))
// ERRORS
// {"success":false,"errorCode":"vehicleNotInAccount","dataName":null,"data":null}
// """Select active vehicle for accounts with multiple VINs."""
// params = {"vin": vin, "_": int(time.time())}
// js_resp = await self.get(API_SELECT_VEHICLE, params=params)
// _LOGGER.debug(pprint.pformat(js_resp))
// if js_resp.get("success"):
// self._current_vin = vin
// _LOGGER.debug("Current vehicle: vin=%s", js_resp["data"]["vin"])
// return js_resp["data"]
// if not js_resp.get("success") and js_resp.get("errorCode") == "VEHICLESETUPERROR":
// # Occasionally happens every few hours. Resetting the session seems to deal with it.
// _LOGGER.warning("VEHICLESETUPERROR received. Resetting session.")
// self.reset_session()
// return False
// _LOGGER.debug("Failed to switch vehicle errorCode=%s", js_resp.get("errorCode"))
// # Something else is probably wrong with the backend server context - try resetting
// self.reset_session()
// raise SubaruException("Failed to switch vehicle %s - resetting session." % js_resp.get("errorCode"))
return vData
}
// GetVehicles .
func (c *Client) GetVehicles() []*Vehicle {
var vehicles []*Vehicle
for _, vin := range c.listOfVins {
params := map[string]string{
"vin": vin,
"_": timestamp()}
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
resp := c.execute(reqURL, GET, params, "", false)
respParsed, err := gabs.ParseJSON([]byte(resp))
if err != nil {
c.logger.Error("error while parsing json", "request", "GetVehicles", "error", err.Error())
}
c.logger.Debug("http request output", "request", "GetVehicles", "body", respParsed)
vData := VehicleData{}
vdString := respParsed.Path("data").String()
json.Unmarshal([]byte(vdString), &vData)
// fmt.Printf("VEHICLE STRING: %+v\n\n", vdString)
// fmt.Printf("VEHICLE DATA: %+v\n\n", vData)
vehicle := &Vehicle{
Vin: vin,
CarName: vData.VehicleName,
CarNickname: vData.Nickname,
ModelName: vData.ModelName,
ModelYear: vData.ModelYear,
ModelCode: vData.ModelCode,
ExtDescrip: vData.ExtDescrip,
IntDescrip: vData.IntDescrip,
TransCode: vData.TransCode,
EngineSize: vData.EngineSize,
VehicleKey: vData.VehicleKey,
LicensePlate: vData.LicensePlate,
LicensePlateState: vData.LicensePlateState,
Features: vData.Features,
SubscriptionFeatures: vData.SubscriptionFeatures,
client: c,
}
vehicle.GetVehicleStatus()
vehicle.GetVehicleCondition()
// vehicle.GetClimatePresets()
vehicle.GetClimateUserPresets()
vehicle.GetClimateQuickPresets()
vehicles = append(vehicles, vehicle)
}
return vehicles
}
// GetVehicleByVIN .
func (c *Client) GetVehicleByVIN(vin string) *Vehicle {
var vehicle *Vehicle
if contains(c.listOfVins, vin) {
params := map[string]string{
"vin": vin,
"_": timestamp()}
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
resp := c.execute(reqURL, GET, params, "", false)
respParsed, err := gabs.ParseJSON([]byte(resp))
if err != nil {
c.logger.Error("error while parsing json", "request", "GetVehicleByVIN", "error", err.Error())
}
c.logger.Debug("http request output", "request", "GetVehicleByVIN", "body", respParsed)
vData := VehicleData{}
vdString := respParsed.Path("data").String()
json.Unmarshal([]byte(vdString), &vData)
vehicle = &Vehicle{
Vin: vin,
CarName: vData.VehicleName,
CarNickname: vData.Nickname,
ModelName: vData.ModelName,
ModelYear: vData.ModelYear,
ModelCode: vData.ModelCode,
ExtDescrip: vData.ExtDescrip,
IntDescrip: vData.IntDescrip,
TransCode: vData.TransCode,
EngineSize: vData.EngineSize,
VehicleKey: vData.VehicleKey,
LicensePlate: vData.LicensePlate,
LicensePlateState: vData.LicensePlateState,
Features: vData.Features,
SubscriptionFeatures: vData.SubscriptionFeatures,
client: c,
}
vehicle.Doors = make(map[string]Door)
vehicle.Windows = make(map[string]Window)
vehicle.Tires = make(map[string]Tire)
vehicle.ClimateProfiles = make(map[string]ClimateProfile)
vehicle.GetVehicleStatus()
vehicle.GetVehicleCondition()
// vehicle.GetClimatePresets()
vehicle.GetClimateUserPresets()
vehicle.GetClimateQuickPresets()
}
return vehicle
}
// GetVehicleStatus .
func (c *Client) GetVehicleStatus() {
// {
// "dataName": null,
// "errorCode": null,
// "success": true,
// "data": {
// "avgFuelConsumptionLitersPer100Kilometers": 12.5,
// "avgFuelConsumptionMpg": 18.8,
// "distanceToEmptyFuelKilometers": 563,
// "distanceToEmptyFuelKilometers10s": 560,
// "distanceToEmptyFuelMiles": 349.83,
// "distanceToEmptyFuelMiles10s": 350,
// "evDistanceToEmptyByStateKilometers": null,
// "evDistanceToEmptyByStateMiles": null,
// "evDistanceToEmptyKilometers": null,
// "evDistanceToEmptyMiles": null,
// "evStateOfChargePercent": null,
// "eventDate": 1640494569000,
// "eventDateStr": "2021-12-26T04:56+0000",
// "latitude": 40.700192,
// "longitude": -74.401377,
// "odometerValue": 24065,
// "odometerValueKilometers": 38721,
// "positionHeadingDegree": "150",
// "tirePressureFrontLeft": "2413",
// "tirePressureFrontLeftPsi": "35",
// "tirePressureFrontRight": "2413",
// "tirePressureFrontRightPsi": "35",
// "tirePressureRearLeft": "2551",
// "tirePressureRearLeftPsi": "37",
// "tirePressureRearRight": "2482",
// "tirePressureRearRightPsi": "36",
// "vehicleStateType": "IGNITION_OFF",
// "vhsId": 923920223
// }
// }
reqURL := MOBILE_API_VERSION + apiURLs["API_VEHICLE_STATUS"]
resp := c.execute(reqURL, GET, map[string]string{}, "", false)
respParsed, err := gabs.ParseJSON(resp)
if err != nil {
c.logger.Error("error while parsing json", "request", "GetVehicleStatus", "error", err.Error())
}
c.logger.Debug("GET VEHICLE STATUS OUTPUT", "body", respParsed)
success, ok := respParsed.Path("success").Data().(bool)
// value == string, ok == false
if !ok {
// TODO: Work with errorCode
panic(success)
}
}
// // GetClimateSettings .
// func (c *Client) GetClimateSettings() {
// // {
// // "success": true,
// // "errorCode": null,
// // "dataName": null,
// // "data": {
// // "climateZoneFrontTemp": "70",
// // "runTimeMinutes": "10",
// // "climateZoneFrontAirMode": "WINDOW",
// // "heatedSeatFrontLeft": "LOW_HEAT",
// // "heatedSeatFrontRight": "LOW_HEAT",
// // "heatedRearWindowActive": "true",
// // "climateZoneFrontAirVolume": "6",
// // "outerAirCirculation": "outsideAir",
// // "airConditionOn": "false",
// // "startConfiguration": "START_ENGINE_ALLOW_KEY_IN_IGNITION"
// // }
// // }
// reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_CLIMATE_SETTINGS"]
// resp := c.execute(reqURL, GET, map[string]string{}, "", false)
// respParsed, err := gabs.ParseJSON(resp)
// if err != nil {
// c.logger.Error("error while parsing json", "request", "GetClimateSettings", "error", err.Error())
// }
// c.logger.Debug("CLIMATE SETTINGS OUTPUT", "response", respParsed)
// // ONLY FOR THAT REQUEST BECAUSE OF API SENDS BACK ESCAPING DATA IN DATA FIELD
// data, ok := respParsed.Path("data").Data().(string)
// // rawIn := json.RawMessage(in)
// // bytes, err := rawIn.MarshalJSON()
// // if err != nil {
// // panic(err)
// // }
// // value == string, ok == false
// if !ok {
// // TODO: Work with errorCode
// panic(data)
// }
// c.logger.Debug("CLIMATE SETTINGS OUTPUT", "body", data)
// }
// func isPINRequired() {}
// func getVehicles() {}
// func getEVStatus() {}
// func getRemoteOptionsStatus() {}
// func getRemoteStartStatus() {}
// func getSafetyStatus() {}
// func getSubscriptionStatus() {}
// func getAPIGen() {}
// func getClimateData() {}
// func saveClimateSettings() {}
// func getVehicleName() {}
// func fetch() {}
// Exec method executes a Client instance with the API URL
func (c *Client) execute(requestUrl string, method string, params map[string]string, pollingUrl string, json bool) []byte {
defer timeTrack("[TIMETRK] Executing Get Request")
var resp *resty.Response
// GET Requests
if method == "GET" {
resp, _ = c.httpClient.
// SetBaseURL(MOBILE_API_SERVER[c.country]).
R().
SetQueryParams(params).
Get(requestUrl)
}
// POST Requests
if method == "POST" {
if json {
// POST > JSON Body
resp, _ = c.httpClient.
R().
SetBody(params).
Post(requestUrl)
} else {
// POST > Form Data
resp, _ = c.httpClient.
R().
SetFormData(params).
Post(requestUrl)
}
}
resBytes, err := io.ReadAll(resp.Body)
if err != nil {
c.logger.Error("error while getting body", "error", err.Error())
}
respParsed, err := gabs.ParseJSON(resBytes)
if err != nil {
c.logger.Error("error while parsing json", "request", "execute", "method", method, "url", requestUrl, "error", err.Error())
}
// c.logger.Debug("HTTP OUTPUT", "body", string(resBytes))
_, ok := respParsed.Path("success").Data().(bool)
// value == string, ok == false
if !ok {
// TODO: Work with errorCode
// panic(success)
fmt.Printf("ERROR: %+v", string(resBytes))
}
if pollingUrl != "" {
serviceRequestId, _ := respParsed.Path("data.serviceRequestId").Data().(string)
time.Sleep(3 * time.Second)
attempts := 20
poolingLoop:
for attempts > 0 {
resp, _ = c.httpClient.
SetBaseURL(MOBILE_API_SERVER[c.country]).
R().
SetQueryParams(map[string]string{
"serviceRequestId": serviceRequestId,
}).
Get(pollingUrl)
resBytes, _ := io.ReadAll(resp.Body)
c.logger.Debug("POLLING HTTP OUTPUT", "body", string(resBytes))
// {"success":false,"errorCode":"404-soa-unableToParseResponseBody","dataName":"errorResponse","data":{"errorLabel":"404-soa-unableToParseResponseBody","errorDescription":null}}
respParsed, err := gabs.ParseJSON(resBytes)
if err != nil {
panic(err)
}
success, ok := respParsed.Path("success").Data().(bool)
if !ok {
panic(success)
}
if success {
status, _ := respParsed.Path("data.remoteServiceState").Data().(string)
switch {
case status == "finished":
c.logger.Debug("Remote service request completed successfully", "request id", serviceRequestId)
break poolingLoop
case status == "started":
c.logger.Debug("Subaru API reports remote service request is in progress", "request id", serviceRequestId)
}
} else {
c.logger.Debug("Backend session expired, please try again")
break poolingLoop
}
attempts--
time.Sleep(3 * time.Second)
}
}
return resBytes
}
// isResponseSuccessfull .
func (c *Client) isResponseSuccessfull(resp []byte) bool {
respParsed, err := gabs.ParseJSON(resp)
if err != nil {
c.logger.Debug("error while parsing json response", "error", err)
}
success, ok := respParsed.Path("success").Data().(bool)
if !ok {
c.logger.Debug("response is not successful", "error", resp)
}
// ERRORS FROM CLIENT CREATION AFTER AUTH
// error, _ := respParsed.Path("errorCode").Data().(string)
// switch {
// case error == apiErrors["ERROR_INVALID_ACCOUNT"]:
// fmt.Println("Invalid account")
// case error == apiErrors["ERROR_INVALID_CREDENTIALS"]:
// {"success":false,"errorCode":"InvalidCredentials","dataName":"remoteServiceStatus","data":{"serviceRequestId":null,"success":false,"cancelled":false,"remoteServiceType":null,"remoteServiceState":null,"subState":null,"errorCode":null,"result":null,"updateTime":null,"vin":null,"errorDescription":"The credentials supplied are invalid, tries left 2"}}
// fmt.Println("Client authentication failed")
// case error == apiErrors["ERROR_PASSWORD_WARNING"]:
// fmt.Println("Multiple Password Failures.")
// default:
// fmt.Println("Uknown error")
// }
return success
}