Files
old-svijetlastrana/application/tncservice/lyft.go
2018-04-25 13:16:36 +02:00

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
}