110 lines
2.7 KiB
Go
110 lines
2.7 KiB
Go
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.Add(-2*time.Hour).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("searchWindow", "14400")
|
|
// query.Set("timetableView", "false")
|
|
// 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()).
|
|
Time("time", *params.Time).
|
|
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
|
|
}
|
|
|