initial commit 2
This commit is contained in:
305
application/tncservice/lyft.go
Normal file
305
application/tncservice/lyft.go
Normal file
@@ -0,0 +1,305 @@
|
||||
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
|
||||
}
|
||||
33
application/tncservice/tncservice.go
Normal file
33
application/tncservice/tncservice.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package tncservice
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/notificationservice"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||
)
|
||||
|
||||
var (
|
||||
instance *Service
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// Service holds the domain service repositories
|
||||
type Service struct {
|
||||
Lyft *lyftService
|
||||
LyftProd *lyftService
|
||||
}
|
||||
|
||||
// New returns a new domain Service instance
|
||||
func New(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, notificationService *notificationservice.Service) *Service {
|
||||
once.Do(func() {
|
||||
instance = &Service{
|
||||
Lyft: newLyftService(svc, mapper, cfg, notificationService),
|
||||
LyftProd: newLyftProdService(svc, mapper, cfg, notificationService),
|
||||
}
|
||||
})
|
||||
|
||||
return instance
|
||||
}
|
||||
Reference in New Issue
Block a user