306 lines
8.2 KiB
Go
306 lines
8.2 KiB
Go
package tncservice
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
|
|
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
|
|
"bitbucket.org/nemt/nemt-portal-api/application/notificationservice"
|
|
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
|
|
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
|
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
|
"github.com/lyft/lyft-go-sdk/lyft"
|
|
"github.com/pquerna/ffjson/ffjson"
|
|
"golang.org/x/oauth2"
|
|
"golang.org/x/oauth2/clientcredentials"
|
|
)
|
|
|
|
const (
|
|
lyftURL = "https://api.lyft.com/v1/"
|
|
)
|
|
|
|
// lyftService holds methods to lyft application service
|
|
type lyftService struct {
|
|
svc *service.Service
|
|
mapEntity *entitymapping.Mapper
|
|
client *lyft.APIClient
|
|
httpClient *http.Client
|
|
cfg *config.Config
|
|
notification *notificationservice.Service
|
|
lyftConfig clientcredentials.Config
|
|
refreshToken string
|
|
}
|
|
|
|
// newLyftProdService returns a lyftService instance with production info
|
|
func newLyftProdService(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, notificationService *notificationservice.Service) *lyftService {
|
|
config := clientcredentials.Config{
|
|
ClientID: cfg.LyftProd.Lyft.Client,
|
|
ClientSecret: cfg.LyftProd.Lyft.Secret,
|
|
TokenURL: "https://api.lyft.com/oauth/token",
|
|
Scopes: []string{"public", "privileged.rides.dispatch", "rides.read", "rides.request", "profile", "offline"},
|
|
}
|
|
httpClient := config.Client(context.Background())
|
|
|
|
return &lyftService{
|
|
svc: svc,
|
|
mapEntity: mapper,
|
|
client: lyft.NewAPIClient(httpClient, "nemt"),
|
|
httpClient: httpClient,
|
|
cfg: cfg,
|
|
notification: notificationService,
|
|
lyftConfig: config,
|
|
refreshToken: cfg.LyftProd.Lyft.RefreshToken,
|
|
}
|
|
}
|
|
|
|
// newLyftService returns a lyftService instance
|
|
func newLyftService(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, notificationService *notificationservice.Service) *lyftService {
|
|
config := clientcredentials.Config{
|
|
ClientID: cfg.Lyft.Client,
|
|
ClientSecret: cfg.Lyft.Secret,
|
|
TokenURL: "https://api.lyft.com/oauth/token",
|
|
Scopes: []string{"public", "privileged.rides.dispatch", "rides.read", "rides.request", "profile", "offline"},
|
|
}
|
|
httpClient := config.Client(context.Background())
|
|
|
|
return &lyftService{
|
|
svc: svc,
|
|
mapEntity: mapper,
|
|
client: lyft.NewAPIClient(httpClient, "nemt"),
|
|
httpClient: httpClient,
|
|
cfg: cfg,
|
|
notification: notificationService,
|
|
lyftConfig: config,
|
|
refreshToken: cfg.Lyft.RefreshToken,
|
|
}
|
|
}
|
|
|
|
func (s *lyftService) getToken() string {
|
|
token, err := s.lyftConfig.Token(context.Background())
|
|
if err != nil {
|
|
fmt.Println("Error to get token: ", err)
|
|
return ""
|
|
}
|
|
|
|
return "Bearer " + token.AccessToken
|
|
}
|
|
|
|
func (s *lyftService) setTokenHeader(req *http.Request) string {
|
|
type Token struct {
|
|
GrantType string `json:"grant_type"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
|
|
token := Token{
|
|
GrantType: "refresh_token",
|
|
RefreshToken: s.refreshToken,
|
|
}
|
|
|
|
bObject, err := ffjson.Marshal(token)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
tokenReq, err := http.NewRequest("POST", s.lyftConfig.TokenURL, bytes.NewBuffer(bObject))
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
tokenReq.Header.Set("Content-Type", "application/json")
|
|
tokenReq.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", s.lyftConfig.ClientID, s.lyftConfig.ClientSecret))))
|
|
tokenReq.Header.Add("cache-control", "no-cache")
|
|
|
|
resp, err := http.DefaultClient.Do(tokenReq)
|
|
if err != nil {
|
|
fmt.Println("Error to refresh token: ", err.Error())
|
|
return ""
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
|
|
|
var returnToken oauth2.Token
|
|
err = ffjson.Unmarshal(body, &returnToken)
|
|
if err != nil {
|
|
fmt.Println("Error to parse token: ", err.Error())
|
|
return ""
|
|
}
|
|
|
|
returnToken.SetAuthHeader(req)
|
|
|
|
return "Bearer " + returnToken.AccessToken
|
|
}
|
|
|
|
func (s *lyftService) GetRideDetails(rideRequest viewmodel.RideRequest) (viewmodel.RideRequest, error) {
|
|
url := lyftURL + "dispatches/" + rideRequest.RideID
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
s.setTokenHeader(req)
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
|
var raw viewmodel.RideRequest
|
|
err = ffjson.Unmarshal(body, &raw)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
|
|
return raw, nil
|
|
}
|
|
|
|
func (s *lyftService) GetRideStatus(rideRequest viewmodel.RideRequest, param string) (viewmodel.RideRequest, error) {
|
|
params := make(map[string]string)
|
|
params["status"] = param
|
|
|
|
bObject, err := ffjson.Marshal(params)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
|
|
fmt.Println("STATUS CHANGE REQUEST ON LYFT")
|
|
fmt.Println("Ride ID: ", rideRequest.RideID)
|
|
fmt.Println("Status: ", param)
|
|
url := lyftURL + "sandbox/dispatches/" + rideRequest.RideID
|
|
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(bObject))
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
resp, err := s.httpClient.Do(req)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
|
fmt.Println("STATUS CHANGE RESPONSE ON LYFT")
|
|
fmt.Println(string(body))
|
|
|
|
var raw viewmodel.RideRequest
|
|
err = ffjson.Unmarshal(body, &raw)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
|
|
rideRequest.Status = raw.Status
|
|
return s.GetRideDetails(rideRequest)
|
|
}
|
|
|
|
func (s *lyftService) CancelRide(rideRequest viewmodel.RideRequest) error {
|
|
finalURL := lyftURL + "dispatches/" + rideRequest.RideID + "/cancel"
|
|
req, err := http.NewRequest("POST", finalURL, bytes.NewBuffer([]byte{}))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.setTokenHeader(req)
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
|
|
|
if resp.StatusCode == 204 || resp.StatusCode == 404 {
|
|
if err != nil {
|
|
fmt.Println("Error: ", err)
|
|
}
|
|
|
|
return nil
|
|
} else {
|
|
fmt.Println("Response Body: ", string(body))
|
|
|
|
raw := map[string]interface{}{}
|
|
err = ffjson.Unmarshal(body, &raw)
|
|
if err != nil {
|
|
return err
|
|
} else {
|
|
return errors.New(raw["error_description"].(string))
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *lyftService) RequestRide(rideRequest viewmodel.RideRequest) (viewmodel.RideRequest, error) {
|
|
bObject, err := ffjson.Marshal(rideRequest)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", lyftURL+"dispatches", bytes.NewBuffer(bObject))
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
s.setTokenHeader(req)
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
|
|
|
var raw viewmodel.RideRequest
|
|
err = ffjson.Unmarshal(body, &raw)
|
|
if err != nil {
|
|
return viewmodel.RideRequest{}, err
|
|
}
|
|
|
|
if raw.Error != "" {
|
|
fmt.Println("Error to call Lyft: ", raw.Error+" - "+raw.ErrorDescription)
|
|
return viewmodel.RideRequest{}, errors.New("Lyft Error: " + raw.Error + " - " + raw.ErrorDescription)
|
|
}
|
|
|
|
return s.GetRideDetails(raw)
|
|
}
|
|
|
|
func (s *lyftService) GetETA(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
|
|
resp, _, err := s.client.PublicApi.GetETA(lag, log, params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *lyftService) GetCost(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
|
|
resp, _, err := s.client.PublicApi.GetCost(lag, log, params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *lyftService) GetDrivers(lag float64, log float64) (interface{}, error) {
|
|
resp, _, err := s.client.PublicApi.GetDrivers(lag, log)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *lyftService) GetTypes(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
|
|
resp, _, err := s.client.PublicApi.GetRideTypes(lag, log, params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|