async def main(client: nio.AsyncClient): # Set up event callbacks callbacks = Callbacks(client) client.add_to_device_callback(callbacks.to_device_callback, (nio.KeyVerificationEvent, )) # Sync encryption keys with the server # Required for participating in encrypted rooms if client.should_upload_keys: await client.keys_upload() print("This program is ready and waiting for the other party to initiate " 'an emoji verification with us by selecting "Verify by Emoji" ' "in their Matrix client.") await client.sync_forever(timeout=30000, full_state=True)
async def main(config: Config): # Configure the database store = Storage(config.database) # Configuration options for the AsyncClient client_config = AsyncClientConfig( max_limit_exceeded=0, max_timeouts=0, store_sync_tokens=True, encryption_enabled=True, ) # Initialize the matrix client client = AsyncClient( config.homeserver_url, config.user_id, device_id=config.device_id, store_path=config.store_path, config=client_config, ) if config.user_token: client.access_token = config.user_token client.user_id = config.user_id # Set up event callbacks callbacks = Callbacks(client, store, config) # noinspection PyTypeChecker client.add_event_callback(callbacks.member, (RoomMemberEvent, )) # noinspection PyTypeChecker client.add_event_callback( callbacks.message, (RoomMessageText, RoomMessageNotice, RoomMessageFormatted)) # noinspection PyTypeChecker client.add_event_callback(callbacks.invite, (InviteMemberEvent, )) # noinspection PyTypeChecker client.add_event_callback(callbacks.decryption_failure, (MegolmEvent, )) # noinspection PyTypeChecker client.add_to_device_callback(callbacks.room_key, (ForwardedRoomKeyEvent, RoomKeyEvent)) # Keep trying to reconnect on failure (with some time in-between) while True: try: if config.user_token: # Use token to log in client.load_store() # Sync encryption keys with the server if client.should_upload_keys: await client.keys_upload() else: # Try to login with the configured username/password try: login_response = await client.login( password=config.user_password, device_name=config.device_name, ) # Check if login failed if type(login_response) == LoginError: logger.error("Failed to login: %s", login_response.message) break except LocalProtocolError as e: # There's an edge case here where the user hasn't installed the correct C # dependencies. In that case, a LocalProtocolError is raised on login. logger.fatal( "Failed to login. Have you installed the correct dependencies? " "https://github.com/poljar/matrix-nio#installation " "Error: %s", e, ) break # Login succeeded! # Join the management room or fail response = await client.join(config.management_room) if type(response) == JoinError: logger.fatal("Could not join the management room, aborting.") break else: logger.info(f"Management room membership is good") # Resolve management room ID if not known if config.management_room.startswith('#'): # Resolve the room ID response = await client.room_resolve_alias( config.management_room) if type(response) == RoomResolveAliasResponse: config.management_room_id = response.room_id else: logger.fatal( "Could not resolve the management room ID from alias, aborting" ) break # Try join the logging room if configured if config.matrix_logging_room and config.matrix_logging_room != config.management_room_id: response = await client.join(config.matrix_logging_room) if type(response) == JoinError: logger.warning("Could not join the logging room") else: logger.info(f"Logging room membership is good") logger.info(f"Logged in as {config.user_id}") await client.sync_forever(timeout=30000, full_state=True) except (ClientConnectionError, ServerDisconnectedError): logger.warning( "Unable to connect to homeserver, retrying in 15s...") # Sleep so we don't bombard the server with login requests sleep(15) finally: # Make sure to close the client connection on disconnect await client.close()
async def main(): # noqa """Create bot as Matrix client and enter event loop.""" # Read config file # A different config file path can be specified # as the first command line argument if len(sys.argv) > 1: config_filepath = sys.argv[1] else: config_filepath = "config.yaml" config = Config(config_filepath) # Configure the database store = Storage(config.database_filepath) # Configuration options for the AsyncClient client_config = AsyncClientConfig( max_limit_exceeded=0, max_timeouts=0, store_sync_tokens=True, encryption_enabled=True, ) # Initialize the matrix client client = AsyncClient( config.homeserver_url, config.user_id, device_id=config.device_id, store_path=config.store_filepath, config=client_config, ) # Set up event callbacks callbacks = Callbacks(client, store, config) client.add_event_callback(callbacks.message, (RoomMessageText, )) client.add_event_callback(callbacks.invite, (InviteMemberEvent, )) client.add_to_device_callback(callbacks.accept_all_verify, (KeyVerificationEvent, )) # Keep trying to reconnect on failure (with some time in-between) while True: try: # Try to login with the configured username/password try: if config.access_token: logger.debug("Using access token from config file to log " f"in. access_token={config.access_token}") client.restore_login(user_id=config.user_id, device_id=config.device_id, access_token=config.access_token) else: logger.debug("Using password from config file to log in.") login_response = await client.login( password=config.user_password, device_name=config.device_name, ) # Check if login failed if type(login_response) == LoginError: logger.error("Failed to login: "******"{login_response.message}") return False logger.info((f"access_token of device {config.device_name}" f" is: \"{login_response.access_token}\"")) except LocalProtocolError as e: # There's an edge case here where the user hasn't installed # the correct C dependencies. In that case, a # LocalProtocolError is raised on login. logger.fatal( "Failed to login. " "Have you installed the correct dependencies? " "Error: %s", e) return False # Login succeeded! logger.debug(f"Logged in successfully as user {config.user_id} " f"with device {config.device_id}.") # Sync encryption keys with the server # Required for participating in encrypted rooms if client.should_upload_keys: await client.keys_upload() if config.change_device_name: content = {"display_name": config.device_name} resp = await client.update_device(config.device_id, content) if isinstance(resp, UpdateDeviceError): logger.debug(f"update_device failed with {resp}") else: logger.debug(f"update_device successful with {resp}") await client.sync(timeout=30000, full_state=True) for device_id, olm_device in client.device_store[ config.user_id].items(): logger.info("Setting up trust for my own " f"device {device_id} and session key " f"{olm_device.keys}.") client.verify_device(olm_device) await client.sync_forever(timeout=30000, full_state=True) except (ClientConnectionError, ServerDisconnectedError): logger.warning( "Unable to connect to homeserver, retrying in 15s...") # Sleep so we don't bombard the server with login requests sleep(15) finally: # Make sure to close the client connection on disconnect await client.close()
async def main_verify() -> None: global client # Read config file config = Config("config.yaml") # Configure the database store = Storage(config.database_filepath) # Configuration options for the AsyncClient client_config = AsyncClientConfig( max_limit_exceeded=0, max_timeouts=0, store_sync_tokens=True, encryption_enabled=config.enable_encryption, ) # Initialize the matrix client client = AsyncClient(config.homeserver_url, config.user_id, device_id=config.device_id, store_path=config.store_filepath, config=client_config, ssl=config.ssl) # Set up event callbacks callbacks = Callbacks(client, store, config) client.add_to_device_callback(callbacks.to_device_callback, (KeyVerificationEvent, )) # Keep trying to reconnect on failure (with some time in-between) error_retries: int = 0 while True: try: # Try to login with the configured username/password try: login_response = await client.login( password=config.user_password, device_name=config.device_name, ) # Check if login failed if type(login_response) == LoginError: logger.error( f"Failed to login: {login_response.message}, retrying in 15s... ({error_retries})" ) # try logging in a few times to work around temporary login errors during homeserver restarts if error_retries < 3: error_retries += 1 await sleep(15) continue else: return False else: error_retries = 0 except LocalProtocolError as e: # There's an edge case here where the user enables encryption but hasn't installed # the correct C dependencies. In that case, a LocalProtocolError is raised on login. # Warn the user if these conditions are met. if config.enable_encryption: logger.fatal( "Failed to login and encryption is enabled. Have you installed the correct dependencies? " "https://github.com/poljar/matrix-nio#installation") return False else: # We don't know why this was raised. Throw it at the user logger.fatal(f"Error logging in: {e}") # Login succeeded! # Sync encryption keys with the server # Required for participating in encrypted rooms if client.should_upload_keys: await client.keys_upload() logger.info(f"Logged in as {config.user_id}") await client.sync_forever(timeout=30000, full_state=True) except (ClientConnectionError, ServerDisconnectedError, AttributeError, asyncio.TimeoutError) as err: logger.debug(err) logger.warning( f"Unable to connect to homeserver, retrying in 15s...") # Sleep so we don't bombard the server with login requests await sleep(15) finally: # Make sure to close the client connection on disconnect await client.close()