|
18 | 18 | #
|
19 | 19 | #
|
20 | 20 | import logging
|
21 |
| -from enum import Enum |
22 |
| -from typing import TYPE_CHECKING, AbstractSet, Dict, Final, List, Optional, Tuple |
| 21 | +from typing import TYPE_CHECKING, AbstractSet, Dict, List, Optional |
23 | 22 |
|
24 |
| -import attr |
25 | 23 | from immutabledict import immutabledict
|
26 | 24 |
|
27 |
| -from synapse._pydantic_compat import HAS_PYDANTIC_V2 |
28 |
| - |
29 |
| -if TYPE_CHECKING or HAS_PYDANTIC_V2: |
30 |
| - from pydantic.v1 import Extra |
31 |
| -else: |
32 |
| - from pydantic import Extra |
33 |
| - |
34 | 25 | from synapse.api.constants import Membership
|
35 | 26 | from synapse.events import EventBase
|
36 |
| -from synapse.rest.client.models import SlidingSyncBody |
37 |
| -from synapse.types import JsonMapping, Requester, RoomStreamToken, StreamToken, UserID |
| 27 | +from synapse.types import Requester, RoomStreamToken, StreamToken, UserID |
| 28 | +from synapse.types.handlers import OperationType, SlidingSyncConfig, SlidingSyncResult |
38 | 29 |
|
39 | 30 | if TYPE_CHECKING:
|
40 | 31 | from synapse.server import HomeServer
|
@@ -62,166 +53,6 @@ def filter_membership_for_sync(*, membership: str, user_id: str, sender: str) ->
|
62 | 53 | return membership != Membership.LEAVE or sender != user_id
|
63 | 54 |
|
64 | 55 |
|
65 |
| -class SlidingSyncConfig(SlidingSyncBody): |
66 |
| - """ |
67 |
| - Inherit from `SlidingSyncBody` since we need all of the same fields and add a few |
68 |
| - extra fields that we need in the handler |
69 |
| - """ |
70 |
| - |
71 |
| - user: UserID |
72 |
| - device_id: Optional[str] |
73 |
| - |
74 |
| - # Pydantic config |
75 |
| - class Config: |
76 |
| - # By default, ignore fields that we don't recognise. |
77 |
| - extra = Extra.ignore |
78 |
| - # By default, don't allow fields to be reassigned after parsing. |
79 |
| - allow_mutation = False |
80 |
| - # Allow custom types like `UserID` to be used in the model |
81 |
| - arbitrary_types_allowed = True |
82 |
| - |
83 |
| - |
84 |
| -class OperationType(Enum): |
85 |
| - """ |
86 |
| - Represents the operation types in a Sliding Sync window. |
87 |
| -
|
88 |
| - Attributes: |
89 |
| - SYNC: Sets a range of entries. Clients SHOULD discard what they previous knew about |
90 |
| - entries in this range. |
91 |
| - INSERT: Sets a single entry. If the position is not empty then clients MUST move |
92 |
| - entries to the left or the right depending on where the closest empty space is. |
93 |
| - DELETE: Remove a single entry. Often comes before an INSERT to allow entries to move |
94 |
| - places. |
95 |
| - INVALIDATE: Remove a range of entries. Clients MAY persist the invalidated range for |
96 |
| - offline support, but they should be treated as empty when additional operations |
97 |
| - which concern indexes in the range arrive from the server. |
98 |
| - """ |
99 |
| - |
100 |
| - SYNC: Final = "SYNC" |
101 |
| - INSERT: Final = "INSERT" |
102 |
| - DELETE: Final = "DELETE" |
103 |
| - INVALIDATE: Final = "INVALIDATE" |
104 |
| - |
105 |
| - |
106 |
| -@attr.s(slots=True, frozen=True, auto_attribs=True) |
107 |
| -class SlidingSyncResult: |
108 |
| - """ |
109 |
| - The Sliding Sync result to be serialized to JSON for a response. |
110 |
| -
|
111 |
| - Attributes: |
112 |
| - next_pos: The next position token in the sliding window to request (next_batch). |
113 |
| - lists: Sliding window API. A map of list key to list results. |
114 |
| - rooms: Room subscription API. A map of room ID to room subscription to room results. |
115 |
| - extensions: Extensions API. A map of extension key to extension results. |
116 |
| - """ |
117 |
| - |
118 |
| - @attr.s(slots=True, frozen=True, auto_attribs=True) |
119 |
| - class RoomResult: |
120 |
| - """ |
121 |
| - Attributes: |
122 |
| - name: Room name or calculated room name. |
123 |
| - avatar: Room avatar |
124 |
| - heroes: List of stripped membership events (containing `user_id` and optionally |
125 |
| - `avatar_url` and `displayname`) for the users used to calculate the room name. |
126 |
| - initial: Flag which is set when this is the first time the server is sending this |
127 |
| - data on this connection. Clients can use this flag to replace or update |
128 |
| - their local state. When there is an update, servers MUST omit this flag |
129 |
| - entirely and NOT send "initial":false as this is wasteful on bandwidth. The |
130 |
| - absence of this flag means 'false'. |
131 |
| - required_state: The current state of the room |
132 |
| - timeline: Latest events in the room. The last event is the most recent |
133 |
| - is_dm: Flag to specify whether the room is a direct-message room (most likely |
134 |
| - between two people). |
135 |
| - invite_state: Stripped state events. Same as `rooms.invite.$room_id.invite_state` |
136 |
| - in sync v2, absent on joined/left rooms |
137 |
| - prev_batch: A token that can be passed as a start parameter to the |
138 |
| - `/rooms/<room_id>/messages` API to retrieve earlier messages. |
139 |
| - limited: True if their are more events than fit between the given position and now. |
140 |
| - Sync again to get more. |
141 |
| - joined_count: The number of users with membership of join, including the client's |
142 |
| - own user ID. (same as sync `v2 m.joined_member_count`) |
143 |
| - invited_count: The number of users with membership of invite. (same as sync v2 |
144 |
| - `m.invited_member_count`) |
145 |
| - notification_count: The total number of unread notifications for this room. (same |
146 |
| - as sync v2) |
147 |
| - highlight_count: The number of unread notifications for this room with the highlight |
148 |
| - flag set. (same as sync v2) |
149 |
| - num_live: The number of timeline events which have just occurred and are not historical. |
150 |
| - The last N events are 'live' and should be treated as such. This is mostly |
151 |
| - useful to determine whether a given @mention event should make a noise or not. |
152 |
| - Clients cannot rely solely on the absence of `initial: true` to determine live |
153 |
| - events because if a room not in the sliding window bumps into the window because |
154 |
| - of an @mention it will have `initial: true` yet contain a single live event |
155 |
| - (with potentially other old events in the timeline). |
156 |
| - """ |
157 |
| - |
158 |
| - name: str |
159 |
| - avatar: Optional[str] |
160 |
| - heroes: Optional[List[EventBase]] |
161 |
| - initial: bool |
162 |
| - required_state: List[EventBase] |
163 |
| - timeline: List[EventBase] |
164 |
| - is_dm: bool |
165 |
| - invite_state: List[EventBase] |
166 |
| - prev_batch: StreamToken |
167 |
| - limited: bool |
168 |
| - joined_count: int |
169 |
| - invited_count: int |
170 |
| - notification_count: int |
171 |
| - highlight_count: int |
172 |
| - num_live: int |
173 |
| - |
174 |
| - @attr.s(slots=True, frozen=True, auto_attribs=True) |
175 |
| - class SlidingWindowList: |
176 |
| - """ |
177 |
| - Attributes: |
178 |
| - count: The total number of entries in the list. Always present if this list |
179 |
| - is. |
180 |
| - ops: The sliding list operations to perform. |
181 |
| - """ |
182 |
| - |
183 |
| - @attr.s(slots=True, frozen=True, auto_attribs=True) |
184 |
| - class Operation: |
185 |
| - """ |
186 |
| - Attributes: |
187 |
| - op: The operation type to perform. |
188 |
| - range: Which index positions are affected by this operation. These are |
189 |
| - both inclusive. |
190 |
| - room_ids: Which room IDs are affected by this operation. These IDs match |
191 |
| - up to the positions in the `range`, so the last room ID in this list |
192 |
| - matches the 9th index. The room data is held in a separate object. |
193 |
| - """ |
194 |
| - |
195 |
| - op: OperationType |
196 |
| - range: Tuple[int, int] |
197 |
| - room_ids: List[str] |
198 |
| - |
199 |
| - count: int |
200 |
| - ops: List[Operation] |
201 |
| - |
202 |
| - next_pos: StreamToken |
203 |
| - lists: Dict[str, SlidingWindowList] |
204 |
| - rooms: Dict[str, RoomResult] |
205 |
| - extensions: JsonMapping |
206 |
| - |
207 |
| - def __bool__(self) -> bool: |
208 |
| - """Make the result appear empty if there are no updates. This is used |
209 |
| - to tell if the notifier needs to wait for more events when polling for |
210 |
| - events. |
211 |
| - """ |
212 |
| - return bool(self.lists or self.rooms or self.extensions) |
213 |
| - |
214 |
| - @staticmethod |
215 |
| - def empty(next_pos: StreamToken) -> "SlidingSyncResult": |
216 |
| - "Return a new empty result" |
217 |
| - return SlidingSyncResult( |
218 |
| - next_pos=next_pos, |
219 |
| - lists={}, |
220 |
| - rooms={}, |
221 |
| - extensions={}, |
222 |
| - ) |
223 |
| - |
224 |
| - |
225 | 56 | class SlidingSyncHandler:
|
226 | 57 | def __init__(self, hs: "HomeServer"):
|
227 | 58 | self.clock = hs.get_clock()
|
|
0 commit comments