def __init__(self, app_config: AppConfig, app_connection: str): self.app_key = app_config.app_key() self.app_conn_key = app_connection self.app_connection = app_config.app_connections[app_connection] settings_key = self.app_connection.settings or app_connection self.settings = Payload.from_obj( app_config.settings.get(settings_key, {}), AppsClientSettings) self.event_connections = { event_name: { conn.event: conn for conn in event_info.connections if conn.app_connection == app_connection } for event_name, event_info in app_config.events.items() } self.routes = { conn.event: self._get_route(conn.event) for event_info in app_config.events.values() for conn in event_info.connections if conn.app_connection == app_connection } self.conn_state: Optional[AppConnectionState] = None self.session: Optional[Any] = None self.token: Optional[str] = None self.token_expire: int = 0
def _update_api_paths(app_config: AppConfig, plugin: Optional[AppConfig] = None): """ Populates paths section of spec based on __api__ specified in implemented events """ assert spec is not None events = { k: v for k, v in app_config.events.items() if v.plug_mode == EventPlugMode.STANDALONE } if plugin is None else { k: v for k, v in plugin.events.items() if v.plug_mode == EventPlugMode.ON_APP } plugin_app = None if plugin is None else plugin.app paths = spec.get('paths', {}) for event_name, event_info in events.items(): route = app_route_name(app_config.app, event_name=event_name, plugin=plugin_app, override_route_name=event_info.route) method = METHOD_MAPPING.get(event_info.type) if method is None: continue event_api_spec = _extract_event_api_spec( app_config if plugin is None else plugin, event_name, event_info ) if event_api_spec is None: event_api_spec = paths.get(route, {}).get(method) if event_api_spec is None and _options.get('generate_mode'): event_api_spec = {"description": f"<<<{event_name}>>>", "parameters": [], "responses": {}} if event_api_spec is not None: event_api_spec['tags'] = [app_config.app_key()] _set_optional_fixed_headers(event_api_spec) _set_track_headers(event_api_spec, app_config) _set_path_security(event_api_spec, app_config, event_info) route_path = paths.get(route, {}) route_path[method] = event_api_spec paths[route] = route_path spec['paths'] = paths
def _setup_client_context(app_config: AppConfig, server_app_config: AppConfig, register_client_key: bool = True) -> EventContext: _init_engine_logger(app_config) assert app_config.server assert server_app_config.server app_config.server.auth = AuthConfig( secrets_location=f"/tmp/{uuid.uuid4()}", auth_passphrase='test_passphrase', enabled=True, create_keys=True ) auth.init(app_config.app_key(), app_config.server.auth) if register_client_key: os.rename( pathlib.Path(app_config.server.auth.secrets_location) / 'public' / f'{app_config.app_key()}_pub.pem', pathlib.Path(server_app_config.server.auth.secrets_location) / 'public' / f'{app_config.app_key()}_pub.pem' ) return EventContext( app_config=app_config, plugin_config=app_config, event_name='mock_event', settings=get_event_settings(app_config.effective_settings, 'mock_event'), # type: ignore track_ids={}, auth_info={} )
def __init__(self, *, app_config: AppConfig, plugins: List[AppConfig], enabled_groups: List[str], streams_enabled: bool = True): """ Creates an instance of the AppEngine :param app_config: AppConfig, Hopeit application configuration as specified in config module :param plugins: List of AppConfig, Hopeit application configurations for enabled plugins :enabled_groups: List of str, list of enabled event groups :streams_enabled: bool, for testing, set to False to disable automatic starting streams """ self.app_config = app_config self.app_key = app_config.app_key() self.effective_events = self._config_effective_events( app_config, enabled_groups) self.plugins = plugins self.settings = get_runtime_settings(app_config, plugins) self.event_handler: Optional[EventHandler] = None self.streams_enabled = streams_enabled self.stream_manager: Optional[StreamManager] = None self._running: Dict[str, asyncio.Lock] = { event_name: asyncio.Lock() for event_name, event_info in self.effective_events.items() if event_info.type in (EventType.STREAM, EventType.SERVICE) } logger.init_app(app_config, plugins)
async def register_app_connections(app_config: AppConfig): """ Used by the engine to initialize and keep client connections """ _registered_clients[app_config.app_key()] = { app_connection: await Client.create(app_config, app_connection).start() for app_connection in app_config.app_connections.keys() }
async def start_app(self, app_config: AppConfig): """ Starts and register a Hopeit App into this engine instance :param app_config: AppConfog, app configuration as specified in config module """ logger.info(__name__, f"Starting app={app_config.app_key()}...") plugins = [ self.app_engine(app_key=plugin.app_key()).app_config for plugin in app_config.plugins ] app_engine = await AppEngine(app_config=app_config, plugins=plugins).start() self.app_engines[app_config.app_key()] = app_engine return app_engine
def _set_path_security(event_api_spec: dict, app_config: AppConfig, event_info: EventDescriptor): """ Setup security schemes allowed for each path """ assert spec is not None security: list = [] for auth in event_info.auth: if auth == AuthType.REFRESH: _update_auth_refresh_method(app_config.app_key()) auth_str = f"{app_config.app_key()}.refresh" security.append({auth_str: []}) elif auth != AuthType.UNSECURED: auth_str = f"auth.{auth.value.lower()}" security.append({auth_str: []}) if len(security) == 0 and AuthType.UNSECURED not in event_info.auth: security = spec['security'] if len(security) > 0: event_api_spec['security'] = security
async def stream_startup_hook(app_config: AppConfig, *args, **kwargs): """ Start all stream event types configured in app. :param app_key: already started app_key """ app_engine = runtime.server.app_engines[app_config.app_key()] for event_name, event_info in app_engine.effective_events.items(): if event_info.type == EventType.STREAM: assert event_info.read_stream logger.info( __name__, f"STREAM start event_name={event_name} read_stream={event_info.read_stream.name}" ) asyncio.create_task(app_engine.read_stream(event_name=event_name)) elif event_info.type == EventType.SERVICE: logger.info(__name__, f"SERVICE start event_name={event_name}") asyncio.create_task(app_engine.service_loop(event_name=event_name))
def _setup_server_context(app_config: AppConfig) -> EventContext: _init_engine_logger(app_config) assert app_config.server app_config.server.auth = AuthConfig( secrets_location=f"/tmp/{uuid.uuid4()}", auth_passphrase='test_passphrase', enabled=True, create_keys=True ) auth.init(app_config.app_key(), app_config.server.auth) return EventContext( app_config=app_config, plugin_config=app_config, event_name='mock_event', settings=get_event_settings(app_config.effective_settings, 'mock_event'), # type: ignore track_ids={}, auth_info={} )
def __init__(self, *, app_config: AppConfig, plugin_config: AppConfig, event_name: str, track_ids: Dict[str, str], auth_info: Dict[str, Any]): self.app_key: str = app_config.app_key() self.app: AppDescriptor = app_config.app self.env: Env = {**plugin_config.env, **app_config.env} self.event_name = event_name base_event = event_name.split('$')[0] self.event_info: EventDescriptor = plugin_config.events[base_event] self.creation_ts: datetime = datetime.now().astimezone(tz=timezone.utc) self.auth_info = auth_info track_fields = [ 'track.operation_id', *app_config.engine.track_headers, *(self.event_info.config.logging.stream_fields if self.event_info.type == EventType.STREAM else []) ] self.track_ids = {k: track_ids.get(k) or '' for k in track_fields}