We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Matrix Connector should not log HTML page contents on a 504
If the matrix server responds with a 504 error on `/sync` (which is pretty common) the connector should not log the whole HTML page, as it clutters the log.

This is *especially* true on a matrix.org account as you get a whole cloudflare error page.
Matrix Connector should not log HTML page contents on a 504
If the matrix server responds with a 504 error on `/sync` (which is pretty common) the connector should not log the whole HTML page, as it clutters the log.

This is *especially* true on a matrix.org account as you get a whole cloudflare error page.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `opsdroid/connector/matrix/connector.py`
Content:
```
1 """Connector for Matrix (https://matrix.org)."""
2 
3 import re
4 import logging
5 from concurrent.futures import CancelledError
6 
7 import aiohttp
8 
9 from matrix_api_async.api_asyncio import AsyncHTTPAPI
10 from matrix_client.errors import MatrixRequestError
11 
12 from opsdroid.connector import Connector, register_event
13 from opsdroid.events import Message
14 
15 from .html_cleaner import clean
16 
17 
18 _LOGGER = logging.getLogger(__name__)
19 
20 __all__ = ['ConnectorMatrix']
21 
22 
23 class ConnectorMatrix(Connector):
24     """Connector for Matrix (https://matrix.org)."""
25 
26     def __init__(self, config, opsdroid=None):  # noqa: D107
27         """Init the config for the connector."""
28         super().__init__(config, opsdroid=opsdroid)
29 
30         self.name = "ConnectorMatrix"  # The name of your connector
31         self.rooms = config.get('rooms', None)
32         if not self.rooms:
33             self.rooms = {'main': config['room']}
34         self.room_ids = {}
35         self.default_target = self.rooms['main']
36         self.mxid = config['mxid']
37         self.nick = config.get('nick', None)
38         self.homeserver = config.get('homeserver', "https://matrix.org")
39         self.password = config['password']
40         self.room_specific_nicks = config.get("room_specific_nicks", False)
41         self.session = None
42         self.filter_id = None
43         self.connection = None
44 
45     @property
46     def filter_json(self):
47         """Define JSON filter to apply to incoming events."""
48         return {
49             "event_format": "client",
50             "account_data": {
51                 "limit": 0,
52                 "types": []
53             },
54             "presence": {
55                 "limit": 0,
56                 "types": []
57             },
58             "room": {
59                 "rooms": [],
60                 "account_data": {
61                     "types": []
62                 },
63                 "timeline": {
64                     "types": ["m.room.message"]
65                 },
66                 "ephemeral": {
67                     "types": []
68                 },
69                 "state": {
70                     "types": []
71                 }
72             }
73         }
74 
75     async def make_filter(self, api, room_ids):
76         """Make a filter on the server for future syncs."""
77         fjson = self.filter_json
78         for room_id in room_ids:
79             fjson['room']['rooms'].append(room_id)
80 
81         resp = await api.create_filter(
82             user_id=self.mxid, filter_params=fjson)
83 
84         return resp['filter_id']
85 
86     async def connect(self):
87         """Create connection object with chat library."""
88         session = aiohttp.ClientSession()
89         mapi = AsyncHTTPAPI(self.homeserver, session)
90 
91         self.session = session
92         login_response = await mapi.login(
93             "m.login.password", user=self.mxid, password=self.password)
94         mapi.token = login_response['access_token']
95         mapi.sync_token = None
96 
97         for roomname, room in self.rooms.items():
98             response = await mapi.join_room(room)
99             self.room_ids[roomname] = response['room_id']
100         self.connection = mapi
101 
102         # Create a filter now, saves time on each later sync
103         self.filter_id = await self.make_filter(mapi, self.room_ids.values())
104 
105         # Do initial sync so we don't get old messages later.
106         response = await self.connection.sync(
107             timeout_ms=3000,
108             filter='{ "room": { "timeline" : { "limit" : 1 } } }',
109             set_presence="online")
110         self.connection.sync_token = response["next_batch"]
111 
112         if self.nick:
113             display_name = await self.connection.get_display_name(self.mxid)
114             if display_name != self.nick:
115                 await self.connection.set_display_name(self.mxid, self.nick)
116 
117     async def _parse_sync_response(self, response):
118         self.connection.sync_token = response["next_batch"]
119         for roomid in self.room_ids.values():
120             room = response['rooms']['join'].get(roomid, None)
121             if room and 'timeline' in room:
122                 for event in room['timeline']['events']:
123                     if event['content']['msgtype'] == 'm.text':
124                         if event['sender'] != self.mxid:
125                             return Message(
126                                 event['content']['body'],
127                                 await self._get_nick(roomid, event['sender']),
128                                 roomid,
129                                 self,
130                                 event_id=event['event_id'],
131                                 raw_event=event)
132 
133     async def listen(self):  # pragma: no cover
134         """Listen for new messages from the chat service."""
135         while True:  # pylint: disable=R1702
136             try:
137                 response = await self.connection.sync(
138                     self.connection.sync_token,
139                     timeout_ms=int(6 * 60 * 60 * 1e3),  # 6h in ms
140                     filter=self.filter_id)
141                 _LOGGER.debug("matrix sync request returned")
142                 message = await self._parse_sync_response(response)
143                 await self.opsdroid.parse(message)
144 
145             except CancelledError:
146                 raise
147             except Exception:  # pylint: disable=W0703
148                 _LOGGER.exception('Matrix Sync Error')
149 
150     async def _get_nick(self, roomid, mxid):
151         """
152         Get nickname from user ID.
153 
154         Get the nickname of a sender depending on the room specific config
155         setting.
156         """
157         if self.room_specific_nicks:
158             try:
159                 return await self.connection.get_room_displayname(roomid, mxid)
160             except Exception:  # pylint: disable=W0703
161                 # Fallback to the non-room specific one
162                 logging.exception(
163                     "Failed to lookup room specific nick for %s", mxid)
164 
165         try:
166             return await self.connection.get_display_name(mxid)
167         except MatrixRequestError as mre:
168             # Log the error if it's not the 404 from the user not having a nick
169             if mre.code != 404:
170                 logging.exception("Failed to lookup nick for %s", mxid)
171             return mxid
172 
173     @staticmethod
174     def _get_formatted_message_body(message, body=None, msgtype="m.text"):
175         """
176         Get HTML from a message.
177 
178         Return the json representation of the message in
179         "org.matrix.custom.html" format.
180         """
181         # Markdown leaves a <p></p> around standard messages that we want to
182         # strip:
183         if message.startswith('<p>'):
184             message = message[3:]
185             if message.endswith('</p>'):
186                 message = message[:-4]
187 
188         clean_html = clean(message)
189 
190         return {
191             # Strip out any tags from the markdown to make the body
192             "body": body if body else re.sub('<[^<]+?>', '', clean_html),
193             "msgtype": msgtype,
194             "format": "org.matrix.custom.html",
195             "formatted_body": clean_html
196             }
197 
198     @register_event(Message)
199     async def send_message(self, message):
200         """Send `message.text` back to the chat service."""
201         if not message.target.startswith(("!", "#")):
202             room_id = self.rooms[message.target]
203         else:
204             room_id = message.target
205 
206         # Ensure we have a room id not alias
207         if not room_id.startswith('!'):
208             room_id = await self.connection.get_room_id(room_id)
209         else:
210             room_id = room_id
211 
212         try:
213             await self.connection.send_message_event(
214                 room_id,
215                 "m.room.message",
216                 self._get_formatted_message_body(message.text))
217         except aiohttp.client_exceptions.ServerDisconnectedError:
218             _LOGGER.debug("Server had disconnected, retrying send.")
219             await self.connection.send_message_event(
220                 room_id,
221                 "m.room.message",
222                 self._get_formatted_message_body(message.text))
223 
224     async def disconnect(self):
225         """Close the matrix session."""
226         await self.session.close()
227 
228     def get_roomname(self, room):
229         """Get the name of a room from alias or room ID."""
230         if room.startswith(('#', '!')):
231             for connroom in self.rooms:
232                 if room in (connroom, self.room_ids[connroom]):
233                     return connroom
234 
235         return room
236
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/opsdroid/connector/matrix/connector.py b/opsdroid/connector/matrix/connector.py
--- a/opsdroid/connector/matrix/connector.py
+++ b/opsdroid/connector/matrix/connector.py
@@ -142,6 +142,14 @@
                 message = await self._parse_sync_response(response)
                 await self.opsdroid.parse(message)
 
+            except MatrixRequestError as mre:
+                # We can safely ignore timeout errors. The non-standard error
+                # codes are returned by Cloudflare.
+                if mre.code in [504, 522, 524]:
+                    _LOGGER.info('Matrix Sync Timeout (code: %d)', mre.code)
+                    continue
+
+                _LOGGER.exception('Matrix Sync Error')
             except CancelledError:
                 raise
             except Exception:  # pylint: disable=W0703

{"golden_diff": "diff --git a/opsdroid/connector/matrix/connector.py b/opsdroid/connector/matrix/connector.py\n--- a/opsdroid/connector/matrix/connector.py\n+++ b/opsdroid/connector/matrix/connector.py\n@@ -142,6 +142,14 @@\n                 message = await self._parse_sync_response(response)\n                 await self.opsdroid.parse(message)\n \n+            except MatrixRequestError as mre:\n+                # We can safely ignore timeout errors. The non-standard error\n+                # codes are returned by Cloudflare.\n+                if mre.code in [504, 522, 524]:\n+                    _LOGGER.info('Matrix Sync Timeout (code: %d)', mre.code)\n+                    continue\n+\n+                _LOGGER.exception('Matrix Sync Error')\n             except CancelledError:\n                 raise\n             except Exception:  # pylint: disable=W0703\n", "issue": "Matrix Connector should not log HTML page contents on a 504\nIf the matrix server responds with a 504 error on `/sync` (which is pretty common) the connector should not log the whole HTML page, as it clutters the log.\r\n\r\nThis is *especially* true on a matrix.org account as you get a whole cloudflare error page.\nMatrix Connector should not log HTML page contents on a 504\nIf the matrix server responds with a 504 error on `/sync` (which is pretty common) the connector should not log the whole HTML page, as it clutters the log.\r\n\r\nThis is *especially* true on a matrix.org account as you get a whole cloudflare error page.\n", "before_files": [{"content": "\"\"\"Connector for Matrix (https://matrix.org).\"\"\"\n\nimport re\nimport logging\nfrom concurrent.futures import CancelledError\n\nimport aiohttp\n\nfrom matrix_api_async.api_asyncio import AsyncHTTPAPI\nfrom matrix_client.errors import MatrixRequestError\n\nfrom opsdroid.connector import Connector, register_event\nfrom opsdroid.events import Message\n\nfrom .html_cleaner import clean\n\n\n_LOGGER = logging.getLogger(__name__)\n\n__all__ = ['ConnectorMatrix']\n\n\nclass ConnectorMatrix(Connector):\n    \"\"\"Connector for Matrix (https://matrix.org).\"\"\"\n\n    def __init__(self, config, opsdroid=None):  # noqa: D107\n        \"\"\"Init the config for the connector.\"\"\"\n        super().__init__(config, opsdroid=opsdroid)\n\n        self.name = \"ConnectorMatrix\"  # The name of your connector\n        self.rooms = config.get('rooms', None)\n        if not self.rooms:\n            self.rooms = {'main': config['room']}\n        self.room_ids = {}\n        self.default_target = self.rooms['main']\n        self.mxid = config['mxid']\n        self.nick = config.get('nick', None)\n        self.homeserver = config.get('homeserver', \"https://matrix.org\")\n        self.password = config['password']\n        self.room_specific_nicks = config.get(\"room_specific_nicks\", False)\n        self.session = None\n        self.filter_id = None\n        self.connection = None\n\n    @property\n    def filter_json(self):\n        \"\"\"Define JSON filter to apply to incoming events.\"\"\"\n        return {\n            \"event_format\": \"client\",\n            \"account_data\": {\n                \"limit\": 0,\n                \"types\": []\n            },\n            \"presence\": {\n                \"limit\": 0,\n                \"types\": []\n            },\n            \"room\": {\n                \"rooms\": [],\n                \"account_data\": {\n                    \"types\": []\n                },\n                \"timeline\": {\n                    \"types\": [\"m.room.message\"]\n                },\n                \"ephemeral\": {\n                    \"types\": []\n                },\n                \"state\": {\n                    \"types\": []\n                }\n            }\n        }\n\n    async def make_filter(self, api, room_ids):\n        \"\"\"Make a filter on the server for future syncs.\"\"\"\n        fjson = self.filter_json\n        for room_id in room_ids:\n            fjson['room']['rooms'].append(room_id)\n\n        resp = await api.create_filter(\n            user_id=self.mxid, filter_params=fjson)\n\n        return resp['filter_id']\n\n    async def connect(self):\n        \"\"\"Create connection object with chat library.\"\"\"\n        session = aiohttp.ClientSession()\n        mapi = AsyncHTTPAPI(self.homeserver, session)\n\n        self.session = session\n        login_response = await mapi.login(\n            \"m.login.password\", user=self.mxid, password=self.password)\n        mapi.token = login_response['access_token']\n        mapi.sync_token = None\n\n        for roomname, room in self.rooms.items():\n            response = await mapi.join_room(room)\n            self.room_ids[roomname] = response['room_id']\n        self.connection = mapi\n\n        # Create a filter now, saves time on each later sync\n        self.filter_id = await self.make_filter(mapi, self.room_ids.values())\n\n        # Do initial sync so we don't get old messages later.\n        response = await self.connection.sync(\n            timeout_ms=3000,\n            filter='{ \"room\": { \"timeline\" : { \"limit\" : 1 } } }',\n            set_presence=\"online\")\n        self.connection.sync_token = response[\"next_batch\"]\n\n        if self.nick:\n            display_name = await self.connection.get_display_name(self.mxid)\n            if display_name != self.nick:\n                await self.connection.set_display_name(self.mxid, self.nick)\n\n    async def _parse_sync_response(self, response):\n        self.connection.sync_token = response[\"next_batch\"]\n        for roomid in self.room_ids.values():\n            room = response['rooms']['join'].get(roomid, None)\n            if room and 'timeline' in room:\n                for event in room['timeline']['events']:\n                    if event['content']['msgtype'] == 'm.text':\n                        if event['sender'] != self.mxid:\n                            return Message(\n                                event['content']['body'],\n                                await self._get_nick(roomid, event['sender']),\n                                roomid,\n                                self,\n                                event_id=event['event_id'],\n                                raw_event=event)\n\n    async def listen(self):  # pragma: no cover\n        \"\"\"Listen for new messages from the chat service.\"\"\"\n        while True:  # pylint: disable=R1702\n            try:\n                response = await self.connection.sync(\n                    self.connection.sync_token,\n                    timeout_ms=int(6 * 60 * 60 * 1e3),  # 6h in ms\n                    filter=self.filter_id)\n                _LOGGER.debug(\"matrix sync request returned\")\n                message = await self._parse_sync_response(response)\n                await self.opsdroid.parse(message)\n\n            except CancelledError:\n                raise\n            except Exception:  # pylint: disable=W0703\n                _LOGGER.exception('Matrix Sync Error')\n\n    async def _get_nick(self, roomid, mxid):\n        \"\"\"\n        Get nickname from user ID.\n\n        Get the nickname of a sender depending on the room specific config\n        setting.\n        \"\"\"\n        if self.room_specific_nicks:\n            try:\n                return await self.connection.get_room_displayname(roomid, mxid)\n            except Exception:  # pylint: disable=W0703\n                # Fallback to the non-room specific one\n                logging.exception(\n                    \"Failed to lookup room specific nick for %s\", mxid)\n\n        try:\n            return await self.connection.get_display_name(mxid)\n        except MatrixRequestError as mre:\n            # Log the error if it's not the 404 from the user not having a nick\n            if mre.code != 404:\n                logging.exception(\"Failed to lookup nick for %s\", mxid)\n            return mxid\n\n    @staticmethod\n    def _get_formatted_message_body(message, body=None, msgtype=\"m.text\"):\n        \"\"\"\n        Get HTML from a message.\n\n        Return the json representation of the message in\n        \"org.matrix.custom.html\" format.\n        \"\"\"\n        # Markdown leaves a <p></p> around standard messages that we want to\n        # strip:\n        if message.startswith('<p>'):\n            message = message[3:]\n            if message.endswith('</p>'):\n                message = message[:-4]\n\n        clean_html = clean(message)\n\n        return {\n            # Strip out any tags from the markdown to make the body\n            \"body\": body if body else re.sub('<[^<]+?>', '', clean_html),\n            \"msgtype\": msgtype,\n            \"format\": \"org.matrix.custom.html\",\n            \"formatted_body\": clean_html\n            }\n\n    @register_event(Message)\n    async def send_message(self, message):\n        \"\"\"Send `message.text` back to the chat service.\"\"\"\n        if not message.target.startswith((\"!\", \"#\")):\n            room_id = self.rooms[message.target]\n        else:\n            room_id = message.target\n\n        # Ensure we have a room id not alias\n        if not room_id.startswith('!'):\n            room_id = await self.connection.get_room_id(room_id)\n        else:\n            room_id = room_id\n\n        try:\n            await self.connection.send_message_event(\n                room_id,\n                \"m.room.message\",\n                self._get_formatted_message_body(message.text))\n        except aiohttp.client_exceptions.ServerDisconnectedError:\n            _LOGGER.debug(\"Server had disconnected, retrying send.\")\n            await self.connection.send_message_event(\n                room_id,\n                \"m.room.message\",\n                self._get_formatted_message_body(message.text))\n\n    async def disconnect(self):\n        \"\"\"Close the matrix session.\"\"\"\n        await self.session.close()\n\n    def get_roomname(self, room):\n        \"\"\"Get the name of a room from alias or room ID.\"\"\"\n        if room.startswith(('#', '!')):\n            for connroom in self.rooms:\n                if room in (connroom, self.room_ids[connroom]):\n                    return connroom\n\n        return room\n", "path": "opsdroid/connector/matrix/connector.py"}], "after_files": [{"content": "\"\"\"Connector for Matrix (https://matrix.org).\"\"\"\n\nimport re\nimport logging\nfrom concurrent.futures import CancelledError\n\nimport aiohttp\n\nfrom matrix_api_async.api_asyncio import AsyncHTTPAPI\nfrom matrix_client.errors import MatrixRequestError\n\nfrom opsdroid.connector import Connector, register_event\nfrom opsdroid.events import Message\n\nfrom .html_cleaner import clean\n\n\n_LOGGER = logging.getLogger(__name__)\n\n__all__ = ['ConnectorMatrix']\n\n\nclass ConnectorMatrix(Connector):\n    \"\"\"Connector for Matrix (https://matrix.org).\"\"\"\n\n    def __init__(self, config, opsdroid=None):  # noqa: D107\n        \"\"\"Init the config for the connector.\"\"\"\n        super().__init__(config, opsdroid=opsdroid)\n\n        self.name = \"ConnectorMatrix\"  # The name of your connector\n        self.rooms = config.get('rooms', None)\n        if not self.rooms:\n            self.rooms = {'main': config['room']}\n        self.room_ids = {}\n        self.default_target = self.rooms['main']\n        self.mxid = config['mxid']\n        self.nick = config.get('nick', None)\n        self.homeserver = config.get('homeserver', \"https://matrix.org\")\n        self.password = config['password']\n        self.room_specific_nicks = config.get(\"room_specific_nicks\", False)\n        self.session = None\n        self.filter_id = None\n        self.connection = None\n\n    @property\n    def filter_json(self):\n        \"\"\"Define JSON filter to apply to incoming events.\"\"\"\n        return {\n            \"event_format\": \"client\",\n            \"account_data\": {\n                \"limit\": 0,\n                \"types\": []\n            },\n            \"presence\": {\n                \"limit\": 0,\n                \"types\": []\n            },\n            \"room\": {\n                \"rooms\": [],\n                \"account_data\": {\n                    \"types\": []\n                },\n                \"timeline\": {\n                    \"types\": [\"m.room.message\"]\n                },\n                \"ephemeral\": {\n                    \"types\": []\n                },\n                \"state\": {\n                    \"types\": []\n                }\n            }\n        }\n\n    async def make_filter(self, api, room_ids):\n        \"\"\"Make a filter on the server for future syncs.\"\"\"\n        fjson = self.filter_json\n        for room_id in room_ids:\n            fjson['room']['rooms'].append(room_id)\n\n        resp = await api.create_filter(\n            user_id=self.mxid, filter_params=fjson)\n\n        return resp['filter_id']\n\n    async def connect(self):\n        \"\"\"Create connection object with chat library.\"\"\"\n        session = aiohttp.ClientSession()\n        mapi = AsyncHTTPAPI(self.homeserver, session)\n\n        self.session = session\n        login_response = await mapi.login(\n            \"m.login.password\", user=self.mxid, password=self.password)\n        mapi.token = login_response['access_token']\n        mapi.sync_token = None\n\n        for roomname, room in self.rooms.items():\n            response = await mapi.join_room(room)\n            self.room_ids[roomname] = response['room_id']\n        self.connection = mapi\n\n        # Create a filter now, saves time on each later sync\n        self.filter_id = await self.make_filter(mapi, self.room_ids.values())\n\n        # Do initial sync so we don't get old messages later.\n        response = await self.connection.sync(\n            timeout_ms=3000,\n            filter='{ \"room\": { \"timeline\" : { \"limit\" : 1 } } }',\n            set_presence=\"online\")\n        self.connection.sync_token = response[\"next_batch\"]\n\n        if self.nick:\n            display_name = await self.connection.get_display_name(self.mxid)\n            if display_name != self.nick:\n                await self.connection.set_display_name(self.mxid, self.nick)\n\n    async def _parse_sync_response(self, response):\n        self.connection.sync_token = response[\"next_batch\"]\n        for roomid in self.room_ids.values():\n            room = response['rooms']['join'].get(roomid, None)\n            if room and 'timeline' in room:\n                for event in room['timeline']['events']:\n                    if event['content']['msgtype'] == 'm.text':\n                        if event['sender'] != self.mxid:\n                            return Message(\n                                event['content']['body'],\n                                await self._get_nick(roomid, event['sender']),\n                                roomid,\n                                self,\n                                event_id=event['event_id'],\n                                raw_event=event)\n\n    async def listen(self):  # pragma: no cover\n        \"\"\"Listen for new messages from the chat service.\"\"\"\n        while True:  # pylint: disable=R1702\n            try:\n                response = await self.connection.sync(\n                    self.connection.sync_token,\n                    timeout_ms=int(6 * 60 * 60 * 1e3),  # 6h in ms\n                    filter=self.filter_id)\n                _LOGGER.debug(\"matrix sync request returned\")\n                message = await self._parse_sync_response(response)\n                await self.opsdroid.parse(message)\n\n            except MatrixRequestError as mre:\n                # We can safely ignore timeout errors. The non-standard error\n                # codes are returned by Cloudflare.\n                if mre.code in [504, 522, 524]:\n                    _LOGGER.info('Matrix Sync Timeout (code: %d)', mre.code)\n                    continue\n\n                _LOGGER.exception('Matrix Sync Error')\n            except CancelledError:\n                raise\n            except Exception:  # pylint: disable=W0703\n                _LOGGER.exception('Matrix Sync Error')\n\n    async def _get_nick(self, roomid, mxid):\n        \"\"\"\n        Get nickname from user ID.\n\n        Get the nickname of a sender depending on the room specific config\n        setting.\n        \"\"\"\n        if self.room_specific_nicks:\n            try:\n                return await self.connection.get_room_displayname(roomid, mxid)\n            except Exception:  # pylint: disable=W0703\n                # Fallback to the non-room specific one\n                logging.exception(\n                    \"Failed to lookup room specific nick for %s\", mxid)\n\n        try:\n            return await self.connection.get_display_name(mxid)\n        except MatrixRequestError as mre:\n            # Log the error if it's not the 404 from the user not having a nick\n            if mre.code != 404:\n                logging.exception(\"Failed to lookup nick for %s\", mxid)\n            return mxid\n\n    @staticmethod\n    def _get_formatted_message_body(message, body=None, msgtype=\"m.text\"):\n        \"\"\"\n        Get HTML from a message.\n\n        Return the json representation of the message in\n        \"org.matrix.custom.html\" format.\n        \"\"\"\n        # Markdown leaves a <p></p> around standard messages that we want to\n        # strip:\n        if message.startswith('<p>'):\n            message = message[3:]\n            if message.endswith('</p>'):\n                message = message[:-4]\n\n        clean_html = clean(message)\n\n        return {\n            # Strip out any tags from the markdown to make the body\n            \"body\": body if body else re.sub('<[^<]+?>', '', clean_html),\n            \"msgtype\": msgtype,\n            \"format\": \"org.matrix.custom.html\",\n            \"formatted_body\": clean_html\n            }\n\n    @register_event(Message)\n    async def send_message(self, message):\n        \"\"\"Send `message.text` back to the chat service.\"\"\"\n        if not message.target.startswith((\"!\", \"#\")):\n            room_id = self.rooms[message.target]\n        else:\n            room_id = message.target\n\n        # Ensure we have a room id not alias\n        if not room_id.startswith('!'):\n            room_id = await self.connection.get_room_id(room_id)\n        else:\n            room_id = room_id\n\n        try:\n            await self.connection.send_message_event(\n                room_id,\n                \"m.room.message\",\n                self._get_formatted_message_body(message.text))\n        except aiohttp.client_exceptions.ServerDisconnectedError:\n            _LOGGER.debug(\"Server had disconnected, retrying send.\")\n            await self.connection.send_message_event(\n                room_id,\n                \"m.room.message\",\n                self._get_formatted_message_body(message.text))\n\n    async def disconnect(self):\n        \"\"\"Close the matrix session.\"\"\"\n        await self.session.close()\n\n    def get_roomname(self, room):\n        \"\"\"Get the name of a room from alias or room ID.\"\"\"\n        if room.startswith(('#', '!')):\n            for connroom in self.rooms:\n                if room in (connroom, self.room_ids[connroom]):\n                    return connroom\n\n        return room\n", "path": "opsdroid/connector/matrix/connector.py"}]}