def blablalines_init_class_test(): instance = MockInstance() ridesharing_manager = RidesharingServiceManager(instance, []) service = ridesharing_manager._init_class(config_blablalines["class"], config_blablalines["args"]) assert isinstance(service, Blablalines) assert service.system_id == "blablalines"
def instant_system_init_class_test(): instance = MockInstance() ridesharing_manager = RidesharingServiceManager(instance, []) service = ridesharing_manager._init_class(config_instant_system["class"], config_instant_system["args"]) assert isinstance(service, InstantSystem) assert service.system_id == 'instant_system'
def get_ridesharing_service_test(): configs = [ { "class": "jormungandr.scenarios.ridesharing.instant_system.InstantSystem", "args": { "service_url": "toto", "api_key": "toto key", "network": "N", "rating_scale_min": 0, "rating_scale_max": 10, "crowfly_radius": 200, "timeframe_duration": 1800, "feed_publisher": DUMMY_INSTANT_SYSTEM_FEED_PUBLISHER, }, }, { "class": "jormungandr.scenarios.ridesharing.instant_system.InstantSystem", "args": { "service_url": "tata", "api_key": "tata key", "network": "M", "rating_scale_min": 1, "rating_scale_max": 5, "crowfly_radius": 200, "timeframe_duration": 1800, }, }, ] instance = DummyInstance() ridesharing_service_manager = RidesharingServiceManager(instance, configs) ridesharing_service_manager.init_ridesharing_services() services = ridesharing_service_manager.get_all_ridesharing_services() assert len(services) == 2 assert services[0].service_url == 'toto' assert services[0].api_key == 'toto key' assert services[0].network == 'N' assert services[0].system_id == 'instant_system' assert services[0].rating_scale_min == 0 assert services[0].rating_scale_max == 10 assert services[0]._get_feed_publisher() == RsFeedPublisher( **DUMMY_INSTANT_SYSTEM_FEED_PUBLISHER) assert services[1].service_url == 'tata' assert services[1].api_key == 'tata key' assert services[1].network == 'M' assert services[1].system_id == 'instant_system' assert services[1].rating_scale_min == 1 assert services[1].rating_scale_max == 5 assert services[1]._get_feed_publisher() == RsFeedPublisher( **DEFAULT_INSTANT_SYSTEM_FEED_PUBLISHER)
def get_ridesharing_service_test(): configs = [ { "class": "jormungandr.scenarios.ridesharing.karos.Karos", "args": { "service_url": "toto", "api_key": "toto key", "network": "N", "timeout": 10, "timedelta": 7000, "departure_radius": 15, "arrival_radius": 15, "feed_publisher": DUMMY_KAROS_FEED_PUBLISHER, }, }, { "class": "jormungandr.scenarios.ridesharing.karos.Karos", "args": { "service_url": "tata", "api_key": "tata key", "network": "M" }, }, ] instance = DummyInstance() ridesharing_service_manager = RidesharingServiceManager(instance, configs) ridesharing_service_manager.init_ridesharing_services() services = ridesharing_service_manager.get_all_ridesharing_services() assert len(services) == 2 assert services[0].service_url == 'toto' assert services[0].api_key == 'toto key' assert services[0].network == 'N' assert services[0].system_id == 'karos' assert services[0].timeout == 10 assert services[0].timedelta == 7000 assert services[0].departure_radius == 15 assert services[0].arrival_radius == 15 assert services[0]._get_feed_publisher() == RsFeedPublisher( **DUMMY_KAROS_FEED_PUBLISHER) assert services[1].service_url == 'tata' assert services[1].api_key == 'tata key' assert services[1].network == 'M' assert services[1].system_id == 'karos' # Default values assert services[1].timeout == 2 assert services[1].timedelta == 3600 assert services[1].departure_radius == 2 assert services[1].arrival_radius == 2 assert services[1]._get_feed_publisher() == RsFeedPublisher( **DEFAULT_KAROS_FEED_PUBLISHER)
def two_ridesharing_service_manager_config_from_file_test(): """ creation of a ride sharing services from the configuration file: Blablalines and InstantSystym Result: We have to find both services Blablalines and InstantSystem """ instance = MockInstance() ridesharing_services_config = [config_blablalines, config_instant_system] ridesharing_manager = RidesharingServiceManager( instance, ridesharing_services_config) ridesharing_manager.init_ridesharing_services() assert len(ridesharing_manager.ridesharing_services_configuration) == 2 assert not ridesharing_manager._ridesharing_services assert not ridesharing_manager._rs_services_getter assert ridesharing_manager._update_interval == 60 assert len(ridesharing_manager._ridesharing_services_legacy) == 2
def blablalines_ridesharing_service_manager_config_from_file_test(): """ creation of a ridesharing service from the configuration file: Blablalines Result: We must find the service Blablalines """ instance = MockInstance() ridesharing_services_config = [config_blablalines] ridesharing_manager = RidesharingServiceManager( instance, ridesharing_services_config) ridesharing_manager.init_ridesharing_services() assert len(ridesharing_manager.ridesharing_services_configuration) == 1 assert not ridesharing_manager._ridesharing_services assert not ridesharing_manager._rs_services_getter assert ridesharing_manager._update_interval == 60 assert len(ridesharing_manager._ridesharing_services_legacy) == 1
def ridesharing_service_manager_config_from_file_and_db_test(): """ creation of a ridesharing service from database: InstantSystem creation of a ridesharing service from database : Blablalines Result: We have to find both services Blablalines and InstantSystem """ instance = MockInstance() ridesharing_manager = RidesharingServiceManager( instance, [], rs_services_getter=mock_get_attr_instant_system_and_blablalines) ridesharing_manager.init_ridesharing_services() ridesharing_manager.update_config() assert len(ridesharing_manager.ridesharing_services_configuration) == 0 assert len(list(ridesharing_manager._ridesharing_services.values())) == 2 assert ridesharing_manager._ridesharing_services[ "InstantSystem"].system_id == "instant_system" assert ridesharing_manager._ridesharing_services[ "Blablalines"].system_id == "blablalines" assert ridesharing_manager._rs_services_getter assert ridesharing_manager._update_interval == 60 assert ridesharing_manager._update_interval == 60 assert len(ridesharing_manager._ridesharing_services_legacy) == 0 services = ridesharing_manager.get_all_ridesharing_services() assert len(services) == 2
def two_same_ridesharing_service_manager_config_from_file_and_db_test(): """ creation of a ridesharing service from the configuration file: InstantSystem creation of a ridesharing service from database : InstantSystem Result: We must find the service InstantSystem """ instance = MockInstance() ridesharing_services_config = [config_instant_system] ridesharing_manager = RidesharingServiceManager( instance, ridesharing_services_config, rs_services_getter=mock_get_attr_instant_system) ridesharing_manager.init_ridesharing_services() ridesharing_manager.update_config() assert len(ridesharing_manager.ridesharing_services_configuration) == 1 assert len(list(ridesharing_manager._ridesharing_services.values())) == 1 assert ridesharing_manager._ridesharing_services[ "InstantSystem"].system_id == "instant_system" assert ridesharing_manager._rs_services_getter assert ridesharing_manager._update_interval == 60 assert ridesharing_manager._update_interval == 60 assert len(ridesharing_manager._ridesharing_services_legacy) == 0 services = ridesharing_manager.get_all_ridesharing_services() assert len(services) == 1
def get_ridesharing_service_test(): configs = [ { "class": "jormungandr.scenarios.ridesharing.blablalines.Blablalines", "args": { "service_url": "toto", "api_key": "toto key", "network": "N", "feed_publisher": DUMMY_BLABLALINES_FEED_PUBLISHER, }, }, { "class": "jormungandr.scenarios.ridesharing.blablalines.Blablalines", "args": { "service_url": "tata", "api_key": "tata key", "network": "M" }, }, ] instance = DummyInstance() ridesharing_service_manager = RidesharingServiceManager(instance, configs) ridesharing_service_manager.init_ridesharing_services() services = ridesharing_service_manager.get_all_ridesharing_services() assert len(services) == 2 assert services[0].service_url == 'toto' assert services[0].api_key == 'toto key' assert services[0].network == 'N' assert services[0].system_id == 'blablalines' assert services[0]._get_feed_publisher() == RsFeedPublisher( **DUMMY_BLABLALINES_FEED_PUBLISHER) assert services[1].service_url == 'tata' assert services[1].api_key == 'tata key' assert services[1].network == 'M' assert services[1].system_id == 'blablalines' assert services[1]._get_feed_publisher() == RsFeedPublisher( **DEFAULT_BLABLALINES_FEED_PUBLISHER)
def __init__( self, context, # type: zmq.Context name, # type: Text zmq_socket, # type: Text street_network_configurations, ridesharing_configurations, realtime_proxies_configuration, zmq_socket_type, autocomplete_type, instance_equipment_providers, # type: List[Text] streetnetwork_backend_manager, external_service_provider_configurations, pt_zmq_socket=None, # type: Text ): self.geom = None self.geojson = None self._sockets = deque() self._pt_sockets = deque() self.socket_path = zmq_socket self._scenario = None self._scenario_name = None self.lock = Lock() self.context = context self.name = name self.timezone = None # timezone will be fetched from the kraken self.publication_date = -1 self.is_initialized = False # kraken hasn't been called yet we don't have geom nor timezone self.breaker = pybreaker.CircuitBreaker( fail_max=app.config.get(str('CIRCUIT_BREAKER_MAX_INSTANCE_FAIL'), 5), reset_timeout=app.config.get( str('CIRCUIT_BREAKER_INSTANCE_TIMEOUT_S'), 60), ) self.georef = georef.Kraken(self) self.planner = planner.Kraken(self) self._streetnetwork_backend_manager = streetnetwork_backend_manager if pt_zmq_socket: self.pt_socket_path = pt_zmq_socket else: self.pt_socket_path = zmq_socket disable_database = app.config[str('DISABLE_DATABASE')] if disable_database: self._streetnetwork_backend_manager.init_streetnetwork_backends_legacy( self, street_network_configurations) self.ridesharing_services_manager = RidesharingServiceManager( self, ridesharing_configurations) else: self.ridesharing_services_manager = RidesharingServiceManager( self, ridesharing_configurations, self.get_ridesharing_services_from_db) # Init Ridesharing services from config file self.ridesharing_services_manager.init_ridesharing_services() self.ptref = ptref.PtRef(self) self.schedule = schedule.MixedSchedule(self) self.realtime_proxy_manager = realtime_schedule.RealtimeProxyManager( realtime_proxies_configuration, self) self._autocomplete_type = autocomplete_type if self._autocomplete_type is not None and self._autocomplete_type not in global_autocomplete: raise RuntimeError('impossible to find autocomplete system {} ' 'cannot initialize instance {}'.format( autocomplete_type, name)) self.zmq_socket_type = zmq_socket_type if disable_database: self.equipment_provider_manager = EquipmentProviderManager( app.config[str('EQUIPMENT_DETAILS_PROVIDERS')]) else: self.equipment_provider_manager = EquipmentProviderManager( app.config[str('EQUIPMENT_DETAILS_PROVIDERS')], self.get_providers_from_db) # Init equipment providers from config self.equipment_provider_manager.init_providers( instance_equipment_providers) # Init free-floating providers from config if disable_database: self.external_service_provider_manager = ExternalServiceManager( self, external_service_provider_configurations) else: self.external_service_provider_manager = ExternalServiceManager( self, external_service_provider_configurations, self.get_external_service_providers_from_db) self.external_service_provider_manager.init_external_services()
class Instance(object): name = None # type: Text _sockets = None # type: Deque[Tuple[zmq.Socket, float]] _pt_sockets = None # type: Deque[Tuple[zmq.Socket, float]] def __init__( self, context, # type: zmq.Context name, # type: Text zmq_socket, # type: Text street_network_configurations, ridesharing_configurations, realtime_proxies_configuration, zmq_socket_type, autocomplete_type, instance_equipment_providers, # type: List[Text] streetnetwork_backend_manager, external_service_provider_configurations, pt_zmq_socket=None, # type: Text ): self.geom = None self.geojson = None self._sockets = deque() self._pt_sockets = deque() self.socket_path = zmq_socket self._scenario = None self._scenario_name = None self.lock = Lock() self.context = context self.name = name self.timezone = None # timezone will be fetched from the kraken self.publication_date = -1 self.is_initialized = False # kraken hasn't been called yet we don't have geom nor timezone self.breaker = pybreaker.CircuitBreaker( fail_max=app.config.get(str('CIRCUIT_BREAKER_MAX_INSTANCE_FAIL'), 5), reset_timeout=app.config.get( str('CIRCUIT_BREAKER_INSTANCE_TIMEOUT_S'), 60), ) self.georef = georef.Kraken(self) self.planner = planner.Kraken(self) self._streetnetwork_backend_manager = streetnetwork_backend_manager if pt_zmq_socket: self.pt_socket_path = pt_zmq_socket else: self.pt_socket_path = zmq_socket disable_database = app.config[str('DISABLE_DATABASE')] if disable_database: self._streetnetwork_backend_manager.init_streetnetwork_backends_legacy( self, street_network_configurations) self.ridesharing_services_manager = RidesharingServiceManager( self, ridesharing_configurations) else: self.ridesharing_services_manager = RidesharingServiceManager( self, ridesharing_configurations, self.get_ridesharing_services_from_db) # Init Ridesharing services from config file self.ridesharing_services_manager.init_ridesharing_services() self.ptref = ptref.PtRef(self) self.schedule = schedule.MixedSchedule(self) self.realtime_proxy_manager = realtime_schedule.RealtimeProxyManager( realtime_proxies_configuration, self) self._autocomplete_type = autocomplete_type if self._autocomplete_type is not None and self._autocomplete_type not in global_autocomplete: raise RuntimeError('impossible to find autocomplete system {} ' 'cannot initialize instance {}'.format( autocomplete_type, name)) self.zmq_socket_type = zmq_socket_type if disable_database: self.equipment_provider_manager = EquipmentProviderManager( app.config[str('EQUIPMENT_DETAILS_PROVIDERS')]) else: self.equipment_provider_manager = EquipmentProviderManager( app.config[str('EQUIPMENT_DETAILS_PROVIDERS')], self.get_providers_from_db) # Init equipment providers from config self.equipment_provider_manager.init_providers( instance_equipment_providers) # Init free-floating providers from config if disable_database: self.external_service_provider_manager = ExternalServiceManager( self, external_service_provider_configurations) else: self.external_service_provider_manager = ExternalServiceManager( self, external_service_provider_configurations, self.get_external_service_providers_from_db) self.external_service_provider_manager.init_external_services() def get_providers_from_db(self): """ :return: a callable query of equipment providers associated to the current instance in db """ return self._get_models().equipment_details_providers def get_ridesharing_services_from_db(self): """ :return: a callable query of ridesharing services associated to the current instance in db """ return self._get_models().ridesharing_services def get_external_service_providers_from_db(self): """ :return: a callable query of external services associated to the current instance in db """ return self._get_models().external_services @property def autocomplete(self): if self._autocomplete_type: # retrocompat: we need to continue to read configuration from file # while we migrate to database configuration return global_autocomplete.get(self._autocomplete_type) backend = global_autocomplete.get(self.autocomplete_backend) if backend is None: raise RuntimeError( 'impossible to find autocomplete {} for instance {}'.format( self.autocomplete_backend, self.name)) return backend def stop_point_fallbacks(self): return [ a for a in global_autocomplete.values() if a.is_handling_stop_points() ] def get_models(self): if self.name not in g.instances_model: g.instances_model[self.name] = self._get_models() return g.instances_model[self.name] def __repr__(self): return 'instance.{}'.format(self.name) @memory_cache.memoize(app.config[str('MEMORY_CACHE_CONFIGURATION')].get( str('TIMEOUT_PARAMS'), 30)) @cache.memoize(app.config[str('CACHE_CONFIGURATION')].get( str('TIMEOUT_PARAMS'), 300)) def _get_models(self): if app.config['DISABLE_DATABASE']: return None return models.Instance.get_by_name(self.name) def scenario(self, override_scenario=None): """ once a scenario has been chosen for a request for an instance (coverage), we cannot change it """ if hasattr(g, 'scenario') and g.scenario.get(self.name): return g.scenario[self.name] def replace_experimental_scenario(s): return 'distributed' if s == 'experimental' else s if override_scenario: logger = logging.getLogger(__name__) logger.debug('overriding the scenario for %s with %s', self.name, override_scenario) try: # for the sake of backwards compatibility... some users may still be using experimental... override_scenario = replace_experimental_scenario( override_scenario) module = import_module( 'jormungandr.scenarios.{}'.format(override_scenario)) except ImportError: logger.exception('scenario not found') abort(404, message='invalid scenario: {}'.format(override_scenario)) scenario = module.Scenario() # Save scenario_name and scenario self._scenario_name = override_scenario self._scenario = scenario if not hasattr(g, 'scenario'): g.scenario = {} g.scenario[self.name] = scenario return scenario instance_db = self.get_models() scenario_name = instance_db.scenario if instance_db else 'new_default' # for the sake of backwards compatibility... some users may still be using experimental... scenario_name = replace_experimental_scenario(scenario_name) if not self._scenario or scenario_name != self._scenario_name: logger = logging.getLogger(__name__) logger.info('loading of scenario %s for instance %s', scenario_name, self.name) self._scenario_name = scenario_name module = import_module( 'jormungandr.scenarios.{}'.format(scenario_name)) self._scenario = module.Scenario() # we save the used scenario for future use if not hasattr(g, 'scenario'): g.scenario = {} g.scenario[self.name] = self._scenario return self._scenario @property def max_waiting_duration(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_waiting_duration', instance_db, self.name) @property def journey_order(self): # type: () -> Text instance_db = self.get_models() return get_value_or_default('journey_order', instance_db, self.name) @property def autocomplete_backend(self): # type: () -> Text instance_db = self.get_models() return get_value_or_default('autocomplete_backend', instance_db, self.name) @property def max_walking_duration_to_pt(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_walking_duration_to_pt', instance_db, self.name) @property def max_bss_duration_to_pt(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_bss_duration_to_pt', instance_db, self.name) @property def max_bike_duration_to_pt(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_bike_duration_to_pt', instance_db, self.name) @property def max_car_duration_to_pt(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_car_duration_to_pt', instance_db, self.name) @property def max_car_no_park_duration_to_pt(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_car_no_park_duration_to_pt', instance_db, self.name) @property def max_ridesharing_duration_to_pt(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_ridesharing_duration_to_pt', instance_db, self.name) @property def max_taxi_duration_to_pt(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_taxi_duration_to_pt', instance_db, self.name) @property def walking_speed(self): # type: () -> float instance_db = self.get_models() return get_value_or_default('walking_speed', instance_db, self.name) @property def bss_speed(self): # type: () -> float instance_db = self.get_models() return get_value_or_default('bss_speed', instance_db, self.name) @property def bike_speed(self): # type: () -> float instance_db = self.get_models() return get_value_or_default('bike_speed', instance_db, self.name) @property def car_speed(self): # type: () -> float instance_db = self.get_models() return get_value_or_default('car_speed', instance_db, self.name) @property def car_no_park_speed(self): # type: () -> float instance_db = self.get_models() return get_value_or_default('car_no_park_speed', instance_db, self.name) @property def ridesharing_speed(self): # type: () -> float instance_db = self.get_models() return get_value_or_default('ridesharing_speed', instance_db, self.name) @property def max_nb_transfers(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_nb_transfers', instance_db, self.name) @property def min_bike(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('min_bike', instance_db, self.name) @property def min_bss(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('min_bss', instance_db, self.name) @property def min_car(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('min_car', instance_db, self.name) @property def min_taxi(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('min_taxi', instance_db, self.name) @property def successive_physical_mode_to_limit_id(self): # type: () -> Text instance_db = self.get_models() return get_value_or_default('successive_physical_mode_to_limit_id', instance_db, self.name) @property def priority(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('priority', instance_db, self.name) @property def bss_provider(self): # type: () -> bool instance_db = self.get_models() return get_value_or_default('bss_provider', instance_db, self.name) @property def car_park_provider(self): # type: () -> bool instance_db = self.get_models() return get_value_or_default('car_park_provider', instance_db, self.name) @property def max_additional_connections(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_additional_connections', instance_db, self.name) @property def is_free(self): # type: () -> bool instance_db = self.get_models() if not instance_db: return False else: return instance_db.is_free @property def is_open_data(self): # type: () -> bool instance_db = self.get_models() if not instance_db: return False else: return instance_db.is_open_data @property def max_duration(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_duration', instance_db, self.name) @property def walking_transfer_penalty(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('walking_transfer_penalty', instance_db, self.name) @property def night_bus_filter_max_factor(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('night_bus_filter_max_factor', instance_db, self.name) @property def night_bus_filter_base_factor(self): # type: () -> float instance_db = self.get_models() return get_value_or_default('night_bus_filter_base_factor', instance_db, self.name) @property def realtime_pool_size(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('realtime_pool_size', instance_db, self.name) @property def min_nb_journeys(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('min_nb_journeys', instance_db, self.name) @property def max_nb_journeys(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_nb_journeys', instance_db, self.name) @property def min_journeys_calls(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('min_journeys_calls', instance_db, self.name) @property def max_successive_physical_mode(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_successive_physical_mode', instance_db, self.name) @property def final_line_filter(self): instance_db = self.get_models() return get_value_or_default('final_line_filter', instance_db, self.name) @property def max_extra_second_pass(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_extra_second_pass', instance_db, self.name) @property def asynchronous_ridesharing(self): # type: () -> bool instance_db = self.get_models() return get_value_or_default('asynchronous_ridesharing', instance_db, self.name) @property def ridesharing_greenlet_pool_size(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('ridesharing_greenlet_pool_size', instance_db, self.name) @property def greenlet_pool_for_ridesharing_services(self): # type: () -> bool instance_db = self.get_models() return get_value_or_default('greenlet_pool_for_ridesharing_services', instance_db, self.name) @property def max_nb_crowfly_by_mode(self): # type: () -> Dict[Text, int] instance_db = self.get_models() # the value by default is a dict... d = copy.deepcopy( get_value_or_default('max_nb_crowfly_by_mode', instance_db, self.name)) # In case we add a new max_nb_crowfly for an other mode than # the ones already present in the database. for mode, duration in default_values.max_nb_crowfly_by_mode.items(): if mode not in d: d[mode] = duration return d @property def poi_dataset(self): # type: () -> Text instance_db = self.get_models() return instance_db.poi_dataset if instance_db else None @property def max_car_no_park_direct_path_duration(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('max_car_no_park_direct_path_duration', instance_db, self.name) @property def min_ridesharing(self): # type: () -> int instance_db = self.get_models() return get_value_or_default('min_ridesharing', instance_db, self.name) # TODO: refactorise all properties taxi_speed = _make_property_getter('taxi_speed') additional_time_after_first_section_taxi = _make_property_getter( 'additional_time_after_first_section_taxi') additional_time_before_last_section_taxi = _make_property_getter( 'additional_time_before_last_section_taxi') max_walking_direct_path_duration = _make_property_getter( 'max_walking_direct_path_duration') max_bike_direct_path_duration = _make_property_getter( 'max_bike_direct_path_duration') max_bss_direct_path_duration = _make_property_getter( 'max_bss_direct_path_duration') max_car_direct_path_duration = _make_property_getter( 'max_car_direct_path_duration') max_taxi_direct_path_duration = _make_property_getter( 'max_taxi_direct_path_duration') max_ridesharing_direct_path_duration = _make_property_getter( 'max_ridesharing_direct_path_duration') street_network_car = _make_property_getter('street_network_car') street_network_car_no_park = _make_property_getter( 'street_network_car_no_park') street_network_walking = _make_property_getter('street_network_walking') street_network_bike = _make_property_getter('street_network_bike') street_network_bss = _make_property_getter('street_network_bss') street_network_ridesharing = _make_property_getter( 'street_network_ridesharing') street_network_taxi = _make_property_getter('street_network_taxi') stop_points_nearby_duration = _make_property_getter( 'stop_points_nearby_duration') def reap_socket(self, ttl): # type: (int) -> None if self.zmq_socket_type != 'transient': return logger = logging.getLogger(__name__) now = time.time() def _reap_sockets(sockets): while True: try: socket, t = sockets.popleft() if now - t > ttl: logger.debug("closing one socket for %s", self.name) socket.setsockopt(zmq.LINGER, 0) socket.close() else: self._sockets.appendleft((socket, t)) break # remaining socket are still in "keep alive" state except IndexError: break _reap_sockets(self._sockets) _reap_sockets(self._pt_sockets) @contextmanager def socket(self, context, pt_socket=False): socket = None if pt_socket: sockets = self._pt_sockets socket_path = self.pt_socket_path else: sockets = self._sockets socket_path = self.socket_path try: socket, _ = sockets.pop() except IndexError: # there is no socket available: lets create one socket = context.socket(zmq.REQ) socket.connect(socket_path) try: yield socket finally: if not socket.closed: sockets.append((socket, time.time())) def send_and_receive(self, *args, **kwargs): """ encapsulate all call to kraken in a circuit breaker, this way we don't loose time calling dead instance """ try: return self.breaker.call(self._send_and_receive, *args, **kwargs) except pybreaker.CircuitBreakerError as e: raise DeadSocketException(self.name, self.socket_path) def _send_and_receive(self, request, timeout=app.config.get('INSTANCE_TIMEOUT', 10000), quiet=False, **kwargs): logger = logging.getLogger(__name__) deadline = datetime.utcnow() + timedelta(milliseconds=timeout) request.deadline = deadline.strftime('%Y%m%dT%H%M%S,%f') pt_socket = request.requested_api == type_pb2.pt_planner with self.socket(self.context, pt_socket) as socket: if 'request_id' in kwargs and kwargs['request_id']: request.request_id = kwargs['request_id'] else: try: request.request_id = flask.request.id except RuntimeError: # we aren't in a flask context, so there is no request if 'flask_request_id' in kwargs and kwargs[ 'flask_request_id']: request.request_id = kwargs['flask_request_id'] socket.send(request.SerializeToString()) if socket.poll(timeout=timeout) > 0: pb = socket.recv() resp = response_pb2.Response() resp.ParseFromString(pb) self.update_property( resp ) # we update the timezone and geom of the instances at each request return resp else: socket.setsockopt(zmq.LINGER, 0) socket.close() if not quiet: logger.error('request on %s failed: %s', self.socket_path, six.text_type(request)) raise DeadSocketException(self.name, self.socket_path) def get_id(self, id_): """ Get the pt_object that have the given id """ req = request_pb2.Request() req.requested_api = type_pb2.place_uri req.place_uri.uri = id_ return self.send_and_receive(req, timeout=app.config.get( 'INSTANCE_FAST_TIMEOUT', 1000)) def has_id(self, id_): """ Does this instance has this id """ try: return len(self.get_id(id_).places) > 0 except DeadSocketException: return False def has_coord(self, lon, lat): return self.has_point(geometry.Point(lon, lat)) def has_point(self, p): try: return self.geom and self.geom.contains(p) except DeadSocketException: return False except PredicateError: logging.getLogger(__name__).exception("has_coord failed") return False except TopologicalError: logging.getLogger(__name__).exception("check_topology failed") return False def get_external_codes(self, type_, id_): """ Get all pt_object with the given id """ req = request_pb2.Request() req.requested_api = type_pb2.place_code if type_ not in type_to_pttype: raise ValueError( "Can't call pt_code API with type: {}".format(type_)) req.place_code.type = type_to_pttype[type_] req.place_code.type_code = "external_code" req.place_code.code = id_ # we set the timeout to 1s return self.send_and_receive(req, timeout=app.config.get( 'INSTANCE_FAST_TIMEOUT', 1000)) def has_external_code(self, type_, id_): """ Does this instance has the given id Returns None if it doesnt, the kraken uri otherwise """ try: res = self.get_external_codes(type_, id_) except DeadSocketException: return False if len(res.places) > 0: return res.places[0].uri return None def update_property(self, response): """ update the property of an instance from a response if the metadatas field if present """ # after a successful call we consider the instance initialised even if no data were loaded self.is_initialized = True if response.HasField( str("metadatas" )) and response.publication_date != self.publication_date: logging.getLogger(__name__).debug('updating metadata for %s', self.name) with self.lock as lock: self.publication_date = response.publication_date if response.metadatas.shape and response.metadatas.shape != "": try: self.geom = wkt.loads(response.metadatas.shape) except ReadingError: self.geom = None else: self.geom = None self.timezone = response.metadatas.timezone self._update_geojson() set_request_instance_timezone(self) def _update_geojson(self): """construct the geojson object from the shape""" if not self.geom or not self.geom.is_valid: self.geojson = None return # simplify the geom to prevent slow query on bragi geom = self.geom.simplify(tolerance=0.01) self.geojson = geometry.mapping(geom) def init(self): """ Get and store variables of the instance. Returns True if we need to clear the cache, False otherwise. """ pub_date = self.publication_date req = request_pb2.Request() req.requested_api = type_pb2.METADATAS request_id = "instance_init" try: # we use _send_and_receive to avoid the circuit breaker, we don't want fast fail on init :) resp = self._send_and_receive(req, request_id=request_id, timeout=1000, quiet=True) # the instance is automatically updated on a call if self.publication_date != pub_date: return True except DeadSocketException: # we don't do anything on error, a new session will be established to an available kraken on # the next request. We don't want to purge all our cache for a small error. logging.getLogger(__name__).debug('timeout on init for %s', self.name) return False def _get_street_network(self, mode, request): if app.config[str('DISABLE_DATABASE')]: return self._streetnetwork_backend_manager.get_street_network_legacy( self, mode, request) else: # We get the name of the column in the database corresponding to the mode used in the request # And we get the value of this column for this instance column_in_db = "street_network_{}".format(mode) streetnetwork_backend_conf = getattr(self, column_in_db) return self._streetnetwork_backend_manager.get_street_network_db( self, streetnetwork_backend_conf) def get_street_network(self, mode, request): if mode != fallback_modes.FallbackModes.car.name: return self._get_street_network(mode, request) walking_service = self._get_street_network( fallback_modes.FallbackModes.walking.name, request) car_service = self._get_street_network( fallback_modes.FallbackModes.car.name, request) return street_network.CarWithPark(instance=self, walking_service=walking_service, car_service=car_service) def get_all_street_networks(self): if app.config[str('DISABLE_DATABASE')]: return self._streetnetwork_backend_manager.get_all_street_networks_legacy( self) else: return self._streetnetwork_backend_manager.get_all_street_networks_db( self) def get_all_ridesharing_services(self): return self.ridesharing_services_manager.get_all_ridesharing_services() def get_autocomplete(self, requested_autocomplete): if not requested_autocomplete: return self.autocomplete autocomplete = global_autocomplete.get(requested_autocomplete) if not autocomplete: raise TechnicalError( 'autocomplete {} not available'.format(requested_autocomplete)) return autocomplete