def _do_request(self): logger = logging.getLogger(__name__) logger.debug( "requesting %s direct path from %s to %s by %s", self._path_type, self._orig_obj.uri, self._dest_obj.uri, self._mode, ) dp = self._direct_path_with_fp(self._instance) if getattr(dp, "journeys", None): if self._mode == "ridesharing": switch_back_to_ridesharing(dp, True) dp.journeys[0].internal_id = str(utils.generate_id()) logger.debug( "finish %s direct path from %s to %s by %s", self._path_type, self._orig_obj.uri, self._dest_obj.uri, self._mode, ) return dp
def _create_crowfly(pt_journey, crowfly_origin, crowfly_destination, begin, end, mode): section = response_pb2.Section() section.type = response_pb2.CROW_FLY section.origin.CopyFrom(crowfly_origin) section.destination.CopyFrom(crowfly_destination) section.duration = end - begin pt_journey.durations.total += section.duration pt_journey.duration += section.duration section.begin_date_time = begin section.end_date_time = end if section.duration > 0: section.street_network.mode = MODE_TO_PB_MODE.get(mode) # mode is always walking for a teleportation crow_fly else: section.street_network.mode = response_pb2.Walking # Calculate section length from_coord = get_pt_object_coord(section.origin) to_coord = get_pt_object_coord(section.destination) section.length = int(crowfly_distance_between(from_coord, to_coord)) # The section "distances" and "durations" in the response needs to be updated according to the mode. # only if it isn't a 'free' crow_fly if section.duration > 0: setattr(pt_journey.distances, mode, (getattr(pt_journey.distances, mode) + section.length)) setattr(pt_journey.durations, mode, (getattr(pt_journey.durations, mode) + section.duration)) section.id = six.text_type(generate_id()) return section
def _do_isochrone_common_request(self): logger = logging.getLogger(__name__) fallback_durations_pool = (self._orig_fallback_durtaions_pool if self._orig_fallback_durtaions_pool is not None else self._dest_fallback_durations_pool) mode = self._dep_mode if self._orig_fallback_durtaions_pool is not None else self._arr_mode self._logger.debug("waiting for fallback durations with %s", mode) fallback_duration_status = fallback_durations_pool.wait_and_get(mode) self._logger.debug( "requesting public transport journey with dep_mode: %s", mode) fallback_durations = { k: v.duration for k, v in fallback_duration_status.items() } if not fallback_durations or not self._request.get('max_duration', 0): return None if self._orig_fallback_durtaions_pool is not None: orig_and_dest_fallback_durations = { "orig_fallback_durations": fallback_durations, "dest_fallback_durations": {}, } else: orig_and_dest_fallback_durations = { "orig_fallback_durations": {}, "dest_fallback_durations": fallback_durations, } if self._request_type == type_pb2.ISOCHRONE: resp = self._journeys(self._instance.planner, **orig_and_dest_fallback_durations) else: resp = self._graphical_isochrone( self._instance.planner, **orig_and_dest_fallback_durations) for j in resp.journeys: j.internal_id = str(utils.generate_id()) if resp.HasField(six.text_type("error")): logger.debug("pt journey has error mode: %s", mode) # Here needs to modify error message of no_solution if not fallback_durations: if self._orig_fallback_durtaions_pool is not None: resp.error.id = response_pb2.Error.no_origin resp.error.message = "no origin point" else: resp.error.id = response_pb2.Error.no_destination resp.error.message = "no destination point" logger.debug("finish public transport journey with mode: %s", mode) return resp
def _do_request(self): logger = logging.getLogger(__name__) logger.debug("waiting for orig fallback durations with %s", self._dep_mode) orig_fallback_duration_status = self._orig_fallback_durtaions_pool.wait_and_get( self._dep_mode) logger.debug("waiting for dest fallback durations with %s", self._arr_mode) dest_fallback_duration_status = self._dest_fallback_durations_pool.wait_and_get( self._arr_mode) logger.debug( "requesting public transport journey with dep_mode: %s and arr_mode: %s", self._dep_mode, self._arr_mode, ) orig_fallback_durations = { k: v.duration for k, v in orig_fallback_duration_status.items() } dest_fallback_durations = { k: v.duration for k, v in dest_fallback_duration_status.items() } if (not orig_fallback_durations or not dest_fallback_durations or not self._request.get('max_duration', 0)): return None resp = self._journeys(self._instance.planner, orig_fallback_durations, dest_fallback_durations) for j in resp.journeys: j.internal_id = str(utils.generate_id()) if resp.HasField(b"error"): logger.debug("pt journey has error dep_mode: %s and arr_mode: %s", self._dep_mode, self._arr_mode) # Here needs to modify error message of no_solution if not orig_fallback_durations: resp.error.id = response_pb2.Error.no_origin resp.error.message = "no origin point" elif not dest_fallback_durations: resp.error.id = response_pb2.Error.no_destination resp.error.message = "no destination point" logger.debug( "finish public transport journey with dep_mode: %s and arr_mode: %s", self._dep_mode, self._arr_mode) return resp
def _do_request(self): logger = logging.getLogger(__name__) logger.debug("requesting %s direct path from %s to %s by %s", self._path_type, self._orig_obj.uri, self._dest_obj.uri, self._mode) dp = self._instance.direct_path(self._mode, self._orig_obj, self._dest_obj, self._fallback_extremity, self._request, self._path_type) if getattr(dp, "journeys", None): dp.journeys[0].internal_id = str(utils.generate_id()) logger.debug("finish %s direct path from %s to %s by %s", self._path_type, self._orig_obj.uri, self._dest_obj.uri, self._mode) return dp
def _do_journeys_request(self): self._logger.debug( "requesting public transport journey with dep_mode: %s and arr_mode: %s", self._dep_mode, self._arr_mode, ) orig_fallback_durations = self._orig_fallback_durtaions_pool.get_best_fallback_durations( self._dep_mode) dest_fallback_durations = self._dest_fallback_durations_pool.get_best_fallback_durations( self._arr_mode) if (not orig_fallback_durations or not dest_fallback_durations or not self._request.get('max_duration', 0)): return None resp = self._journeys(self._instance.planner, orig_fallback_durations, dest_fallback_durations) for j in resp.journeys: j.internal_id = str(utils.generate_id()) if resp.HasField(str("error")): self._logger.debug( "pt journey has error dep_mode: %s and arr_mode: %s", self._dep_mode, self._arr_mode) # Here needs to modify error message of no_solution if not orig_fallback_durations: resp.error.id = response_pb2.Error.no_origin resp.error.message = "no origin point" elif not dest_fallback_durations: resp.error.id = response_pb2.Error.no_destination resp.error.message = "no destination point" self._logger.debug( "finish public transport journey with dep_mode: %s and arr_mode: %s", self._dep_mode, self._arr_mode) return resp
def _do_request(self): self._logger.debug( "requesting %s direct path from %s to %s by %s", self._path_type, self._orig_obj.uri, self._dest_obj.uri, self._mode, ) dp = self._direct_path_with_fp(self._streetnetwork_service) if getattr(dp, "journeys", None): dp.journeys[0].internal_id = str(utils.generate_id()) self._logger.debug( "finish %s direct path from %s to %s by %s", self._path_type, self._orig_obj.uri, self._dest_obj.uri, self._mode, ) return dp
def _create_crowfly(pt_journey, crowfly_origin, crowfly_destination, begin, end, mode): section = response_pb2.Section() section.type = response_pb2.CROW_FLY section.origin.CopyFrom(crowfly_origin) section.destination.CopyFrom(crowfly_destination) section.duration = end - begin pt_journey.durations.total += section.duration pt_journey.duration += section.duration section.begin_date_time = begin section.end_date_time = end if section.duration > 0: section.street_network.mode = FallbackModes[mode].value # mode is always walking for a teleportation crow_fly else: section.street_network.mode = response_pb2.Walking # Calculate section length from_coord = get_pt_object_coord(section.origin) to_coord = get_pt_object_coord(section.destination) section.length = int(crowfly_distance_between(from_coord, to_coord)) section.id = six.text_type(generate_id()) return section
def _rename_fallback_sections_ids(sections): for s in sections: s.id = six.text_type(generate_id())
def build_ridesharing_journeys(from_pt_obj, to_pt_obj, period_extremity, instance): from_coord = get_pt_object_coord(from_pt_obj) to_coord = get_pt_object_coord(to_pt_obj) from_str = "{},{}".format(from_coord.lat, from_coord.lon) to_str = "{},{}".format(to_coord.lat, to_coord.lon) try: rsjs, fps = instance.get_ridesharing_journeys_with_feed_publishers( from_str, to_str, period_extremity) except Exception as e: logging.exception( 'Error while retrieving ridesharing ads and feed_publishers from %s to %s: {}', from_str, to_str) new_relic.record_custom_event('ridesharing_internal_failure', {'message': str(e)}) rsjs = [] fps = [] pb_rsjs = [] pb_tickets = [] pb_feed_publishers = [_make_pb_fp(fp) for fp in fps if fp is not None] for rsj in rsjs: pb_rsj = response_pb2.Journey() pb_rsj_pickup = instance.georef.place("{};{}".format( rsj.pickup_place.lon, rsj.pickup_place.lat)) pb_rsj_dropoff = instance.georef.place("{};{}".format( rsj.dropoff_place.lon, rsj.dropoff_place.lat)) pickup_coord = get_pt_object_coord(pb_rsj_pickup) dropoff_coord = get_pt_object_coord(pb_rsj_dropoff) pb_rsj.requested_date_time = period_extremity.datetime pb_rsj.departure_date_time = rsj.pickup_date_time pb_rsj.arrival_date_time = rsj.dropoff_date_time pb_rsj.tags.append('ridesharing') # start teleport section start_teleport_section = pb_rsj.sections.add() start_teleport_section.id = "section_{}".format( six.text_type(generate_id())) start_teleport_section.type = response_pb2.CROW_FLY start_teleport_section.street_network.mode = response_pb2.Walking start_teleport_section.origin.CopyFrom(from_pt_obj) start_teleport_section.destination.CopyFrom(pb_rsj_pickup) start_teleport_section.length = int( crowfly_distance_between(from_coord, pickup_coord)) start_teleport_section.duration = 0 start_teleport_section.shape.extend([from_coord, pickup_coord]) start_teleport_section.begin_date_time = rsj.pickup_date_time start_teleport_section.end_date_time = rsj.pickup_date_time # report value to journey pb_rsj.distances.walking += start_teleport_section.length # real ridesharing section rs_section = pb_rsj.sections.add() rs_section.id = "section_{}".format(six.text_type(generate_id())) rs_section.type = response_pb2.RIDESHARING rs_section.origin.CopyFrom(pb_rsj_pickup) rs_section.destination.CopyFrom(pb_rsj_dropoff) rs_section.additional_informations.append( response_pb2.HAS_DATETIME_ESTIMATED) rs_section.ridesharing_information.operator = rsj.metadata.system_id rs_section.ridesharing_information.network = rsj.metadata.network if rsj.available_seats is not None: rs_section.ridesharing_information.seats.available = rsj.available_seats if rsj.total_seats is not None: rs_section.ridesharing_information.seats.total = rsj.total_seats if rsj.driver.alias: rs_section.ridesharing_information.driver.alias = rsj.driver.alias if rsj.driver.image: rs_section.ridesharing_information.driver.image = rsj.driver.image if rsj.driver.gender is not None: if rsj.driver.gender == Gender.MALE: rs_section.ridesharing_information.driver.gender = response_pb2.MALE elif rsj.driver.gender == Gender.FEMALE: rs_section.ridesharing_information.driver.gender = response_pb2.FEMALE if rsj.driver.rate is not None and rsj.driver.rate_count: rs_section.ridesharing_information.driver.rating.value = rsj.driver.rate if rsj.driver.rate_count: rs_section.ridesharing_information.driver.rating.count = rsj.driver.rate_count if rsj.metadata.rating_scale_min is not None and rsj.metadata.rating_scale_max is not None: rs_section.ridesharing_information.driver.rating.scale_min = rsj.metadata.rating_scale_min rs_section.ridesharing_information.driver.rating.scale_max = rsj.metadata.rating_scale_max if rsj.ridesharing_ad: l = rs_section.ridesharing_information.links.add() l.key = "ridesharing_ad" l.href = rsj.ridesharing_ad # TODO CO2 = length * coeffCar / (totalSeats + 1) rs_section.length = rsj.distance rs_section.shape.extend(rsj.shape) rs_section.duration = rsj.dropoff_date_time - rsj.pickup_date_time rs_section.begin_date_time = rsj.pickup_date_time rs_section.end_date_time = rsj.dropoff_date_time # report values to journey pb_rsj.distances.ridesharing += rs_section.length pb_rsj.duration += rs_section.duration pb_rsj.durations.total += rs_section.duration pb_rsj.durations.ridesharing += rs_section.duration # end teleport section end_teleport_section = pb_rsj.sections.add() end_teleport_section.id = "section_{}".format( six.text_type(generate_id())) end_teleport_section.type = response_pb2.CROW_FLY end_teleport_section.street_network.mode = response_pb2.Walking end_teleport_section.origin.CopyFrom(pb_rsj_dropoff) end_teleport_section.destination.CopyFrom(to_pt_obj) end_teleport_section.length = int( crowfly_distance_between(dropoff_coord, to_coord)) end_teleport_section.duration = 0 end_teleport_section.shape.extend([dropoff_coord, to_coord]) end_teleport_section.begin_date_time = rsj.dropoff_date_time end_teleport_section.end_date_time = rsj.dropoff_date_time # report value to journey pb_rsj.distances.walking += end_teleport_section.length # create ticket associated ticket = response_pb2.Ticket() ticket.id = "ticket_{}".format(six.text_type(generate_id())) ticket.name = "ridesharing_price_{}".format(ticket.id) ticket.found = True ticket.comment = "Ridesharing price for section {}".format( rs_section.id) ticket.section_id.extend([rs_section.id]) # also add fare to journey ticket.cost.value = rsj.price pb_rsj.fare.total.value = ticket.cost.value ticket.cost.currency = rsj.currency pb_rsj.fare.total.currency = rsj.currency pb_rsj.fare.found = True pb_rsj.fare.ticket_id.extend([ticket.id]) pb_tickets.append(ticket) pb_rsjs.append(pb_rsj) return pb_rsjs, pb_tickets, pb_feed_publishers
def call_kraken(self, request_type, request, instance, krakens_call): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ logger = logging.getLogger(__name__) logger.debug('datetime: %s', request['datetime']) # odt_stop_points is a set of stop_point.uri with is_zonal = true used to manage tad_zonal odt_stop_points = set() # crowfly_stop_points is a set of stop_point.uri used to create a crowfly section. crowfly_stop_points = set() if not g.requested_origin: g.requested_origin = instance.georef.place(request['origin']) if not g.requested_origin: r = self._make_error_response( "The entry point: {} is not valid".format( request['origin']), response_pb2.Error.unknown_object) return [r] if not g.requested_destination: g.requested_destination = instance.georef.place( request['destination']) if not g.requested_destination: r = self._make_error_response( "The entry point: {} is not valid".format( request['destination']), response_pb2.Error.unknown_object) return [r] worker = AsyncWorker(instance, krakens_call, request) resp = [] # Now we compute the direct path with all requested departure # mode their time will be used to initialized our PT calls and # to bound the fallback duration of the first section. futures = worker.get_direct_path_futures( g.fallback_direct_path, g.requested_origin, g.requested_destination, request['datetime'], request['clockwise'], False, {mode for mode, _ in krakens_call}) for future in gevent.iwait(futures): resp_key, resp_direct_path = future.get() g.fallback_direct_path[resp_key] = resp_direct_path if resp_direct_path.journeys: resp_direct_path.journeys[0].internal_id = str(generate_id()) resp.append(resp_direct_path) if request.get('max_duration', 0): direct_path_duration_by_mode = make_direct_path_duration_by_mode( g.fallback_direct_path) # Get all stop_points around the requested origin within a crowfly range # Calls on origins and destinations are asynchronous orig_futures, dest_futures = worker.get_crowfly_futures( g.requested_origin, g.requested_destination, direct_path_duration_by_mode) gevent.joinall(orig_futures + dest_futures) for future in orig_futures: g.origins_places_crowfly.update(future.get()) for future in dest_futures: g.destinations_places_crowfly.update(future.get()) # Once we get crow fly stop points with origins and destinations, we start # the computation NM: the fallback matrix which contains the arrival duration for crowfly stop_points # from origin/destination # Ex: # stop_point1 stop_point2 stop_point3 # request_origin_1 86400(s) 43200(s) 21600(s) # As a side note this won't work the day when our ETA will be impacted by the datetime of the journey, # at least for the arrival when doing a "departure after" request. orig_futures, dest_futures = worker.get_routing_matrix_futures( g.requested_origin, g.requested_destination, g.origins_places_crowfly, g.destinations_places_crowfly, direct_path_duration_by_mode) gevent.joinall(orig_futures + dest_futures) for future in orig_futures: g.origins_fallback.update(future.get()) for future in dest_futures: g.destinations_fallback.update(future.get()) # In Some special cases, like "odt" or "departure(arrive) from(to) a stop_area", # the first(last) section should be treated differently orig_futures, dest_futures = worker.get_update_crowfly_duration_futures( ) gevent.joinall(orig_futures + dest_futures) def _updater(_futures, fb, crowfly_stop_points, odt_stop_points): for f in _futures: crowfly_res, odt_res, fb_res = f.get() crowfly_stop_points |= crowfly_res odt_stop_points |= odt_res for mode in (mode for mode in fb_res if mode in fb): fb.merge_reached_values(mode, fb_res[mode]) _updater(orig_futures, g.origins_fallback, crowfly_stop_points, odt_stop_points) _updater(dest_futures, g.destinations_fallback, crowfly_stop_points, odt_stop_points) # We update the fallback duration matrix if the requested origin/destination is also # present in the fallback duration matrix, which means from stop_point_1 to itself, it takes 0 second # Ex: # stop_point1 stop_point2 stop_point3 # stop_point_1 0(s) ... ... for dep_mode, arr_mode in krakens_call: g.origins_fallback.reset_if_exist(dep_mode, g.requested_origin.uri) g.destinations_fallback.reset_if_exist( arr_mode, g.requested_destination.uri) # Here starts the computation for pt journey journey_parameters = create_parameters(request) futures = worker.get_pt_journey_futures(g.requested_origin, g.requested_destination, g.fallback_direct_path, g.origins_fallback, g.destinations_fallback, journey_parameters) response_tuples = [] for future in gevent.iwait(futures): dep_mode, arr_mode, local_resp = future.get() if local_resp is None: continue dp_key = make_direct_path_key(dep_mode, g.requested_origin.uri, g.requested_destination.uri, request['datetime'], request['clockwise'], False) direct_path = g.fallback_direct_path.get(dp_key) if local_resp.HasField(b"error") and local_resp.error.id == response_pb2.Error.error_id.Value('no_solution') \ and direct_path.journeys: local_resp.ClearField(b"error") if local_resp.HasField(b"error"): #Here needs to modify error message of no_solution if len(g.origins_fallback[dep_mode]) == 0: self.update_error_message(local_resp, response_pb2.Error.no_origin, "no origin point") elif len(g.destinations_fallback[arr_mode]) == 0: self.update_error_message( local_resp, response_pb2.Error.no_destination, "no destination point") return [local_resp] # for log purpose we put and id in each journeys for j in local_resp.journeys: j.internal_id = str(generate_id()) response_tuples.append((dep_mode, arr_mode, j)) resp.append(local_resp) # Once the pt journey is found, we need to reconstruct the whole journey with fallback regarding the mode # For the sake of performance, we compute at first all fallback direct path asynchronously # then we update the pool of direct paths futures = worker.get_fallback_direct_path_futures( response_tuples, crowfly_stop_points, odt_stop_points) for future in gevent.iwait(futures): resp_key, resp_direct_path = future.get() g.fallback_direct_path[resp_key] = resp_direct_path # Now we construct the whole journey by concatenating the fallback direct path with the pt journey worker.build_journeys(response_tuples, crowfly_stop_points, odt_stop_points) #If resp doesn't contain any response we have to add an error message if len(resp) == 0: if len(g.origins_fallback[dep_mode]) == 0 and len( g.destinations_fallback[arr_mode]) == 0: resp.append( self._make_error_response( "no origin point nor destination point", response_pb2.Error.no_origin_nor_destination)) elif len(g.origins_fallback[dep_mode]) == 0: resp.append( self._make_error_response("no origin point", response_pb2.Error.no_origin)) elif len(g.destinations_fallback[arr_mode]) == 0: resp.append( self._make_error_response( "no destination point", response_pb2.Error.no_destination)) return resp for r in resp: fill_uris(r) return resp