def on_GET(self, origin, content, query): return defer.succeed((200, { "server": { "name": "Synapse", "version": get_version_string(synapse) }, }))
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse frontend proxy", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-frontend-proxy", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts ss = SynchrotronServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), application_service_handler=SynchrotronApplicationService(), ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-synchrotron", config)
def setup_logging(hs, config, use_worker_options=False, logBeginner: LogBeginner = globalLogBeginner) -> None: """ Set up the logging subsystem. Args: config (LoggingConfig | synapse.config.worker.WorkerConfig): configuration data use_worker_options (bool): True to use the 'worker_log_config' option instead of 'log_config'. logBeginner: The Twisted logBeginner to use. """ log_config_path = (config.worker_log_config if use_worker_options else config.log_config) # Perform one-time logging configuration. _setup_stdlib_logging(config, log_config_path, logBeginner=logBeginner) # Add a SIGHUP handler to reload the logging configuration, if one is available. appbase.register_sighup(_reload_logging_config, log_config_path) # Log immediately so we can grep backwards. logging.warning("***** STARTING SERVER *****") logging.warning("Server %s version %s", sys.argv[0], get_version_string(synapse)) logging.info("Server hostname: %s", config.server_name) logging.info("Instance name: %s", hs.get_instance_name())
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse client reader", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.client_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = ClientReaderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-client-reader", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse synchrotron", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config, use_worker_options=True) synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-synchrotron", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config, use_worker_options=True) synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-synchrotron", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse client reader", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.client_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = ClientReaderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-client-reader", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse event creator", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.event_creator" assert config.worker_replication_http_port is not None # This should only be done on the user directory worker or the master config.update_user_directory = False events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = EventCreatorServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-event-creator", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse media repository", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" if config.enable_media_repo: _base.quit_with_error( "enable_media_repo must be disabled in the main synapse process\n" "before the media repo can be run in a separate worker.\n" "Please add ``enable_media_repo: false`` to the main config\n") events.USE_FROZEN_DICTS = config.use_frozen_dicts ss = MediaRepositoryServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-media-repository", config)
def setup_logging( hs, config, use_worker_options=False, logBeginner: LogBeginner = globalLogBeginner) -> ILogObserver: """ Set up the logging subsystem. Args: config (LoggingConfig | synapse.config.workers.WorkerConfig): configuration data use_worker_options (bool): True to use the 'worker_log_config' option instead of 'log_config'. logBeginner: The Twisted logBeginner to use. Returns: The "root" Twisted Logger observer, suitable for sending logs to from a Logger instance. """ log_config = config.worker_log_config if use_worker_options else config.log_config def read_config(*args, callback=None): if log_config is None: return None with open(log_config, "rb") as f: log_config_body = yaml.safe_load(f.read()) if callback: callback(log_config=log_config_body) logging.info("Reloaded log config from %s due to SIGHUP", log_config) return log_config_body log_config_body = read_config() if log_config_body and log_config_body.get("structured") is True: logger = setup_structured_logging(hs, config, log_config_body, logBeginner=logBeginner) appbase.register_sighup(read_config, callback=reload_structured_logging) else: logger = _setup_stdlib_logging(config, log_config_body, logBeginner=logBeginner) appbase.register_sighup(read_config, callback=_reload_stdlib_logging) # make sure that the first thing we log is a thing we can grep backwards # for logging.warning("***** STARTING SERVER *****") logging.warning("Server %s version %s", sys.argv[0], get_version_string(synapse)) logging.info("Server hostname: %s", config.server_name) return logger
def start(config_options): try: config = HomeServerConfig.load_config("Synapse frontend proxy", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-frontend-proxy", config)
def setup(config_options): """ Args: config_options_options: The options passed to Synapse. Usually `sys.argv[1:]`. Returns: HomeServer """ try: config = HomeServerConfig.load_or_generate_config( "Synapse Homeserver", config_options) except ConfigError as e: sys.stderr.write("\n") for f in format_config_error(e): sys.stderr.write(f) sys.stderr.write("\n") sys.exit(1) if not config: # If a config isn't returned, and an exception isn't raised, we're just # generating config files and shouldn't try to continue. sys.exit(0) events.USE_FROZEN_DICTS = config.use_frozen_dicts synapse.util.caches.TRACK_MEMORY_USAGE = config.caches.track_memory_usage if config.server.gc_seconds: synapse.metrics.MIN_TIME_BETWEEN_GCS = config.server.gc_seconds hs = SynapseHomeServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), ) synapse.config.logger.setup_logging(hs, config, use_worker_options=False) logger.info("Setting up server") try: hs.setup() except Exception as e: handle_startup_exception(e) async def start(): # Load the OIDC provider metadatas, if OIDC is enabled. if hs.config.oidc_enabled: oidc = hs.get_oidc_handler() # Loading the provider metadata also ensures the provider config is valid. await oidc.load_metadata() await _base.start(hs) hs.get_datastore().db_pool.updates.start_doing_background_updates() register_start(start) return hs
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config, use_worker_options=True) synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def run(): # make sure that we run the reactor with the sentinel log context, # otherwise other PreserveLoggingContext instances will get confused # and complain when they see the logcontext arbitrarily swapping # between the sentinel and `run` logcontexts. with PreserveLoggingContext(): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_datastore().start_profiling() ss.replicate() ss.get_state_handler().start_caching() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-synchrotron", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def start(config_options): try: config = HomeServerConfig.load_config("Synapse client reader", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.client_reader" setup_logging(config.worker_log_config, config.worker_log_file) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = ClientReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.get_handlers() ss.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() ss.replicate() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-client-reader", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation reader", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_reader" setup_logging(config.worker_log_config, config.worker_log_file) database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = FederationReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.get_handlers() ss.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() ss.replicate() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-federation-reader", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
async def on_GET(self, origin, content, query): return ( 200, { "server": { "name": "Synapse", "version": get_version_string(synapse) } }, )
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config.worker_log_config, config.worker_log_file) database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_datastore().start_profiling() ss.replicate() ss.get_state_handler().start_caching() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-synchrotron", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse user directory", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.user_dir" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.update_user_directory: sys.stderr.write( "\nThe update_user_directory must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``update_user_directory: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.update_user_directory = True tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ps = UserDirectoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_datastore().start_profiling() ps.get_state_handler().start_caching() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-user-dir", config)
def on_GET(self, request): requester = yield self.auth.get_user_by_req(request) is_admin = yield self.auth.is_server_admin(requester.user) if not is_admin: raise AuthError(403, "You are not a server admin") ret = { 'server_version': get_version_string(synapse), 'python_version': platform.python_version(), } defer.returnValue((200, ret))
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse user directory", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.user_dir" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.update_user_directory: sys.stderr.write( "\nThe update_user_directory must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``update_user_directory: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.update_user_directory = True tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ps = UserDirectoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-user-dir", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation sender", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_sender" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.send_federation: sys.stderr.write( "\nThe send_federation must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``send_federation: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.send_federation = True tls_server_context_factory = context_factory.ServerContextFactory(config) ps = FederationSenderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_datastore().start_profiling() ps.get_state_handler().start_caching() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-sender", config)
async def on_GET( self, origin: Optional[str], content: Literal[None], query: Dict[bytes, List[bytes]], ) -> Tuple[int, JsonDict]: return ( 200, { "server": { "name": "Synapse", "version": get_version_string(synapse) } }, )
def start(config_options): try: config = HomeServerConfig.load_config("Synapse federation sender", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_sender" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.send_federation: sys.stderr.write( "\nThe send_federation must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``send_federation: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.send_federation = True ss = FederationSenderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() def start(): ss.config.read_certificate_from_disk() ss.tls_server_context_factory = context_factory.ServerContextFactory( config) ss.tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss.start_listening(config.worker_listeners) ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-sender", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse pusher", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_pusherpool().start() ps.get_datastore().start_profiling() ps.get_state_handler().start_caching() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-pusher", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse pusher", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_pusherpool().start() ps.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-pusher", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse media repository", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" if config.enable_media_repo: _base.quit_with_error( "enable_media_repo must be disabled in the main synapse process\n" "before the media repo can be run in a separate worker.\n" "Please add ``enable_media_repo: false`` to the main config\n" ) setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ss = MediaRepositoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-media-repository", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse media repository", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" if config.enable_media_repo: _base.quit_with_error( "enable_media_repo must be disabled in the main synapse process\n" "before the media repo can be run in a separate worker.\n" "Please add ``enable_media_repo: false`` to the main config\n") setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss = MediaRepositoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-media-repository", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse event creator", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.event_creator" assert config.worker_replication_http_port is not None setup_logging(config, use_worker_options=True) # This should only be done on the user directory worker or the master config.update_user_directory = False events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ss = EventCreatorServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-event-creator", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation sender", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_sender" events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.send_federation: sys.stderr.write( "\nThe send_federation must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``send_federation: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.send_federation = True ss = FederationSenderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger( "before", "startup", _base.start, ss, config.worker_listeners ) _base.start_worker_reactor("synapse-federation-sender", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse frontend proxy", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-frontend-proxy", config)
def setup_sentry(hs: "HomeServer") -> None: """Enable sentry integration, if enabled in configuration""" if not hs.config.metrics.sentry_enabled: return import sentry_sdk sentry_sdk.init(dsn=hs.config.metrics.sentry_dsn, release=get_version_string(synapse)) # We set some default tags that give some context to this instance with sentry_sdk.configure_scope() as scope: scope.set_tag("matrix_server_name", hs.config.server.server_name) app = (hs.config.worker.worker_app if hs.config.worker.worker_app else "synapse.app.homeserver") name = hs.get_instance_name() scope.set_tag("worker_app", app) scope.set_tag("worker_name", name)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse frontend proxy", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-frontend-proxy", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse pusher", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" events.USE_FROZEN_DICTS = config.use_frozen_dicts if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True ps = PusherServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), ) setup_logging(ps, config, use_worker_options=True) ps.setup() def start(): _base.start(ps, config.worker_listeners) ps.get_pusherpool().start() reactor.addSystemEventTrigger("before", "startup", start) _base.start_worker_reactor("synapse-pusher", config)
def setup(config_options): try: config = SynchrotronConfig.load_config( "Synapse synchrotron", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) if not config: sys.exit(0) config.setup_logging() database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string=get_version_string("Synapse", synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening() change_resource_limit(ss.config.soft_file_limit) if ss.config.gc_thresholds: ss.set_threshold(*ss.config.gc_thresholds) def start(): ss.get_datastore().start_profiling() ss.replicate() reactor.callWhenRunning(start) return ss
def start(config_options): try: config = HomeServerConfig.load_config("Synapse federation reader", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss = FederationReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-reader", config)
def setup(config_options): try: config = PusherSlaveConfig.load_config( "Synapse pusher", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) if not config: sys.exit(0) config.setup_logging() database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string=get_version_string("Synapse", synapse), database_engine=database_engine, ) ps.setup() ps.start_listening() change_resource_limit(ps.config.soft_file_limit) if ps.config.gc_thresholds: gc.set_threshold(*ps.config.gc_thresholds) def start(): ps.replicate() ps.get_pusherpool().start() ps.get_datastore().start_profiling() reactor.callWhenRunning(start) return ps
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation reader", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ss = FederationReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-reader", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse user directory", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.user_dir" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.update_user_directory: sys.stderr.write( "\nThe update_user_directory must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``update_user_directory: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.update_user_directory = True ss = UserDirectoryServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-user-dir", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse media repository", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = MediaRepositoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.get_handlers() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-media-repository", config)
def setup(config_options): try: config = PusherSlaveConfig.load_config("Synapse pusher", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) if not config: sys.exit(0) config.setup_logging() database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string=get_version_string("Synapse", synapse), database_engine=database_engine, ) ps.setup() ps.start_listening() change_resource_limit(ps.config.soft_file_limit) if ps.config.gc_thresholds: gc.set_threshold(*ps.config.gc_thresholds) def start(): ps.replicate() ps.get_pusherpool().start() ps.get_datastore().start_profiling() reactor.callWhenRunning(start) return ps
def setup_sentry(hs): """Enable sentry integration, if enabled in configuration Args: hs (synapse.server.HomeServer) """ if not hs.config.sentry_enabled: return import sentry_sdk sentry_sdk.init( dsn=hs.config.sentry_dsn, release=get_version_string(synapse), ) # We set some default tags that give some context to this instance with sentry_sdk.configure_scope() as scope: scope.set_tag("matrix_server_name", hs.config.server_name) app = hs.config.worker_app if hs.config.worker_app else "synapse.app.homeserver" name = hs.config.worker_name if hs.config.worker_name else "master" scope.set_tag("worker_app", app) scope.set_tag("worker_name", name)
def setup(config_options): """ Args: config_options_options: The options passed to Synapse. Usually `sys.argv[1:]`. Returns: HomeServer """ try: config = HomeServerConfig.load_or_generate_config( "Synapse Homeserver", config_options, ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) if not config: # If a config isn't returned, and an exception isn't raised, we're just # generating config files and shouldn't try to continue. sys.exit(0) config.setup_logging() # check any extra requirements we have now we have a config check_requirements(config) version_string = get_version_string("Synapse", synapse) logger.info("Server hostname: %s", config.server_name) logger.info("Server version: %s", version_string) events.USE_FROZEN_DICTS = config.use_frozen_dicts tls_server_context_factory = context_factory.ServerContextFactory(config) database_engine = create_engine(config.database_config) config.database_config["args"]["cp_openfun"] = database_engine.on_new_connection hs = SynapseHomeServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, content_addr=config.content_addr, version_string=version_string, database_engine=database_engine, ) logger.info("Preparing database: %s...", config.database_config['name']) try: db_conn = hs.get_db_conn(run_new_connection=False) prepare_database(db_conn, database_engine, config=config) database_engine.on_new_connection(db_conn) hs.run_startup_checks(db_conn, database_engine) db_conn.commit() except UpgradeDatabaseException: sys.stderr.write( "\nFailed to upgrade database.\n" "Have you checked for version specific instructions in" " UPGRADES.rst?\n" ) sys.exit(1) logger.info("Database prepared in %s.", config.database_config['name']) hs.setup() hs.start_listening() def start(): hs.get_pusherpool().start() hs.get_state_handler().start_caching() hs.get_datastore().start_profiling() hs.get_datastore().start_doing_background_updates() hs.get_replication_layer().start_get_pdu_cache() reactor.callWhenRunning(start) return hs
def setup(config_options): """ Args: config_options_options: The options passed to Synapse. Usually `sys.argv[1:]`. Returns: HomeServer """ try: config = HomeServerConfig.load_or_generate_config( "Synapse Homeserver", config_options, ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) if not config: # If a config isn't returned, and an exception isn't raised, we're just # generating config files and shouldn't try to continue. sys.exit(0) synapse.config.logger.setup_logging(config, use_worker_options=False) events.USE_FROZEN_DICTS = config.use_frozen_dicts tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) database_engine = create_engine(config.database_config) config.database_config["args"]["cp_openfun"] = database_engine.on_new_connection hs = SynapseHomeServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) logger.info("Preparing database: %s...", config.database_config['name']) try: with hs.get_db_conn(run_new_connection=False) as db_conn: prepare_database(db_conn, database_engine, config=config) database_engine.on_new_connection(db_conn) hs.run_startup_checks(db_conn, database_engine) db_conn.commit() except UpgradeDatabaseException: sys.stderr.write( "\nFailed to upgrade database.\n" "Have you checked for version specific instructions in" " UPGRADES.rst?\n" ) sys.exit(1) logger.info("Database prepared in %s.", config.database_config['name']) hs.setup() hs.start_listening() def start(): hs.get_pusherpool().start() hs.get_datastore().start_profiling() hs.get_datastore().start_doing_background_updates() reactor.callWhenRunning(start) return hs
def setup(config_options): """ Args: config_options_options: The options passed to Synapse. Usually `sys.argv[1:]`. Returns: HomeServer """ try: config = HomeServerConfig.load_or_generate_config( "Synapse Homeserver", config_options, ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) if not config: # If a config isn't returned, and an exception isn't raised, we're just # generating config files and shouldn't try to continue. sys.exit(0) synapse.config.logger.setup_logging( config, use_worker_options=False ) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) config.database_config["args"]["cp_openfun"] = database_engine.on_new_connection hs = SynapseHomeServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) logger.info("Preparing database: %s...", config.database_config['name']) try: with hs.get_db_conn(run_new_connection=False) as db_conn: prepare_database(db_conn, database_engine, config=config) database_engine.on_new_connection(db_conn) hs.run_startup_checks(db_conn, database_engine) db_conn.commit() except UpgradeDatabaseException: sys.stderr.write( "\nFailed to upgrade database.\n" "Have you checked for version specific instructions in" " UPGRADES.rst?\n" ) sys.exit(1) logger.info("Database prepared in %s.", config.database_config['name']) hs.setup() hs.setup_master() @defer.inlineCallbacks def do_acme(): """ Reprovision an ACME certificate, if it's required. Returns: Deferred[bool]: Whether the cert has been updated. """ acme = hs.get_acme_handler() # Check how long the certificate is active for. cert_days_remaining = hs.config.is_disk_cert_valid( allow_self_signed=False ) # We want to reprovision if cert_days_remaining is None (meaning no # certificate exists), or the days remaining number it returns # is less than our re-registration threshold. provision = False if ( cert_days_remaining is None or cert_days_remaining < hs.config.acme_reprovision_threshold ): provision = True if provision: yield acme.provision_certificate() defer.returnValue(provision) @defer.inlineCallbacks def reprovision_acme(): """ Provision a certificate from ACME, if required, and reload the TLS certificate if it's renewed. """ reprovisioned = yield do_acme() if reprovisioned: _base.refresh_certificate(hs) @defer.inlineCallbacks def start(): try: # Run the ACME provisioning code, if it's enabled. if hs.config.acme_enabled: acme = hs.get_acme_handler() # Start up the webservices which we will respond to ACME # challenges with, and then provision. yield acme.start_listening() yield do_acme() # Check if it needs to be reprovisioned every day. hs.get_clock().looping_call( reprovision_acme, 24 * 60 * 60 * 1000 ) _base.start(hs, config.listeners) hs.get_pusherpool().start() hs.get_datastore().start_doing_background_updates() except Exception: # Print the exception and bail out. print("Error during startup:", file=sys.stderr) # this gives better tracebacks than traceback.print_exc() Failure().printTraceback(file=sys.stderr) if reactor.running: reactor.stop() sys.exit(1) reactor.callWhenRunning(start) return hs
def setup_logging(config, use_worker_options=False): """ Set up python logging Args: config (LoggingConfig | synapse.config.workers.WorkerConfig): configuration data use_worker_options (bool): True to use 'worker_log_config' and 'worker_log_file' options instead of 'log_config' and 'log_file'. """ log_config = (config.worker_log_config if use_worker_options else config.log_config) log_file = (config.worker_log_file if use_worker_options else config.log_file) log_format = ( "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s" " - %(message)s" ) if log_config is None: # We don't have a logfile, so fall back to the 'verbosity' param from # the config or cmdline. (Note that we generate a log config for new # installs, so this will be an unusual case) level = logging.INFO level_for_storage = logging.INFO if config.verbosity: level = logging.DEBUG if config.verbosity > 1: level_for_storage = logging.DEBUG logger = logging.getLogger('') logger.setLevel(level) logging.getLogger('synapse.storage.SQL').setLevel(level_for_storage) formatter = logging.Formatter(log_format) if log_file: # TODO: Customisable file size / backup count handler = logging.handlers.RotatingFileHandler( log_file, maxBytes=(1000 * 1000 * 100), backupCount=3, encoding='utf8' ) def sighup(signum, stack): logger.info("Closing log file due to SIGHUP") handler.doRollover() logger.info("Opened new log file due to SIGHUP") else: handler = logging.StreamHandler() def sighup(signum, stack): pass handler.setFormatter(formatter) handler.addFilter(LoggingContextFilter(request="")) logger.addHandler(handler) else: def load_log_config(): with open(log_config, 'r') as f: logging.config.dictConfig(yaml.load(f)) def sighup(signum, stack): # it might be better to use a file watcher or something for this. load_log_config() logging.info("Reloaded log config from %s due to SIGHUP", log_config) load_log_config() # TODO(paul): obviously this is a terrible mechanism for # stealing SIGHUP, because it means no other part of synapse # can use it instead. If we want to catch SIGHUP anywhere # else as well, I'd suggest we find a nicer way to broadcast # it around. if getattr(signal, "SIGHUP"): signal.signal(signal.SIGHUP, sighup) # make sure that the first thing we log is a thing we can grep backwards # for logging.warn("***** STARTING SERVER *****") logging.warn( "Server %s version %s", sys.argv[0], get_version_string(synapse), ) logging.info("Server hostname: %s", config.server_name) # It's critical to point twisted's internal logging somewhere, otherwise it # stacks up and leaks kup to 64K object; # see: https://twistedmatrix.com/trac/ticket/8164 # # Routing to the python logging framework could be a performance problem if # the handlers blocked for a long time as python.logging is a blocking API # see https://twistedmatrix.com/documents/current/core/howto/logger.html # filed as https://github.com/matrix-org/synapse/issues/1727 # # However this may not be too much of a problem if we are just writing to a file. observer = STDLibLogObserver() def _log(event): if "log_text" in event: if event["log_text"].startswith("DNSDatagramProtocol starting on "): return if event["log_text"].startswith("(UDP Port "): return if event["log_text"].startswith("Timing out client"): return return observer(event) globalLogBeginner.beginLoggingTo( [_log], redirectStandardIO=not config.no_redirect_stdio, )
def __init__(self, hs): self.res = { 'server_version': get_version_string(synapse), 'python_version': platform.python_version(), }
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse pusher", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" setup_logging(config.worker_log_config, config.worker_log_file) if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ps.replicate() ps.get_pusherpool().start() ps.get_datastore().start_profiling() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-pusher", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()