def on_transaction_typing(self, transaction_id, event): """Routes typing notifications from Matrix server to the client.""" del transaction_id # Unused. room_id = query_json_path(event, "room_id") if room_id in self.base.rooms and self.base.rooms[room_id].members: user = self.base.rooms[room_id].user typing_user_ids = set(query_json_path(event, "content", "user_ids")) # Note: the implementation assumes 1:1 chat. contact = next(iter(self.base.rooms[room_id].members)) account = self.base.find_account_for_contact(user, contact) if account: conv_id = self.base.rooms[room_id].conv_id # We cannot operate without conv_id as it's required by # the client for sending the typing state. if not conv_id: ext_contact = self.base.mxid_to_ext_contact(account.network, contact) conv_id = account.client.create_conversation( account.network, account.ext_user, ext_contact) self.base.rooms[room_id].conv_id = conv_id if conv_id: # Note: we can get here via feedback loop, that is - when Matrix server # receives our typing notification from the external client, it will send # us the transaction and we'll end up here. We cannot distinguish it from # the "genuine" update for the user and discard, though, so the best we # can do is to send the correct current typing state for the user. account.client.set_typing( account.network, account.ext_user, conv_id, user in typing_user_ids) return logger.info( "Cannot figure out conversation id or account " "for room '{0}', cannot set typing state", room_id) else: logger.info("Room '{0}' is unknown, cannot set typing state", room_id)
def on_transaction_presence(self, transaction_id, event): """Routes user presence changes from Matrix to the client.""" del transaction_id # Unused. user = query_json_path(event, "content", "user_id") presence = query_json_path(event, "content", "presence") if user in self.base.accounts: for account in self.base.accounts[user]: account.client.set_account_status(account.network, account.ext_user, presence)
def _get_joined_members(state): if state and "rooms" in state and "join" in state["rooms"]: for room_id, room_state in state["rooms"]["join"].items(): members = set() events = query_json_path(room_state, "state", "events") if events: for event in events: state_key = query_json_path(event, "state_key") if state_key and query_json_path(event, "content", "membership") == "join": members.add(state_key) yield room_id, members
def process_transaction_message(self, transaction_id, event): """Processes messagereceived from Matrix. Note: this function is not registered directly as a callback but is called from 'ServiceLayer' if it determines the message should be handled as the 'normal' one.""" del transaction_id # Unused. sender = event["sender"] room_id = event["room_id"] payload = query_json_path(event, "content") if sender in self.base.accounts: if event["event_id"] in self.sent_ids: self.sent_ids.remove(event["event_id"]) return if room_id in self.base.rooms: for member in self.base.rooms[room_id].members: self.send_message_to_client(room_id, sender, member, payload) else: # Unknown room_id - potentially we're not currently tracking # the recipient contact, so we cannot determine the exact account to use. # Store message as offline so that once the contact is online and its room state # is fetched - we can deliver the message. self._store_offline_message_to_clients_without_account( room_id, sender, get_event_datetime(event), payload)
def _render_payload_for_client(account, payload): body = query_json_path(payload, "body") fmt = query_json_path(payload, "format") formatted_body = query_json_path(payload, "formatted_body") rendered_body = body if "format" in account.config and fmt and account.config["format"] == fmt: rendered_body = formatted_body else: if "convert_from_text" in account.config: if account.config["convert_from_text"] == "markdown": rendered_body = markdown.markdown(body) else: logger.error( "PuMaDuct misconfiguration: from text converter '{0}'" " for the network '{1}' is unknown.", account.config["convert_from_text"], account.network) return rendered_body
def start(self): self.presence_refresh_cb = self.base.glib.timeout_add_seconds( self.presence_refresh_interval, self.on_presence_refresh) # Determine which users are on our presence list. presence_list = self.base.matrix_client.get_presence_list( self.service.user) for presence in presence_list: user = query_json_path(presence, "content", "user_id") if user is not None: self.presence_list.add(user) # Add to presence list everybody who's not yet on it. for user in self.base.accounts: if user not in self.presence_list: logger.info( "Service {0} doesn't have the presence for user {1}, requesting", self.service.user, user) self.base.matrix_client.add_to_presence_list( user, self.service.user) self.base.matrix_client.set_user_presence(self.service.user, "online")
def test_query_json_path(self): json = {"a": {"b": {"c": 1}}} self.assertEqual(query_json_path(json, "a", "b", "c"), 1) self.assertIsNone(query_json_path(json, "a", "b", "d"))