Skip to content

Commit

Permalink
Merge pull request #12 from traveltime-dev/feature/proto
Browse files Browse the repository at this point in the history
Feature/proto
  • Loading branch information
EivydasKoc authored Nov 7, 2022
2 parents 1968ec8 + 402039e commit 924ab74
Show file tree
Hide file tree
Showing 19 changed files with 603 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .gemfiles/google-protobuf.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
eval_gemfile '../Gemfile'

gem 'google-protobuf', '~> 3.21', '>= 3.21.9'
10 changes: 7 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ AllCops:
DisplayStyleGuide: true
TargetRubyVersion: 2.7
NewCops: enable
Exclude:
- spec/*.rb
- lib/travel_time/proto/v2/*.rb
- vendor/**/*
- gemfiles/vendor/bundle/**/*

# Disabling until TravelTime Rubygems account is MFA-protected.
Gemspec/RequireMFA:
Expand All @@ -24,8 +29,7 @@ RSpec/NestedGroups:
RSpec/MultipleMemoizedHelpers:
Max: 10

RSpec/Rails/HaveHttpStatus:
Enabled: false

Metrics/ParameterLists:
Enabled: false
RSpec/Rails/HaveHttpStatus:
Enabled: false
69 changes: 69 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,75 @@ response = client.time_filter_fast(
puts response.body
```

### [Time Filter (Fast) Proto](https://docs.traveltime.com/api/reference/travel-time-distance-matrix-proto)
A fast version of time filter communicating using [protocol buffers](https://github.com/protocolbuffers/protobuf).

The request parameters are much more limited and only travel time is returned. In addition, the results are only approximately correct (95% of the results are guaranteed to be within 5% of the routes returned by regular time filter).

This inflexibility comes with a benefit of faster response times (Over 5x faster compared to regular time filter) and larger limits on the amount of destination points.

Body attributes:
* origin: Origin point.
* destinations: Destination points. Cannot be more than 200,000.
* transport: Transportation type.
* travelTime: Time limit;
* country: Return the results that are within the specified country

```ruby
origin = {
lat: 51.508930,
lng: -0.131387,
}

destinations = [{
lat: 51.508824,
lng: -0.167093,
}]

response = client.time_filter_fast_proto(
country: 'UK',
origin: origin,
destinations: destinations,
transport: 'driving+ferry',
traveltime: 7200
)
puts(response.body)
```

### Time Filter (Fast) Proto Distance
A version of `Time Filter (Fast) Proto` endpoint that also returns distance information. Request parameters are even more limited than `Time Filter (Fast) Proto`.

This endpoint is not enabled by default, please [contact us](https://traveltime.com/contact-us) if you wish to obtain access.

Body attributes:
* origin: Origin point.
* destinations: Destination points. Cannot be more than 200,000.
* transport: Transportation type.
* travelTime: Time limit;
* country: Return the results that are within the specified country

```ruby
origin = {
lat: 51.508930,
lng: -0.131387,
}

destinations = [{
lat: 51.508824,
lng: -0.167093,
}]

response = client.time_filter_fast_proto_distance(
country: 'UK',
origin: origin,
destinations: destinations,
transport: 'driving+ferry',
traveltime: 7200
)
puts(response.body)
```


### [Time Filter (Postcode Districts)](https://traveltime.com/docs/api/reference/postcode-district-filter)
Find districts that have a certain coverage from origin (or to destination) and get statistics about postcodes within such districts.
Currently only supports United Kingdom.
Expand Down
1 change: 1 addition & 0 deletions lib/travel_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require 'travel_time/error'
require 'travel_time/response'
require 'travel_time/version'
require 'travel_time/proto/utils'

# Main TravelTime module
module TravelTime
Expand Down
42 changes: 41 additions & 1 deletion lib/travel_time/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

require 'faraday'
require 'travel_time/middleware/authentication'
require 'travel_time/middleware/proto'

module TravelTime
# The Client class provides the main interface to interact with the TravelTime API
class Client # rubocop:disable Metrics/ClassLength
API_BASE_URL = 'https://api.traveltimeapp.com/v4/'

attr_reader :connection
attr_reader :connection, :proto_connection

def initialize
@connection = Faraday.new(API_BASE_URL) do |f|
Expand All @@ -19,12 +20,27 @@ def initialize
f.use TravelTime::Middleware::Authentication
f.adapter TravelTime.config.http_adapter || Faraday.default_adapter
end

init_proto_connection
end

def init_proto_connection
@proto_connection = Faraday.new do |f|
f.use TravelTime::Middleware::ProtoMiddleware
f.response :raise_error if TravelTime.config.raise_on_failure
f.response :logger if TravelTime.config.enable_logging
f.adapter TravelTime.config.http_adapter || Faraday.default_adapter
end
end

def unwrap(response)
Response.from_object(response)
end

def unwrap_proto(response)
Response.from_object_proto(response)
end

def perform_request
unwrap(yield)
rescue Faraday::Error => e
Expand All @@ -35,6 +51,12 @@ def perform_request
raise TravelTime::Error.new(exception: e)
end

def perform_request_proto
unwrap_proto(yield)
rescue StandardError => e
raise TravelTime::Error.new(exception: e)
end

def map_info
perform_request { connection.get('map-info') }
end
Expand Down Expand Up @@ -94,6 +116,24 @@ def time_filter_fast(locations:, arrival_searches:)
perform_request { connection.post('time-filter/fast', payload) }
end

def time_filter_fast_proto(country:, origin:, destinations:, transport:, traveltime:)
message = ProtoUtils.make_proto_message(origin, destinations, transport, traveltime)
payload = ProtoUtils.encode_proto_message(message)
perform_request_proto do
proto_connection.post("http://proto.api.traveltimeapp.com/api/v2/#{country}/time-filter/fast/#{transport}",
payload)
end
end

def time_filter_fast_proto_distance(country:, origin:, destinations:, transport:, traveltime:)
message = ProtoUtils.make_proto_message(origin, destinations, transport, traveltime, properties: [1])
payload = ProtoUtils.encode_proto_message(message)
perform_request_proto do
proto_connection.post("https://proto-with-distance.api.traveltimeapp.com/api/v2/#{country}/time-filter/fast/#{transport}",
payload)
end
end

def time_filter_postcodes(departure_searches: nil, arrival_searches: nil)
payload = {
departure_searches: departure_searches,
Expand Down
19 changes: 19 additions & 0 deletions lib/travel_time/middleware/proto.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

require 'faraday'
require 'base64'

module TravelTime
module Middleware
# The Proto middleware is responsible for setting the basic auth headers for proto requests
# on each request. These are automatically taken from the `TravelTime.config`.
class ProtoMiddleware < Faraday::Middleware
def on_request(env)
env.request_headers['Authorization'] =
"Basic #{Base64.encode64("#{TravelTime.config.application_id}:#{TravelTime.config.api_key}")}"
env.request_headers['Content-Type'] = 'application/octet-stream'
env.request_headers['Accept'] = 'application/octet-stream'
end
end
end
end
61 changes: 61 additions & 0 deletions lib/travel_time/proto/source/RequestsCommon.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
syntax = "proto3";

package com.igeolise.traveltime.rabbitmq.requests;

message Coords {
float lat = 1;
float lng = 2;
}

message Transportation {
TransportationType type = 1;
}

enum TransportationType {
// Considers all paths found by the following steps:
// * up to 30 minutes of walking (always included even if no stops found)
// * all connections in the 30 minute walking range from public transport
// stops to other public transport stops in travel_time_limit, AND
// * up to 30 minutes of walking from public transport stops that were visited
// by public transport (IOW a path
// [origin]--walking->[stop]--walking-->[destination] is not possible but
// [origin]--walking->[stop]--public_transport-->[stop]--walking--> is.
PUBLIC_TRANSPORT = 0;
// Considers all paths found traveling by car from origin(s) to
// destination(s) within the travel_time_limit
DRIVING = 1;
// Considers all paths found by the following steps:
// * up to 30 minutes of driving (always included even no stops found)
// * all connections in the 30 minute driving range from public transport stops
// to other public transport stops in travel_time_limit, AND
// * up to 30 minutes of walking from public transport stops that were visited
// by public transport (IOW a path
// [origin]--driving->[stop]--walking-->[destination] is not possible but
// [origin]--driving->[stop]--public_transport-->[stop]--walking--> is.
// AND/OR
// * up to 30 minutes of walking
//
DRIVING_AND_PUBLIC_TRANSPORT = 2;
// Considers all paths found travelling by car from origin(s) to
// destination(s) including all paths that are traversable by ferries that
// take cars within the travel_time_limit.
DRIVING_AND_FERRY = 3;
// Considers all paths found travelling by foot from origin(s) to
// destination(s) within the travel_time_limit
WALKING = 4;
// Considers all paths found travelling by foot from origin(s) to
// destination(s) including all paths that are traversable by ferries that
// take passengers within the travel_time_limit
WALKING_AND_FERRY = 7;
// Considers all paths found travelling by bike from origin(s) to
// destination(s) within the travel_time_limit
CYCLING = 5;
// Considers all paths found travelling by bike from origin(s) to
// destination(s) including all paths that are traversable by ferries that
// take bikes within the travel_time_limit
CYCLING_AND_FERRY = 6;
}

enum TimePeriod {
WEEKDAY_MORNING = 0;
}
35 changes: 35 additions & 0 deletions lib/travel_time/proto/source/TimeFilterFastRequest.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
syntax = "proto3";

package com.igeolise.traveltime.rabbitmq.requests;

import "RequestsCommon.proto";

message TimeFilterFastRequest {
enum Property {
FARES = 0;
DISTANCES = 1;
}
message OneToMany {
Coords departureLocation = 1;
/*
* We encode arrival locations as deltas (relative to the source) using a fixedpoint encoding i.e
* deltaLat = round((lat - sourceLat) * 10^5).toInt
* deltaLon = round((lon - sourceLon) * 10^5).toInt
*
* The deltas should be interleaved in the `locationDeltas` field i.e
*
* locationDeltas[0] should be the first lat
* locationDeltas[1] should be the first lon
* locationDeltas[2] should be the second lat
* ...
* etc
*/
repeated sint32 locationDeltas = 2;
Transportation transportation = 3;
TimePeriod arrivalTimePeriod = 4;
sint32 travelTime = 5;
repeated Property properties = 6;
}

OneToMany oneToManyRequest = 1;
}
84 changes: 84 additions & 0 deletions lib/travel_time/proto/source/TimeFilterFastResponse.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
syntax = "proto3";

package com.igeolise.traveltime.rabbitmq.responses;

message TimeFilterFastResponse {
message Properties {
repeated sint32 travelTimes = 1;
repeated int32 monthlyFares = 2;
repeated int32 distances = 3;
}

message Error {
ErrorType type = 1;
}

enum ErrorType {
/*
* Catch all unknown error type
*/
UNKNOWN = 0;
/*
* oneToManyRequest to many field must not be null
*/
ONE_TO_MANY_MUST_NOT_BE_NULL = 1;
/*
* Source (either departure or arrival location) must not be null
*/
SOURCE_MUST_NOT_BE_NULL = 2;
/*
* Transportation mode must not be null.
*/
TRANSPORTATION_MUST_NOT_BE_NULL = 3;
/*
* Source (either departure or arrival location) must not be null
*/
SOURCE_NOT_IN_GEOMETRY = 4;

/*
* Transportation mode unrecognized.
*/
UNRECOGNIZED_TRANSPORTATION_MODE = 5;

/*
* The travel time limit is too low to process this request.
*/
TRAVEL_TIME_LIMIT_TOO_LOW = 6;

/*
* The travel time limit is too high to process this request.
*/
TRAVEL_TIME_LIMIT_TOO_HIGH = 7;

/*
* User id not set.
*/
AUTH_ERROR_NO_USER_ID = 8;

/*
* Message sent to wrong queue - transportation mode cannot be handled.
*/
SERVICE_MISMATCH_WRONG_TRANSPORTATION_MODE = 9;

/*
* Source is in a area that doesn't have any points that can be out of
* search e.g a lake, mountains or other desolate areas.
*/
SOURCE_OUT_OF_REACH = 10;

/*
* The interleaved deltas array should have (lat/lon) deltas and have an
* even number of elements
*/
INTERLEAVED_DELTAS_INVALID_COORDINATE_PAIRS = 11;

/*
* Public transport requests do not support returning distances for
* returned points.
*/
DISTANCE_PROPERTY_NOT_SUPPORTED = 12;
}

Error error = 1;
Properties properties = 2;
}
Loading

0 comments on commit 924ab74

Please sign in to comment.