update transitous connection
This commit is contained in:
parent
8680f56006
commit
63fc3e7c83
|
@ -0,0 +1,105 @@
|
||||||
|
package transitous
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client represents a Transitous API client
|
||||||
|
type Client struct {
|
||||||
|
baseURL string
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates a new Transitous client
|
||||||
|
func NewClient(baseURL string) *Client {
|
||||||
|
return &Client{
|
||||||
|
baseURL: baseURL,
|
||||||
|
httpClient: &http.Client{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanParams represents the parameters for route planning
|
||||||
|
type PlanParams struct {
|
||||||
|
FromPlace string
|
||||||
|
ToPlace string
|
||||||
|
Time *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanResponse represents the response from the Transitous API
|
||||||
|
type PlanResponse struct {
|
||||||
|
Itineraries []Itinerary `json:"itineraries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanWithResponse plans a route and returns the response
|
||||||
|
func (c *Client) PlanWithResponse(ctx context.Context, params *PlanParams) (*TransitousResponse, error) {
|
||||||
|
// Build URL with query parameters
|
||||||
|
u, err := url.Parse(fmt.Sprintf("%s/api/v4/plan", c.baseURL))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse base URL: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
query := u.Query()
|
||||||
|
query.Set("fromPlace", params.FromPlace)
|
||||||
|
query.Set("toPlace", params.ToPlace)
|
||||||
|
|
||||||
|
if params.Time != nil {
|
||||||
|
// Use ISO 8601 format with timezone like in the example
|
||||||
|
query.Set("time", params.Time.Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional parameters matching the example
|
||||||
|
query.Set("withFares", "true")
|
||||||
|
query.Set("fastestDirectFactor", "1.5")
|
||||||
|
query.Set("joinInterlinedLegs", "false")
|
||||||
|
query.Set("maxMatchingDistance", "250")
|
||||||
|
query.Set("arriveBy", "true")
|
||||||
|
|
||||||
|
u.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
// Create HTTP request
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
req.Header.Set("User-Agent", "COOPGO-Platform/1.0")
|
||||||
|
|
||||||
|
log.Debug().
|
||||||
|
Str("url", u.String()).
|
||||||
|
Msg("Making Transitous API request")
|
||||||
|
|
||||||
|
// Execute request
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("request failed: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("API request failed with status %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse response
|
||||||
|
var transitousResponse TransitousResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&transitousResponse); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().
|
||||||
|
Str("from", params.FromPlace).
|
||||||
|
Str("to", params.ToPlace).
|
||||||
|
Int("itineraries", len(transitousResponse.Itineraries)).
|
||||||
|
Msg("Transitous API response received")
|
||||||
|
|
||||||
|
return &transitousResponse, nil
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package transitous
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// TransitousResponse represents the top-level response from Transitous API
|
||||||
|
type TransitousResponse struct {
|
||||||
|
RequestParameters map[string]interface{} `json:"requestParameters"`
|
||||||
|
DebugOutput map[string]interface{} `json:"debugOutput"`
|
||||||
|
From Place `json:"from"`
|
||||||
|
To Place `json:"to"`
|
||||||
|
Direct []interface{} `json:"direct"`
|
||||||
|
Itineraries []Itinerary `json:"itineraries"`
|
||||||
|
PreviousPageCursor string `json:"previousPageCursor,omitempty"`
|
||||||
|
NextPageCursor string `json:"nextPageCursor,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Itinerary represents a complete journey from origin to destination
|
||||||
|
type Itinerary struct {
|
||||||
|
StartTime time.Time `json:"startTime"`
|
||||||
|
EndTime time.Time `json:"endTime"`
|
||||||
|
Duration int `json:"duration"` // Duration in seconds
|
||||||
|
Legs []Leg `json:"legs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leg represents a single segment of a journey
|
||||||
|
type Leg struct {
|
||||||
|
Mode string `json:"mode"` // WALK, BUS, TRAIN, etc.
|
||||||
|
StartTime time.Time `json:"startTime"`
|
||||||
|
EndTime time.Time `json:"endTime"`
|
||||||
|
Duration int `json:"duration"` // Duration in seconds
|
||||||
|
Distance float64 `json:"distance"` // Distance in meters
|
||||||
|
From Place `json:"from"`
|
||||||
|
To Place `json:"to"`
|
||||||
|
Route *Route `json:"route,omitempty"`
|
||||||
|
AgencyName string `json:"agencyName,omitempty"`
|
||||||
|
Headsign string `json:"headsign,omitempty"`
|
||||||
|
RouteShortName string `json:"routeShortName,omitempty"`
|
||||||
|
RouteColor string `json:"routeColor,omitempty"`
|
||||||
|
RouteTextColor string `json:"routeTextColor,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place represents a location (stop, station, or coordinate)
|
||||||
|
type Place struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Lat float64 `json:"lat"`
|
||||||
|
Lon float64 `json:"lon"`
|
||||||
|
StopId string `json:"stopId,omitempty"`
|
||||||
|
StopCode string `json:"stopCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route represents a transit route
|
||||||
|
type Route struct {
|
||||||
|
AgencyName string `json:"agencyName"`
|
||||||
|
ShortName string `json:"shortName"`
|
||||||
|
LongName string `json:"longName"`
|
||||||
|
Type int `json:"type"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
TextColor string `json:"textColor"`
|
||||||
|
Url string `json:"url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agency represents a transit agency
|
||||||
|
type Agency struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Timezone string `json:"timezone"`
|
||||||
|
Lang string `json:"lang,omitempty"`
|
||||||
|
Phone string `json:"phone,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop represents a transit stop or station
|
||||||
|
type Stop struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Code string `json:"code,omitempty"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Lat float64 `json:"lat"`
|
||||||
|
Lon float64 `json:"lon"`
|
||||||
|
ZoneId string `json:"zoneId,omitempty"`
|
||||||
|
Url string `json:"url,omitempty"`
|
||||||
|
LocationType int `json:"locationType,omitempty"`
|
||||||
|
ParentStation string `json:"parentStation,omitempty"`
|
||||||
|
Timezone string `json:"timezone,omitempty"`
|
||||||
|
WheelchairBoarding int `json:"wheelchairBoarding,omitempty"`
|
||||||
|
}
|
Loading…
Reference in New Issue