Esempio n. 1
0
    async def connect(self):
        """Create connection object with chat library."""
        config = nio.AsyncClientConfig(
            nio.ClientConfig(encryption_enabled=False, pickle_key=""))
        mapi = nio.AsyncClient(self.homeserver, self.mxid, config=config)

        login_response = await mapi.login(password=self.password,
                                          device_name=self.device_name)
        if isinstance(login_response, nio.LoginError):
            _LOGGER.error(
                f"Error while connecting: {login_response.message} (status code {login_response.status_code})"
            )
            return

        mapi.token = login_response.access_token
        mapi.sync_token = None

        for roomname, room in self.rooms.items():
            response = await mapi.join(room["alias"])
            if isinstance(response, nio.JoinError):
                _LOGGER.error(
                    f"Error while joining room: {room['alias']}, Message: {response.message} (status code {response.status_code})"
                )

            else:
                self.room_ids[roomname] = response.room_id

        self.connection = mapi

        # Create a filter now, saves time on each later sync
        self.filter_id = await self.make_filter(mapi, self.filter_json)
        first_filter_id = await self.make_filter(
            mapi, '{ "room": { "timeline" : { "limit" : 1 } } }')

        # Do initial sync so we don't get old messages later.
        response = await self.connection.sync(timeout=3000,
                                              sync_filter=first_filter_id)

        if isinstance(response, nio.SyncError):
            _LOGGER.error(
                f"Error during initial sync: {response.message} (status code {response.status_code})"
            )
            return

        self.connection.sync_token = response.next_batch

        if self.nick:
            display_name = await self.connection.get_displayname(self.mxid)
            if display_name != self.nick:
                await self.connection.set_displayname(self.nick)
Esempio n. 2
0
    def __init__(self, config: Config, sync: bool = True):
        self.__client_config = nio.AsyncClientConfig(
            max_limit_exceeded=0,
            max_timeouts=0,
            store_sync_tokens=True,
            encryption_enabled=True,
        )
        self.__config = config
        self.__client = self.__load_client()
        self.__sync_keys()
        self.__sync = None

        if sync:
            self.__sync = self.__sync_state()
Esempio n. 3
0
    def __init__(self,
                 backend,
                 user:       str,
                 homeserver: str           = "https://matrix.org",
                 device_id:  Optional[str] = None) -> None:

        if not urlparse(homeserver).scheme:
            raise ValueError(
                f"homeserver is missing scheme (e.g. https://): {homeserver}",
            )

        store = Path(backend.appdirs.user_data_dir) / "encryption"
        store.mkdir(parents=True, exist_ok=True)

        super().__init__(
            homeserver = homeserver,
            user       = user,
            device_id  = device_id,
            store_path = store,
            config     = nio.AsyncClientConfig(
                max_timeout_retry_wait_time = 10,
                # TODO: pass a custom encryption DB pickle key?
            ),
        )

        self.backend: "Backend"  = backend
        self.models:  ModelStore = self.backend.models

        self.profile_task:       Optional[asyncio.Future] = None
        self.server_config_task: Optional[asyncio.Future] = None
        self.sync_task:          Optional[asyncio.Future] = None
        self.load_rooms_task:    Optional[asyncio.Future] = None

        self.upload_monitors:    Dict[UUID, nio.TransferMonitor] = {}
        self.upload_tasks:       Dict[UUID, asyncio.Task]        = {}
        self.send_message_tasks: Dict[UUID, asyncio.Task]        = {}

        self.first_sync_done: asyncio.Event      = asyncio.Event()
        self.first_sync_date: Optional[datetime] = None

        self.past_tokens:          Dict[str, str] = {}     # {room_id: token}
        self.fully_loaded_rooms:   Set[str]       = set()  # {room_id}
        self.loaded_once_rooms:    Set[str]       = set()  # {room_id}
        self.cleared_events_rooms: Set[str]       = set()  # {room_id}

        self.skipped_events: DefaultDict[str, int] = DefaultDict(lambda: 0)

        self.nio_callbacks = NioCallbacks(self)
Esempio n. 4
0
async def main() -> None:
    config = Config()
    store_path = config.get_store_path()

    if not os.path.exists(store_path):
        os.makedirs(store_path)

    if len(config.get_access_token()) > 0:
        print("Access token already set.")
        sys.exit(1)

    client_config = nio.AsyncClientConfig(
        max_limit_exceeded=0,
        max_timeouts=0,
        store_sync_tokens=True,
        encryption_enabled=True,
    )

    client = nio.AsyncClient(
        homeserver=config.get_home_server(),
        user=config.get_user_id(),
        store_path=config.get_store_path(),
        config=client_config,
        ssl=True
    )

    response = await client.login(
        password=getpass.getpass(),
        device_name=config.get_device_name()
    )
    await client.close()

    if not isinstance(response, nio.LoginResponse):
        print("Failed to get access token.")
        sys.exit(1)

    config.set_access_token(response.access_token)
    config.set_device_id(response.device_id)
    config.save_config()
Esempio n. 5
0
    async def connect(self):
        """Create connection object with chat library."""
        if self._allow_encryption:
            _LOGGER.debug(
                f"Using {self.store_path} for the matrix client store.")
            Path(self.store_path).mkdir(exist_ok=True)

        config = nio.AsyncClientConfig(
            encryption_enabled=self._allow_encryption,
            pickle_key="",
            store_name="opsdroid.db" if self._allow_encryption else "",
        )
        self.connection = nio.AsyncClient(
            self.homeserver,
            self.mxid,
            config=config,
            store_path=self.store_path if self._allow_encryption else "",
            device_id=self.device_id,
        )

        if self.access_token is not None:
            self.connection.access_token = self.access_token

            whoami_response = await self.connection.whoami()
            if isinstance(whoami_response, nio.responses.WhoamiError):
                _LOGGER.error(
                    f"Error while connecting: {whoami_response.message} (status code {whoami_response.status_code})"
                )
                return

            self.mxid = whoami_response.user_id
            self.connection.user_id = self.mxid

        elif self.mxid is not None and self.password is not None:
            login_response = await self.connection.login(
                password=self.password, device_name=self.device_name)
            if isinstance(login_response, nio.LoginError):
                _LOGGER.error(
                    f"Error while connecting: {login_response.message} (status code {login_response.status_code})"
                )
                return

            self.access_token = (
                self.connection.access_token) = login_response.access_token
        else:
            raise ValueError(
                "Configuration for the matrix connector should specify mxid and password or access_token."
            )  # pragma: no cover

        self.connection.sync_token = None

        for roomname, room in self.rooms.items():
            response = await self.connection.join(room["alias"])
            if isinstance(response, nio.JoinError):
                _LOGGER.error(
                    f"Error while joining room: {room['alias']}, Message: {response.message} (status code {response.status_code})"
                )

            else:
                self.room_ids[roomname] = response.room_id

        # Create a filter now, saves time on each later sync
        self.filter_id = await self.make_filter(self.connection,
                                                self.filter_json)
        first_filter_id = await self.make_filter(
            self.connection, '{ "room": { "timeline" : { "limit" : 1 } } }')

        # Do initial sync so we don't get old messages later.
        response = await self.connection.sync(timeout=3000,
                                              sync_filter=first_filter_id,
                                              full_state=True)

        if isinstance(response, nio.SyncError):
            _LOGGER.error(
                f"Error during initial sync: {response.message} (status code {response.status_code})"
            )
            return

        self.connection.sync_token = response.next_batch

        await self.exchange_keys(initial_sync=True)

        if self.nick:
            display_name = await self.connection.get_displayname(self.mxid)
            if isinstance(display_name, nio.ErrorResponse):
                _LOGGER.warning(
                    f"Error fetching current display_name: {display_name.message} (status code {display_name.status_code})"
                )
                display_name = None
            else:
                display_name = display_name.displayname

            if display_name != self.nick:
                display_name_resp = await self.connection.set_displayname(
                    self.nick)
                if isinstance(display_name_resp, nio.ErrorResponse):
                    _LOGGER.warning(
                        f"Error setting display_name: {display_name_resp.message} (status code {display_name_resp.status_code})"
                    )
Esempio n. 6
0
    async def connect(self):
        """Create connection object with chat library."""

        if self._allow_encryption:
            _LOGGER.debug(f"Using {self.store_path} for the matrix client store.")
            Path(self.store_path).mkdir(exist_ok=True)

        config = nio.AsyncClientConfig(
            encryption_enabled=self._allow_encryption,
            pickle_key="",
            store_name="opsdroid.db" if self._allow_encryption else "",
        )
        mapi = nio.AsyncClient(
            self.homeserver,
            self.mxid,
            config=config,
            store_path=self.store_path if self._allow_encryption else "",
            device_id=self.device_id,
        )

        login_response = await mapi.login(
            password=self.password, device_name=self.device_name
        )
        if isinstance(login_response, nio.LoginError):
            _LOGGER.error(
                f"Error while connecting: {login_response.message} (status code {login_response.status_code})"
            )
            return

        mapi.token = login_response.access_token
        mapi.sync_token = None

        for roomname, room in self.rooms.items():
            response = await mapi.join(room["alias"])
            if isinstance(response, nio.JoinError):
                _LOGGER.error(
                    f"Error while joining room: {room['alias']}, Message: {response.message} (status code {response.status_code})"
                )

            else:
                self.room_ids[roomname] = response.room_id

        self.connection = mapi

        # Create a filter now, saves time on each later sync
        self.filter_id = await self.make_filter(mapi, self.filter_json)
        first_filter_id = await self.make_filter(
            mapi, '{ "room": { "timeline" : { "limit" : 1 } } }'
        )

        # Do initial sync so we don't get old messages later.
        response = await self.connection.sync(
            timeout=3000, sync_filter=first_filter_id, full_state=True
        )

        if isinstance(response, nio.SyncError):
            _LOGGER.error(
                f"Error during initial sync: {response.message} (status code {response.status_code})"
            )
            return

        self.connection.sync_token = response.next_batch

        await self.exchange_keys(initial_sync=True)

        if self.nick:
            display_name = await self.connection.get_displayname(self.mxid)
            if display_name != self.nick:
                await self.connection.set_displayname(self.nick)