Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
211
pkg/vehicleconfig/sap.go
Normal file
211
pkg/vehicleconfig/sap.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package vehicleconfig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"fiskerinc.com/modules/common"
|
||||
"fiskerinc.com/modules/common/staticerrors"
|
||||
"fiskerinc.com/modules/logger"
|
||||
"fiskerinc.com/modules/utils/envtool"
|
||||
)
|
||||
|
||||
func NewSAPService() SAPServiceInterface {
|
||||
return &SAPService{
|
||||
sapUser: envtool.GetEnv("SAP_USER", "REPLACE_ME"),
|
||||
sapPass: envtool.GetEnv("SAP_PASS", "REPLACE_ME"),
|
||||
sapURL: envtool.GetEnv("SAP_URL", "REPLACE_ME"),
|
||||
}
|
||||
}
|
||||
|
||||
type SAPServiceInterface interface {
|
||||
GetSAPOrder(vin string) (order common.VehicleOrder, err error)
|
||||
GetECUVersions(vin string) (versions map[string]string, err error)
|
||||
UpdateECUVersions(vin string, versions map[string]string) (err error)
|
||||
GetFeatureCodes(vin string) (common.SAPResponse, error)
|
||||
SubmitResult(vin string, success bool) (err error)
|
||||
SubmitCarFlashpackVersion(vin string, previousFlashpack string, flashpack string) error
|
||||
}
|
||||
|
||||
// This is currently a mock of the actual calls to the SAP and the ODX parser services
|
||||
type SAPService struct {
|
||||
sapUser string
|
||||
sapPass string
|
||||
sapURL string
|
||||
}
|
||||
|
||||
type SAPSubmitResultBody struct {
|
||||
VIN string `json:"vin" validate:"required,vin"`
|
||||
DateTime string `json:"dateTime"`
|
||||
Flag string `json:"flag"`
|
||||
}
|
||||
|
||||
type SAPSubmitCarFlashpackVersionBody struct {
|
||||
VIN string `json:"vin" validate:"required,vin"`
|
||||
CreatedOn string `json:"createdOn"`
|
||||
CurrentSWV string `json:"currentSWV"`
|
||||
PreviousSWV string `json:"previousSWV"`
|
||||
ModeOfSWU string `json:"modeOfSWU"`
|
||||
}
|
||||
|
||||
// Returns the current vehicle order from SAP
|
||||
func (cs *SAPService) GetSAPOrder(vin string) (order common.VehicleOrder, err error) {
|
||||
var result common.OrderUpdated
|
||||
err = xml.Unmarshal([]byte(vehicleOrder), &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
order = result.VehicleOrder
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the current ECU versions for a car
|
||||
func (cs *SAPService) GetECUVersions(vin string) (versions map[string]string, err error) {
|
||||
versions = map[string]string{}
|
||||
for _, ecu := range ecus {
|
||||
versions[ecu] = "10000"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Submits the updated ECU versions for a car back to SAP
|
||||
func (cs *SAPService) UpdateECUVersions(vin string, versions map[string]string) (err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *SAPService) GetFeatureCodes(vin string) (common.SAPResponse, error) {
|
||||
headers := http.Header{}
|
||||
headers.Add("Authorization", cs.createToken())
|
||||
url := fmt.Sprintf("%s/vehicleSpec?vin=%s", cs.sapURL, vin)
|
||||
|
||||
request, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return common.SAPResponse{}, errors.WithStack(err)
|
||||
}
|
||||
|
||||
client := createHttpClient()
|
||||
request.Header = headers
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return common.SAPResponse{}, errors.WithStack(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return common.SAPResponse{}, errors.WithStack(fmt.Errorf(staticerrors.ErrorSAPFailedCall+" with status: %s", resp.Status))
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return common.SAPResponse{}, errors.WithStack(err)
|
||||
}
|
||||
|
||||
respPayload := common.SAPResponse{}
|
||||
err = json.Unmarshal(respBody, &respPayload)
|
||||
if err != nil {
|
||||
return common.SAPResponse{}, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return respPayload, nil
|
||||
}
|
||||
|
||||
func (cs *SAPService) SubmitResult(vin string, success bool) (err error) {
|
||||
headers := http.Header{}
|
||||
headers.Add("Authorization", cs.createToken())
|
||||
headers.Add("Content-Type", "application/json")
|
||||
|
||||
timeNow := time.Now()
|
||||
formattedTime := timeNow.Format("2006-01-02T15:04:05")
|
||||
|
||||
body := &SAPSubmitResultBody{
|
||||
VIN: vin,
|
||||
DateTime: formattedTime,
|
||||
Flag: "not completed",
|
||||
}
|
||||
if success {
|
||||
body.Flag = "completed"
|
||||
}
|
||||
|
||||
bodyJSON, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return cs.submit("vehicleSpecAck", bodyJSON, http.StatusOK)
|
||||
}
|
||||
|
||||
func (cs *SAPService) SubmitCarFlashpackVersion(vin string, previousFlashpack string, flashpack string) error {
|
||||
timeNow := time.Now()
|
||||
formattedTime := timeNow.Format("2006-01-02T15:04:05.999999Z")
|
||||
body := &SAPSubmitCarFlashpackVersionBody{
|
||||
VIN: vin,
|
||||
CreatedOn: formattedTime,
|
||||
PreviousSWV: previousFlashpack,
|
||||
CurrentSWV: flashpack,
|
||||
ModeOfSWU: "OTA",
|
||||
}
|
||||
|
||||
bodyJSON, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return cs.submit("swVersionUpdate", bodyJSON, http.StatusCreated)
|
||||
}
|
||||
|
||||
func (cs *SAPService) submit(endpoint string, bodyJSON []byte, successStatus int) error {
|
||||
headers := http.Header{}
|
||||
headers.Add("Authorization", cs.createToken())
|
||||
headers.Add("Content-Type", "application/json")
|
||||
url := fmt.Sprintf("%s/%s", cs.sapURL, endpoint)
|
||||
|
||||
request, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(bodyJSON))
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
client := createHttpClient()
|
||||
request.Header = headers
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != successStatus {
|
||||
return errors.WithStack(fmt.Errorf(staticerrors.ErrorSAPFailedCall+" with status: %s and payload: %s", resp.Status, string(bodyJSON)))
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.Info().Msg(fmt.Sprintf("sap service has been notified at %s of car update: %s", endpoint, string(respBody)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *SAPService) createToken() string {
|
||||
token := base64.StdEncoding.EncodeToString([]byte(cs.sapUser + ":" + cs.sapPass))
|
||||
return fmt.Sprintf("Basic %s", token)
|
||||
}
|
||||
|
||||
func createHttpClient() http.Client {
|
||||
transport := http.DefaultTransport.(*http.Transport)
|
||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
return http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user