All checks were successful
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Successful in 26s
467 lines
18 KiB
Go
467 lines
18 KiB
Go
package mysubaru
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"log/slog"
|
|
"slices"
|
|
"sync"
|
|
|
|
"git.savin.nyc/alex/mysubaru/config"
|
|
"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
|
|
isAlive bool
|
|
logger *slog.Logger
|
|
sync.RWMutex
|
|
}
|
|
|
|
// 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()
|
|
|
|
var sd SessionData
|
|
err := json.Unmarshal(resp.Data, &sd)
|
|
if err != nil {
|
|
client.logger.Error("error while parsing json", "request", "auth", "error", err.Error())
|
|
}
|
|
// client.logger.Debug("unmarshaled json data", "request", "auth", "type", "sessionData", "body", sd)
|
|
|
|
if sd.DeviceRegistered && sd.RegisteredDevicePermanent {
|
|
// client.logger.Debug("client authentication successful")
|
|
client.isAuthenticated = true
|
|
client.isRegistered = true
|
|
}
|
|
// TODO: Work on registerDevice()
|
|
// } else {
|
|
// // client.logger.Debug("client authentication successful, but devices is not registered")
|
|
// client.registerDevice()
|
|
// }
|
|
|
|
// client.logger.Debug("parsing cars assigned to the account", "quantity", len(sd.Vehicles))
|
|
if len(sd.Vehicles) > 0 {
|
|
for _, vehicle := range sd.Vehicles {
|
|
// client.logger.Debug("parsing car", "vin", vehicle.Vin)
|
|
client.listOfVins = append(client.listOfVins, vehicle.Vin)
|
|
}
|
|
client.currentVin = client.listOfVins[0]
|
|
} else {
|
|
client.logger.Error("there no cars assigned to the account")
|
|
return nil, err
|
|
}
|
|
return client, nil
|
|
}
|
|
|
|
// SelectVehicle .
|
|
func (c *Client) SelectVehicle(vin string) (*VehicleData, error) {
|
|
if vin == "" {
|
|
vin = c.currentVin
|
|
}
|
|
|
|
vinCheck(vin)
|
|
|
|
params := map[string]string{
|
|
"vin": vin,
|
|
"_": timestamp()}
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
|
|
// TODO: Add error handling
|
|
resp, _ := c.execute(GET, reqURL, params, false)
|
|
// c.logger.Debug("http request output", "request", "SelectVehicle", "body", resp)
|
|
|
|
var vd VehicleData
|
|
err := json.Unmarshal(resp.Data, &vd)
|
|
if err != nil {
|
|
c.logger.Error("error while parsing json", "request", "SelectVehicle", "error", err.Error())
|
|
return nil, errors.New("error while parsing json while vehicle selection")
|
|
}
|
|
// c.logger.Debug("http request output", "request", "SelectVehicle", "body", resp)
|
|
return &vd, nil
|
|
}
|
|
|
|
// GetVehicles .
|
|
func (c *Client) GetVehicles() []*Vehicle {
|
|
var vehicles []*Vehicle
|
|
for _, vin := range c.listOfVins {
|
|
vehicle, err := c.GetVehicleByVIN(vin)
|
|
if err != nil {
|
|
c.logger.Error("cannot get vehile data", "request", "SelectVehicle", "error", err.Error())
|
|
}
|
|
vehicles = append(vehicles, vehicle)
|
|
}
|
|
return vehicles
|
|
}
|
|
|
|
// GetVehicleByVIN .
|
|
func (c *Client) GetVehicleByVIN(vin string) (*Vehicle, error) {
|
|
var vehicle *Vehicle
|
|
if slices.Contains(c.listOfVins, vin) {
|
|
params := map[string]string{
|
|
"vin": vin,
|
|
"_": timestamp()}
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
|
|
// TODO: Add error handling
|
|
resp, _ := c.execute(GET, reqURL, params, false)
|
|
// c.logger.Debug("http request output", "request", "GetVehicleByVIN", "body", resp)
|
|
|
|
var vd VehicleData
|
|
err := json.Unmarshal(resp.Data, &vd)
|
|
if err != nil {
|
|
c.logger.Error("error while parsing json", "request", "GetVehicleByVIN", "error", err.Error())
|
|
}
|
|
// c.logger.Debug("http request output", "request", "GetVehicleByVIN", "body", resp)
|
|
|
|
vehicle = &Vehicle{
|
|
Vin: vin,
|
|
CarName: vd.VehicleName,
|
|
CarNickname: vd.Nickname,
|
|
ModelName: vd.ModelName,
|
|
ModelYear: vd.ModelYear,
|
|
ModelCode: vd.ModelCode,
|
|
ExtDescrip: vd.ExtDescrip,
|
|
IntDescrip: vd.IntDescrip,
|
|
TransCode: vd.TransCode,
|
|
EngineSize: vd.EngineSize,
|
|
VehicleKey: vd.VehicleKey,
|
|
LicensePlate: vd.LicensePlate,
|
|
LicensePlateState: vd.LicensePlateState,
|
|
Features: vd.Features,
|
|
SubscriptionFeatures: vd.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.Troubles = make(map[string]Trouble)
|
|
|
|
if vehicle.isEV() {
|
|
vehicle.EV = true
|
|
} else {
|
|
vehicle.EV = false
|
|
}
|
|
|
|
vehicle.GetVehicleStatus()
|
|
vehicle.GetVehicleCondition()
|
|
vehicle.GetVehicleHealth()
|
|
vehicle.GetClimatePresets()
|
|
vehicle.GetClimateUserPresets()
|
|
vehicle.GetClimateQuickPresets()
|
|
|
|
return vehicle, nil
|
|
}
|
|
c.logger.Error("vin code is not in the list of the available vin codes", "request", "GetVehicleByVIN")
|
|
return nil, errors.New("vin code is not in the list of the available vin codes")
|
|
}
|
|
|
|
// func isPINRequired() {}
|
|
// func getVehicles() {}
|
|
// func getEVStatus() {}
|
|
// func getRemoteOptionsStatus() {}
|
|
// func getRemoteStartStatus() {}
|
|
// func getSafetyStatus() {}
|
|
// func getSubscriptionStatus() {}
|
|
// func getClimateData() {}
|
|
// func saveClimateSettings() {}
|
|
|
|
func (c *Client) IsAlive() bool {
|
|
return c.isAlive
|
|
}
|
|
|
|
// Exec method executes a Client instance with the API URL
|
|
func (c *Client) execute(method string, url string, params map[string]string, j bool) (*Response, error) {
|
|
// defer timeTrack("[TIMETRK] Executing HTTP Request")
|
|
var resp *resty.Response
|
|
|
|
// GET Requests
|
|
if method == GET {
|
|
resp, _ = c.httpClient.
|
|
R().
|
|
SetQueryParams(params).
|
|
Get(url)
|
|
}
|
|
|
|
// POST Requests
|
|
if method == POST {
|
|
if j { // POST > JSON Body
|
|
resp, _ = c.httpClient.
|
|
R().
|
|
SetBody(params).
|
|
Post(url)
|
|
} else { // POST > Form Data
|
|
resp, _ = c.httpClient.
|
|
R().
|
|
SetFormData(params).
|
|
Post(url)
|
|
}
|
|
}
|
|
|
|
if resp.IsSuccess() {
|
|
resBytes, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
c.logger.Error("error while getting body", "error", err.Error())
|
|
}
|
|
c.logger.Debug("parsed http request output", "data", string(resBytes))
|
|
|
|
if r, ok := c.parseResponse(resBytes); ok {
|
|
c.isAlive = true
|
|
return &r, nil
|
|
} else {
|
|
if r.DataName == "errorResponse" {
|
|
var er ErrorResponse
|
|
err := json.Unmarshal(r.Data, &er)
|
|
if err != nil {
|
|
c.logger.Error("error while parsing json", "request", "errorResponse", "error", err.Error())
|
|
}
|
|
if _, ok := API_ERRORS[er.ErrorLabel]; ok {
|
|
c.logger.Error("request got an error", "request", "execute", "method", method, "url", url, "label", er.ErrorLabel, "descrip[tion", er.ErrorDescription)
|
|
}
|
|
c.logger.Error("request got an unknown error", "request", "execute", "method", method, "url", url, "label", er.ErrorLabel, "descrip[tion", er.ErrorDescription)
|
|
return nil, errors.New("request is not successfull, HTTP code: " + resp.Status())
|
|
}
|
|
c.logger.Error("request is not successfull", "request", "execute", "method", method, "url", url, "error", err.Error())
|
|
}
|
|
}
|
|
c.isAlive = false
|
|
return nil, errors.New("request is not successfull, HTTP code: " + resp.Status())
|
|
}
|
|
|
|
// auth .
|
|
func (c *Client) auth() *Response {
|
|
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, err := c.execute(POST, reqURL, params, false)
|
|
c.logger.Debug("AUTH HTTP OUTPUT", "body", resp)
|
|
if err != nil {
|
|
c.logger.Error("error while executing auth request", "request", "auth", "error", err.Error())
|
|
return nil
|
|
}
|
|
c.logger.Debug("AUTH HTTP OUTPUT", "body", resp)
|
|
return resp
|
|
}
|
|
|
|
// parseResponse .
|
|
func (c *Client) parseResponse(b []byte) (Response, bool) {
|
|
var r Response
|
|
err := json.Unmarshal(b, &r)
|
|
if err != nil {
|
|
c.logger.Error("error while parsing json", "error", err.Error())
|
|
return r, false
|
|
}
|
|
return r, true
|
|
}
|
|
|
|
// validateSession .
|
|
// TODO: add session validation process and add it to the proper functions
|
|
// func (c *Client) validateSession() bool {
|
|
// reqURL := MOBILE_API_VERSION + apiURLs["API_VALIDATE_SESSION"]
|
|
// resp := c.execute(reqURL, GET, map[string]string{}, "", false)
|
|
// // c.logger.Debug("http request output", "request", "validateSession", "body", resp)
|
|
|
|
// if r, ok := c.parseResponse(resp); ok {
|
|
// c.logger.Error("error while parsing json", "request", "validateSession", "error", err.Error())
|
|
// return true
|
|
// } else {
|
|
// resp := c.auth()
|
|
// return true
|
|
// }
|
|
// return false
|
|
// }
|
|
|
|
// 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"]
|
|
// resp, _ := c.execute(POST, reqURL, 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))
|
|
// // }
|
|
// }
|
|
|
|
// c.logger.Debug("parsed http request output", "data", r.Data)
|
|
|
|
// ERROR
|
|
// {"httpCode":500,"errorCode":"error","errorMessage":"org.springframework.web.HttpMediaTypeNotSupportedException - Content type 'application/x-www-form-urlencoded' not supported"}
|
|
// {"success":true,"errorCode":null,"dataName":"remoteServiceStatus","data":{"serviceRequestId":"4S4BTGND8L3137058_1640203129607_19_@NGTP","success":false,"cancelled":false,"remoteServiceType":"unlock","remoteServiceState":"started","subState":null,"errorCode":null,"result":null,"updateTime":null,"vin":"4S4BTGND8L3137058"}}
|
|
// API_REMOTE_SVC_STATUS
|
|
// {"success":false,"errorCode":"404-soa-unableToParseResponseBody","dataName":"errorResponse","data":{"errorLabel":"404-soa-unableToParseResponseBody","errorDescription":null}}
|
|
// if js_resp["errorCode"] == sc.ERROR_SOA_403:
|
|
// raise RemoteServiceFailure("Backend session expired, please try again")
|
|
// if js_resp["data"]["remoteServiceState"] == "finished":
|
|
// if js_resp["data"]["success"]:
|
|
// _LOGGER.info("Remote service request completed successfully: %s", req_id)
|
|
// return True, js_resp
|
|
// _LOGGER.error(
|
|
// "Remote service request completed but failed: %s Error: %s",
|
|
// req_id,
|
|
// js_resp["data"]["errorCode"],
|
|
// )
|
|
// raise RemoteServiceFailure(
|
|
// "Remote service request completed but failed: %s" % js_resp["data"]["errorCode"]
|
|
// )
|
|
// if js_resp["data"].get("remoteServiceState") == "started":
|
|
// _LOGGER.info(
|
|
// "Subaru API reports remote service request is in progress: %s",
|
|
// req_id,
|
|
// )
|
|
// attempts_left -= 1
|
|
// await asyncio.sleep(2)
|
|
|
|
// TODO: Work on errors
|
|
// 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")
|
|
// }
|