def test_send_receipts(self): mock_send_transaction = ( self.hs.get_federation_transport_client().send_transaction) mock_send_transaction.return_value = make_awaitable({}) sender = self.hs.get_federation_sender() receipt = ReadReceipt("room_id", "m.read", "user_id", ["event_id"], {"ts": 1234}) self.successResultOf( defer.ensureDeferred(sender.send_read_receipt(receipt))) self.pump() # expect a call to send_transaction mock_send_transaction.assert_called_once() json_cb = mock_send_transaction.call_args[0][1] data = json_cb() self.assertEqual( data["edus"], [{ "edu_type": "m.receipt", "content": { "room_id": { "m.read": { "user_id": { "event_ids": ["event_id"], "data": { "ts": 1234 }, } } } }, }], )
async def _received_remote_receipt(self, origin: str, content: JsonDict) -> None: """Called when we receive an EDU of type m.receipt from a remote HS.""" receipts = [] for room_id, room_values in content.items(): for receipt_type, users in room_values.items(): for user_id, user_values in users.items(): if get_domain_from_id(user_id) != origin: logger.info( "Received receipt for user %r from server %s, ignoring", user_id, origin, ) continue receipts.append( ReadReceipt( room_id=room_id, receipt_type=receipt_type, user_id=user_id, event_ids=user_values["event_ids"], data=user_values.get("data", {}), )) await self._handle_new_receipts(receipts)
def _received_remote_receipt(self, origin, content): """Called when we receive an EDU of type m.receipt from a remote HS. """ receipts = [ ReadReceipt( room_id=room_id, receipt_type=receipt_type, user_id=user_id, event_ids=user_values["event_ids"], data=user_values.get("data", {}), ) for room_id, room_values in content.items() for receipt_type, users in room_values.items() for user_id, user_values in users.items() ] yield self._handle_new_receipts(receipts)
async def received_client_receipt(self, room_id, receipt_type, user_id, event_id): """Called when a client tells us a local user has read up to the given event_id in the room. """ receipt = ReadReceipt( room_id=room_id, receipt_type=receipt_type, user_id=user_id, event_ids=[event_id], data={"ts": int(self.clock.time_msec())}, ) is_new = await self._handle_new_receipts([receipt]) if not is_new: return await self.federation.send_read_receipt(receipt)
def _on_new_receipts(self, rows): """ Args: rows (iterable[synapse.replication.tcp.streams.ReceiptsStreamRow]): new receipts to be processed """ for receipt in rows: # we only want to send on receipts for our own users if not self._is_mine_id(receipt.user_id): continue receipt_info = ReadReceipt( receipt.room_id, receipt.receipt_type, receipt.user_id, [receipt.event_id], receipt.data, ) yield self.federation_sender.send_read_receipt(receipt_info)
async def received_client_receipt(self, room_id: str, receipt_type: str, user_id: str, event_id: str) -> None: """Called when a client tells us a local user has read up to the given event_id in the room. """ receipt = ReadReceipt( room_id=room_id, receipt_type=receipt_type, user_id=user_id, event_ids=[event_id], data={"ts": int(self.clock.time_msec())}, ) is_new = await self._handle_new_receipts([receipt]) if not is_new: return if self.federation_sender and receipt_type != ReceiptTypes.READ_PRIVATE: await self.federation_sender.send_read_receipt(receipt)
async def _on_new_receipts(self, rows): """ Args: rows (Iterable[synapse.replication.tcp.streams.ReceiptsStream.ReceiptsStreamRow]): new receipts to be processed """ for receipt in rows: # we only want to send on receipts for our own users if not self._is_mine_id(receipt.user_id): continue if (receipt.data.get("hidden", False) and self._hs.config.experimental.msc2285_enabled): continue receipt_info = ReadReceipt( receipt.room_id, receipt.receipt_type, receipt.user_id, [receipt.event_id], receipt.data, ) await self.federation_sender.send_read_receipt(receipt_info)
async def _on_new_receipts( self, rows: Iterable[ReceiptsStream.ReceiptsStreamRow]) -> None: """ Args: rows: new receipts to be processed """ for receipt in rows: # we only want to send on receipts for our own users if not self._is_mine_id(receipt.user_id): continue # Private read receipts never get sent over federation. if receipt.receipt_type == ReceiptTypes.READ_PRIVATE: continue receipt_info = ReadReceipt( receipt.room_id, receipt.receipt_type, receipt.user_id, [receipt.event_id], receipt.data, ) await self.federation_sender.send_read_receipt(receipt_info)
async def _received_remote_receipt(self, origin: str, content: JsonDict) -> None: """Called when we receive an EDU of type m.receipt from a remote HS.""" receipts = [] for room_id, room_values in content.items(): # If we're not in the room just ditch the event entirely. This is # probably an old server that has come back and thinks we're still in # the room (or we've been rejoined to the room by a state reset). is_in_room = await self.event_auth_handler.check_host_in_room( room_id, self.server_name ) if not is_in_room: logger.info( "Ignoring receipt for room %r from server %s as we're not in the room", room_id, origin, ) continue for receipt_type, users in room_values.items(): for user_id, user_values in users.items(): if get_domain_from_id(user_id) != origin: logger.info( "Received receipt for user %r from server %s, ignoring", user_id, origin, ) continue receipts.append( ReadReceipt( room_id=room_id, receipt_type=receipt_type, user_id=user_id, event_ids=user_values["event_ids"], data=user_values.get("data", {}), ) ) await self._handle_new_receipts(receipts)
async def received_client_receipt( self, room_id: str, receipt_type: str, user_id: str, event_id: str, hidden: bool ) -> None: """Called when a client tells us a local user has read up to the given event_id in the room. """ receipt = ReadReceipt( room_id=room_id, receipt_type=receipt_type, user_id=user_id, event_ids=[event_id], data={"ts": int(self.clock.time_msec()), "hidden": hidden}, ) is_new = await self._handle_new_receipts([receipt]) if not is_new: return if self.federation_sender and not ( self.hs.config.experimental.msc2285_enabled and hidden ): await self.federation_sender.send_read_receipt(receipt)
def test_send_receipts(self): mock_state_handler = self.hs.get_state_handler() mock_state_handler.get_current_hosts_in_room.return_value = [ "test", "host2" ] mock_send_transaction = ( self.hs.get_federation_transport_client().send_transaction) mock_send_transaction.return_value = defer.succeed({}) sender = self.hs.get_federation_sender() receipt = ReadReceipt("room_id", "m.read", "user_id", ["event_id"], {"ts": 1234}) self.successResultOf(sender.send_read_receipt(receipt)) self.pump() # expect a call to send_transaction mock_send_transaction.assert_called_once() json_cb = mock_send_transaction.call_args[0][1] data = json_cb() self.assertEqual( data['edus'], [{ 'edu_type': 'm.receipt', 'content': { 'room_id': { 'm.read': { 'user_id': { 'event_ids': ['event_id'], 'data': { 'ts': 1234 }, } } } }, }], )
def test_send_receipts_with_backoff(self): """Send two receipts in quick succession; the second should be flushed, but only after 20ms""" mock_send_transaction = ( self.hs.get_federation_transport_client().send_transaction) mock_send_transaction.return_value = make_awaitable({}) sender = self.hs.get_federation_sender() receipt = ReadReceipt("room_id", "m.read", "user_id", ["event_id"], {"ts": 1234}) self.successResultOf( defer.ensureDeferred(sender.send_read_receipt(receipt))) self.pump() # expect a call to send_transaction mock_send_transaction.assert_called_once() json_cb = mock_send_transaction.call_args[0][1] data = json_cb() self.assertEqual( data["edus"], [{ "edu_type": "m.receipt", "content": { "room_id": { "m.read": { "user_id": { "event_ids": ["event_id"], "data": { "ts": 1234 }, } } } }, }], ) mock_send_transaction.reset_mock() # send the second RR receipt = ReadReceipt("room_id", "m.read", "user_id", ["other_id"], {"ts": 1234}) self.successResultOf( defer.ensureDeferred(sender.send_read_receipt(receipt))) self.pump() mock_send_transaction.assert_not_called() self.reactor.advance(19) mock_send_transaction.assert_not_called() self.reactor.advance(10) mock_send_transaction.assert_called_once() json_cb = mock_send_transaction.call_args[0][1] data = json_cb() self.assertEqual( data["edus"], [{ "edu_type": "m.receipt", "content": { "room_id": { "m.read": { "user_id": { "event_ids": ["other_id"], "data": { "ts": 1234 }, } } } }, }], )
def test_send_receipts_with_backoff(self): """Send two receipts in quick succession; the second should be flushed, but only after 20ms""" mock_state_handler = self.hs.get_state_handler() mock_state_handler.get_current_hosts_in_room.return_value = [ "test", "host2" ] mock_send_transaction = ( self.hs.get_federation_transport_client().send_transaction) mock_send_transaction.return_value = defer.succeed({}) sender = self.hs.get_federation_sender() receipt = ReadReceipt("room_id", "m.read", "user_id", ["event_id"], {"ts": 1234}) self.successResultOf(sender.send_read_receipt(receipt)) self.pump() # expect a call to send_transaction mock_send_transaction.assert_called_once() json_cb = mock_send_transaction.call_args[0][1] data = json_cb() self.assertEqual( data['edus'], [{ 'edu_type': 'm.receipt', 'content': { 'room_id': { 'm.read': { 'user_id': { 'event_ids': ['event_id'], 'data': { 'ts': 1234 }, } } } }, }], ) mock_send_transaction.reset_mock() # send the second RR receipt = ReadReceipt("room_id", "m.read", "user_id", ["other_id"], {"ts": 1234}) self.successResultOf(sender.send_read_receipt(receipt)) self.pump() mock_send_transaction.assert_not_called() self.reactor.advance(19) mock_send_transaction.assert_not_called() self.reactor.advance(10) mock_send_transaction.assert_called_once() json_cb = mock_send_transaction.call_args[0][1] data = json_cb() self.assertEqual( data['edus'], [{ 'edu_type': 'm.receipt', 'content': { 'room_id': { 'm.read': { 'user_id': { 'event_ids': ['other_id'], 'data': { 'ts': 1234 }, } } } }, }], )