|
16 | 16 | import logging |
17 | 17 | import re |
18 | 18 | from collections import deque |
19 | | -from typing import TYPE_CHECKING, Iterable, List, Optional, Sequence, Set, Tuple |
| 19 | +from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Sequence, Set, Tuple |
20 | 20 |
|
21 | 21 | import attr |
22 | 22 |
|
@@ -89,7 +89,10 @@ async def get_space_summary( |
89 | 89 | room_queue = deque((_RoomQueueEntry(room_id, ()),)) |
90 | 90 |
|
91 | 91 | # rooms we have already processed |
92 | | - processed_rooms = set() # type: Set[str] |
| 92 | + processed_rooms: Dict[str, bool] = {} |
| 93 | + |
| 94 | + # events which are pending knowing if a room is accessible. |
| 95 | + pending_events: Dict[str, List[JsonDict]] = {} |
93 | 96 |
|
94 | 97 | rooms_result = [] # type: List[JsonDict] |
95 | 98 | events_result = [] # type: List[JsonDict] |
@@ -123,21 +126,27 @@ async def get_space_summary( |
123 | 126 |
|
124 | 127 | if room: |
125 | 128 | rooms_result.append(room) |
| 129 | + |
| 130 | + # Mark whether this room was accessible or not. |
| 131 | + processed_rooms[room_id] = bool(room) |
126 | 132 | else: |
127 | | - fed_rooms, fed_events = await self._summarize_remote_room( |
| 133 | + fed_rooms, events = await self._summarize_remote_room( |
128 | 134 | queue_entry, |
129 | 135 | suggested_only, |
130 | 136 | max_children, |
131 | 137 | exclude_rooms=processed_rooms, |
132 | 138 | ) |
133 | 139 |
|
| 140 | + # The queried room may or may not have been returned, but don't process |
| 141 | + # it again, anyway. (This may be overridden below if it is accessible.) |
| 142 | + processed_rooms[room_id] = False |
| 143 | + |
134 | 144 | # The results over federation might include rooms that the we, |
135 | 145 | # as the requesting server, are allowed to see, but the requesting |
136 | 146 | # user is not permitted see. |
137 | 147 | # |
138 | 148 | # Filter the returned results to only what is accessible to the user. |
139 | 149 | room_ids = set() |
140 | | - events = [] |
141 | 150 | for room in fed_rooms: |
142 | 151 | fed_room_id = room.get("room_id") |
143 | 152 | if not fed_room_id or not isinstance(fed_room_id, str): |
@@ -181,34 +190,42 @@ async def get_space_summary( |
181 | 190 |
|
182 | 191 | # All rooms returned don't need visiting again (even if the user |
183 | 192 | # didn't have access to them). |
184 | | - processed_rooms.add(fed_room_id) |
185 | | - |
186 | | - for event in fed_events: |
187 | | - if event.get("room_id") in room_ids: |
188 | | - events.append(event) |
| 193 | + processed_rooms[fed_room_id] = include_room |
189 | 194 |
|
190 | 195 | logger.debug( |
191 | 196 | "Query of %s returned rooms %s, events %s", |
192 | 197 | room_id, |
193 | 198 | [room.get("room_id") for room in fed_rooms], |
194 | | - ["%s->%s" % (ev["room_id"], ev["state_key"]) for ev in fed_events], |
| 199 | + ["%s->%s" % (ev["room_id"], ev["state_key"]) for ev in events], |
195 | 200 | ) |
196 | 201 |
|
197 | | - # the room we queried may or may not have been returned, but don't process |
198 | | - # it again, anyway. |
199 | | - processed_rooms.add(room_id) |
| 202 | + # There might be events which point to this room which are waiting |
| 203 | + # to see if it is accessible. |
| 204 | + room_pending_events = pending_events.pop(room_id, ()) |
| 205 | + if not processed_rooms[room_id]: |
| 206 | + room_pending_events = () |
200 | 207 |
|
201 | | - # XXX: is it ok that we blindly iterate through any events returned by |
202 | | - # a remote server, whether or not they actually link to any rooms in our |
203 | | - # tree? |
204 | | - for ev in events: |
205 | | - events_result.append(ev) |
| 208 | + # Return the events which reference rooms that were found to be |
| 209 | + # accessible. Otherwise, queue them until we process those rooms. |
| 210 | + for ev in itertools.chain(events, room_pending_events): |
| 211 | + parent_room_id = ev["room_id"] |
| 212 | + child_room_id = ev["state_key"] |
| 213 | + |
| 214 | + try: |
| 215 | + if ( |
| 216 | + processed_rooms[parent_room_id] |
| 217 | + and processed_rooms[child_room_id] |
| 218 | + ): |
| 219 | + events_result.append(ev) |
| 220 | + except KeyError: |
| 221 | + # Note that events are pending of the child event since if |
| 222 | + # the parent event was not accessible it shouldn't be included |
| 223 | + # at all. |
| 224 | + pending_events.setdefault(child_room_id, []).append(ev) |
206 | 225 |
|
207 | 226 | # add the child to the queue. we have already validated |
208 | 227 | # that the vias are a list of server names. |
209 | | - room_queue.append( |
210 | | - _RoomQueueEntry(ev["state_key"], ev["content"]["via"]) |
211 | | - ) |
| 228 | + room_queue.append(_RoomQueueEntry(child_room_id, ev["content"]["via"])) |
212 | 229 |
|
213 | 230 | # Before returning to the client, remove the allowed_spaces key for any |
214 | 231 | # rooms. |
|
0 commit comments