Esempio n. 1
0
        def add_messages_txn(txn, now_ms, stream_id):
            # Add the local messages directly to the local inbox.
            self._add_messages_to_local_device_inbox_txn(
                txn, stream_id, local_messages_by_user_then_device
            )

            # Add the remote messages to the federation outbox.
            # We'll send them to a remote server when we next send a
            # federation transaction to that destination.
            self.db_pool.simple_insert_many_txn(
                txn,
                table="device_federation_outbox",
                values=[
                    {
                        "destination": destination,
                        "stream_id": stream_id,
                        "queued_ts": now_ms,
                        "messages_json": json_encoder.encode(edu),
                        "instance_name": self._instance_name,
                    }
                    for destination, edu in remote_messages_by_destination.items()
                ],
            )

            if remote_messages_by_destination:
                issue9533_logger.debug(
                    "Queued outgoing to-device messages with stream_id %i for %s",
                    stream_id,
                    list(remote_messages_by_destination.keys()),
                )
Esempio n. 2
0
    async def _get_to_device_message_edus(self,
                                          limit: int) -> Tuple[List[Edu], int]:
        last_device_stream_id = self._last_device_stream_id
        to_device_stream_id = self._store.get_to_device_stream_token()
        contents, stream_id = await self._store.get_new_device_msgs_for_remote(
            self._destination, last_device_stream_id, to_device_stream_id,
            limit)
        for content in contents:
            message_id = content.get("message_id")
            if not message_id:
                continue

            set_tag(SynapseTags.TO_DEVICE_MESSAGE_ID, message_id)

        edus = [
            Edu(
                origin=self._server_name,
                destination=self._destination,
                edu_type=EduTypes.DIRECT_TO_DEVICE,
                content=content,
            ) for content in contents
        ]

        if edus:
            issue9533_logger.debug(
                "Sending %i to-device messages to %s, up to stream id %i",
                len(edus),
                self._destination,
                stream_id,
            )

        return edus, stream_id
Esempio n. 3
0
    def on_new_event(
        self,
        stream_key: str,
        new_token: Union[int, RoomStreamToken],
        users: Optional[Collection[Union[str, UserID]]] = None,
        rooms: Optional[Collection[str]] = None,
    ):
        """Used to inform listeners that something has happened event wise.

        Will wake up all listeners for the given users and rooms.
        """
        users = users or []
        rooms = rooms or []

        with Measure(self.clock, "on_new_event"):
            user_streams = set()

            log_kv(
                {
                    "waking_up_explicit_users": len(users),
                    "waking_up_explicit_rooms": len(rooms),
                }
            )

            for user in users:
                user_stream = self.user_to_user_stream.get(str(user))
                if user_stream is not None:
                    user_streams.add(user_stream)

            for room in rooms:
                user_streams |= self.room_to_user_streams.get(room, set())

            if stream_key == "to_device_key":
                issue9533_logger.debug(
                    "to-device messages stream id %s, awaking streams for %s",
                    new_token,
                    users,
                )

            time_now_ms = self.clock.time_msec()
            for user_stream in user_streams:
                try:
                    user_stream.notify(stream_key, new_token, time_now_ms)
                except Exception:
                    logger.exception("Failed to notify listener")

            self.notify_replication()

            # Notify appservices
            self._notify_app_services_ephemeral(
                stream_key,
                new_token,
                users,
            )
Esempio n. 4
0
    def _add_messages_to_local_device_inbox_txn(
        self, txn, stream_id, messages_by_user_then_device
    ):
        assert self._can_write_to_device

        local_by_user_then_device = {}
        for user_id, messages_by_device in messages_by_user_then_device.items():
            messages_json_for_user = {}
            devices = list(messages_by_device.keys())
            if len(devices) == 1 and devices[0] == "*":
                # Handle wildcard device_ids.
                devices = self.db_pool.simple_select_onecol_txn(
                    txn,
                    table="devices",
                    keyvalues={"user_id": user_id},
                    retcol="device_id",
                )

                message_json = json_encoder.encode(messages_by_device["*"])
                for device_id in devices:
                    # Add the message for all devices for this user on this
                    # server.
                    messages_json_for_user[device_id] = message_json
            else:
                if not devices:
                    continue

                rows = self.db_pool.simple_select_many_txn(
                    txn,
                    table="devices",
                    keyvalues={"user_id": user_id},
                    column="device_id",
                    iterable=devices,
                    retcols=("device_id",),
                )

                for row in rows:
                    # Only insert into the local inbox if the device exists on
                    # this server
                    device_id = row["device_id"]
                    message_json = json_encoder.encode(messages_by_device[device_id])
                    messages_json_for_user[device_id] = message_json

            if messages_json_for_user:
                local_by_user_then_device[user_id] = messages_json_for_user

        if not local_by_user_then_device:
            return

        self.db_pool.simple_insert_many_txn(
            txn,
            table="device_inbox",
            values=[
                {
                    "user_id": user_id,
                    "device_id": device_id,
                    "stream_id": stream_id,
                    "message_json": message_json,
                    "instance_name": self._instance_name,
                }
                for user_id, messages_by_device in local_by_user_then_device.items()
                for device_id, message_json in messages_by_device.items()
            ],
        )

        issue9533_logger.debug(
            "Stored to-device messages with stream_id %i for %s",
            stream_id,
            [
                (user_id, device_id)
                for (user_id, messages_by_device) in local_by_user_then_device.items()
                for device_id in messages_by_device.keys()
            ],
        )
Esempio n. 5
0
    def on_new_event(
        self,
        stream_key: str,
        new_token: Union[int, RoomStreamToken],
        users: Optional[Collection[Union[str, UserID]]] = None,
        rooms: Optional[Collection[str]] = None,
    ) -> None:
        """Used to inform listeners that something has happened event wise.

        Will wake up all listeners for the given users and rooms.

        Args:
            stream_key: The stream the event came from.
            new_token: The value of the new stream token.
            users: The users that should be informed of the new event.
            rooms: A collection of room IDs for which each joined member will be
                informed of the new event.
        """
        users = users or []
        rooms = rooms or []

        with Measure(self.clock, "on_new_event"):
            user_streams = set()

            log_kv(
                {
                    "waking_up_explicit_users": len(users),
                    "waking_up_explicit_rooms": len(rooms),
                }
            )

            for user in users:
                user_stream = self.user_to_user_stream.get(str(user))
                if user_stream is not None:
                    user_streams.add(user_stream)

            for room in rooms:
                user_streams |= self.room_to_user_streams.get(room, set())

            if stream_key == "to_device_key":
                issue9533_logger.debug(
                    "to-device messages stream id %s, awaking streams for %s",
                    new_token,
                    users,
                )

            time_now_ms = self.clock.time_msec()
            for user_stream in user_streams:
                try:
                    user_stream.notify(stream_key, new_token, time_now_ms)
                except Exception:
                    logger.exception("Failed to notify listener")

            self.notify_replication()

            # Notify appservices.
            try:
                self.appservice_handler.notify_interested_services_ephemeral(
                    stream_key,
                    new_token,
                    users,
                )
            except Exception:
                logger.exception("Error notifying application services of event")
Esempio n. 6
0
    def _add_messages_to_local_device_inbox_txn(
        self,
        txn: LoggingTransaction,
        stream_id: int,
        messages_by_user_then_device: Dict[str, Dict[str, JsonDict]],
    ) -> None:
        assert self._can_write_to_device

        local_by_user_then_device = {}
        for user_id, messages_by_device in messages_by_user_then_device.items(
        ):
            messages_json_for_user = {}
            devices = list(messages_by_device.keys())
            if len(devices) == 1 and devices[0] == "*":
                # Handle wildcard device_ids.
                # We exclude hidden devices (such as cross-signing keys) here as they are
                # not expected to receive to-device messages.
                devices = self.db_pool.simple_select_onecol_txn(
                    txn,
                    table="devices",
                    keyvalues={
                        "user_id": user_id,
                        "hidden": False
                    },
                    retcol="device_id",
                )

                message_json = json_encoder.encode(messages_by_device["*"])
                for device_id in devices:
                    # Add the message for all devices for this user on this
                    # server.
                    messages_json_for_user[device_id] = message_json
            else:
                if not devices:
                    continue

                # We exclude hidden devices (such as cross-signing keys) here as they are
                # not expected to receive to-device messages.
                rows = self.db_pool.simple_select_many_txn(
                    txn,
                    table="devices",
                    keyvalues={
                        "user_id": user_id,
                        "hidden": False
                    },
                    column="device_id",
                    iterable=devices,
                    retcols=("device_id", ),
                )

                for row in rows:
                    # Only insert into the local inbox if the device exists on
                    # this server
                    device_id = row["device_id"]
                    message_json = json_encoder.encode(
                        messages_by_device[device_id])
                    messages_json_for_user[device_id] = message_json

            if messages_json_for_user:
                local_by_user_then_device[user_id] = messages_json_for_user

        if not local_by_user_then_device:
            return

        self.db_pool.simple_insert_many_txn(
            txn,
            table="device_inbox",
            keys=("user_id", "device_id", "stream_id", "message_json",
                  "instance_name"),
            values=[(user_id, device_id, stream_id, message_json,
                     self._instance_name) for user_id, messages_by_device in
                    local_by_user_then_device.items()
                    for device_id, message_json in messages_by_device.items()],
        )

        issue9533_logger.debug(
            "Stored to-device messages with stream_id %i for %s",
            stream_id,
            [(user_id, device_id)
             for (user_id,
                  messages_by_device) in local_by_user_then_device.items()
             for device_id in messages_by_device.keys()],
        )