package carpool import ( "encoding/json" "errors" "fmt" "io" "net/http" "strconv" "time" "git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss" "github.com/google/uuid" "github.com/rs/zerolog/log" ) type BBCDailyCarpoolAPI struct { OperatorId string APIKey string BaseURL string } func NewBBCDailyCarpoolAPI(operatorId string, api_key string, baseURL string) (*BBCDailyCarpoolAPI, error) { return &BBCDailyCarpoolAPI{ OperatorId: operatorId, APIKey: api_key, BaseURL: baseURL, }, nil } type BBCDailyResult struct { ID *string `json:"id"` Duration *time.Duration `json:"duration"` Distance *int64 `json:"distance"` PickupLatitude *float64 `json:"pickup_latitude"` PickupLongitude *float64 `json:"pickup_longitude"` PickupDatetime *string `json:"pickup_datetime"` DropoffLatitude *float64 `json:"dropoff_latitude"` DropoffLongitude *float64 `json:"dropoff_longitude"` DropoffDatetime *string `json:"dropoff_datetime"` WebURL *string `json:"web_url"` DepartureToPickupWalkingTime *time.Duration `json:"departure_to_pickup_walking_time"` DropoffToArrivalWalkingTime *time.Duration `json:"dropoff_to_arrival_walking_time"` JourneyPolyline *string `json:"journey_polyline"` Price *struct { Currency string `json:"currency"` Amount float64 `json:"amount"` } `json:"price"` AvailableSeats *int64 `json:"available_seats"` } func (api *BBCDailyCarpoolAPI) GetOperatorId() string { return api.OperatorId } func (api *BBCDailyCarpoolAPI) GetDriverJourneys( departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius int64, arrivalRadius int64, count int64, ) ([]ocss.DriverJourney, error) { td := 1 * time.Hour if timeDelta != nil { td = *timeDelta } results, err := blablacarDailySearch( api.BaseURL+"/search", api.APIKey, departureLat, departureLng, arrivalLat, arrivalLng, departureDate, td, ) if err != nil { log.Error().Err(err).Msg("error in blablacarDailySearch") return nil, err } journeys := []ocss.DriverJourney{} for _, r := range results { var price *ocss.Price if r.Price != nil { paying := ocss.Paying price = &ocss.Price{ Type: &paying, Amount: &r.Price.Amount, Currency: &r.Price.Currency, } } i, err := strconv.ParseInt(*r.PickupDatetime, 10, 64) if err != nil { log.Error().Err(err).Msg("error in string ot int conversion") } pd := time.Unix(i, 0) pickupDatetime := ocss.OCSSTime(pd) driverJourney := ocss.DriverJourney{ DriverTrip: ocss.DriverTrip{ Driver: ocss.User{ ID: uuid.NewString(), Operator: api.OperatorId, Alias: "Utilisateur BlablacarDaily", }, DepartureToPickupWalkingDuration: r.DepartureToPickupWalkingTime, DropoffToArrivalWalkingDuration: r.DropoffToArrivalWalkingTime, Trip: ocss.Trip{ Operator: api.OperatorId, PassengerPickupLat: nilCheck(r.PickupLatitude), PassengerPickupLng: nilCheck(r.PickupLongitude), PassengerDropLat: nilCheck(r.DropoffLatitude), PassengerDropLng: nilCheck(r.DropoffLongitude), Duration: nilCheck(r.Duration), Distance: r.Distance, JourneyPolyline: r.JourneyPolyline, }, }, JourneySchedule: ocss.JourneySchedule{ ID: r.ID, PassengerPickupDate: pickupDatetime, WebUrl: r.WebURL, }, AvailableSteats: r.AvailableSeats, Price: price, } journeys = append(journeys, driverJourney) } return journeys, nil } func (api *BBCDailyCarpoolAPI) GetPassengerJourneys( departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius int64, arrivalRadius int64, count int64, ) ([]ocss.PassengerJourney, error) { return nil, errors.New("not implemented") } func blablacarDailySearch(url string, access_token string, departure_latitude float64, departure_longitude float64, arrival_latitude float64, arrival_longitude float64, departure_time time.Time, departure_timedelta time.Duration) ([]BBCDailyResult, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { log.Error().Err(err).Msg("new request issue") return nil, err } req.Header.Set("Content-Type", "application/json") q := req.URL.Query() q.Add("access_token", access_token) q.Add("departure_latitude", fmt.Sprintf("%f", departure_latitude)) q.Add("departure_longitude", fmt.Sprintf("%f", departure_longitude)) q.Add("arrival_latitude", fmt.Sprintf("%f", arrival_latitude)) q.Add("arrival_longitude", fmt.Sprintf("%f", arrival_longitude)) q.Add("departure_epoch", strconv.FormatInt(departure_time.Unix(), 10)) q.Add("departure_timedelta", fmt.Sprintf("%v", departure_timedelta.Abs().Seconds())) req.URL.RawQuery = q.Encode() resp, err := http.DefaultClient.Do(req) if err != nil { log.Error().Err(err).Msg("error in BBCDaily request") return nil, err } response := []BBCDailyResult{} err = json.NewDecoder(resp.Body).Decode(&response) if err != nil { body, err2 := io.ReadAll(resp.Body) if err2 != nil { log.Error().Err(err2).Msg("error reading json string") } log.Error().Err(err).Bytes("resp body", body).Any("status", resp.Status).Msg("cannot read json response to blablacardaily API") return nil, err } return response, nil } func nilCheck[T any](a *T) T { var t T if a == nil { return t } return *a }