|
6 | 6 | import re |
7 | 7 | import string |
8 | 8 | import time |
| 9 | +from abc import ABC, abstractmethod |
9 | 10 | from copy import deepcopy |
10 | | -from typing import Dict, Iterable, List, Optional, Tuple |
| 11 | +from typing import ( |
| 12 | + Dict, |
| 13 | + Iterable, |
| 14 | + List, |
| 15 | + NoReturn, |
| 16 | + Optional, |
| 17 | + Protocol, |
| 18 | + Tuple, |
| 19 | + runtime_checkable, |
| 20 | +) |
11 | 21 |
|
12 | 22 | from django.conf import settings |
13 | 23 | from django.core.signals import setting_changed |
@@ -97,7 +107,39 @@ def set(self, key: str, layer: BaseChannelLayer): |
97 | 107 | return old |
98 | 108 |
|
99 | 109 |
|
100 | | -class BaseChannelLayer: |
| 110 | +@runtime_checkable |
| 111 | +class WithFlushExtension(Protocol): |
| 112 | + async def flush(self) -> NoReturn: |
| 113 | + """ |
| 114 | + Clears messages and if available groups |
| 115 | + """ |
| 116 | + |
| 117 | + async def close(self) -> NoReturn: |
| 118 | + """ |
| 119 | + Close connection to the layer. Called before stopping layer. |
| 120 | + Unusable after. |
| 121 | + """ |
| 122 | + |
| 123 | + |
| 124 | +@runtime_checkable |
| 125 | +class WithGroupsExtension(Protocol): |
| 126 | + async def group_add(self, group: str, channel: str): |
| 127 | + """ |
| 128 | + Adds the channel name to a group. |
| 129 | + """ |
| 130 | + |
| 131 | + async def group_discard(self, group: str, channel: str) -> NoReturn: |
| 132 | + """ |
| 133 | + Removes the channel name from a group when it exists. |
| 134 | + """ |
| 135 | + |
| 136 | + async def group_send(self, group: str, message: dict) -> NoReturn: |
| 137 | + """ |
| 138 | + Sends message to group |
| 139 | + """ |
| 140 | + |
| 141 | + |
| 142 | +class BaseChannelLayer(ABC): |
101 | 143 | """ |
102 | 144 | Base channel layer class that others can inherit from, with useful |
103 | 145 | common functionality. |
@@ -199,51 +241,29 @@ def non_local_name(self, name: str) -> str: |
199 | 241 | else: |
200 | 242 | return name |
201 | 243 |
|
| 244 | + @abstractmethod |
202 | 245 | async def send(self, channel: str, message: dict): |
203 | 246 | """ |
204 | 247 | Send a message onto a (general or specific) channel. |
205 | 248 | """ |
206 | | - raise NotImplementedError() |
207 | 249 |
|
| 250 | + @abstractmethod |
208 | 251 | async def receive(self, channel: str) -> dict: |
209 | 252 | """ |
210 | 253 | Receive the first message that arrives on the channel. |
211 | 254 | If more than one coroutine waits on the same channel, a random one |
212 | 255 | of the waiting coroutines will get the result. |
213 | 256 | """ |
214 | | - raise NotImplementedError() |
215 | 257 |
|
| 258 | + @abstractmethod |
216 | 259 | async def new_channel(self, prefix: str = "specific.") -> str: |
217 | 260 | """ |
218 | 261 | Returns a new channel name that can be used by something in our |
219 | 262 | process as a specific channel. |
220 | 263 | """ |
221 | | - raise NotImplementedError() |
222 | | - |
223 | | - # Flush extension |
224 | | - |
225 | | - async def flush(self): |
226 | | - raise NotImplementedError() |
227 | | - |
228 | | - async def close(self): |
229 | | - raise NotImplementedError() |
230 | | - |
231 | | - # Groups extension |
232 | | - |
233 | | - async def group_add(self, group: str, channel: str): |
234 | | - """ |
235 | | - Adds the channel name to a group. |
236 | | - """ |
237 | | - raise NotImplementedError() |
238 | | - |
239 | | - async def group_discard(self, group: str, channel: str): |
240 | | - raise NotImplementedError() |
241 | | - |
242 | | - async def group_send(self, group: str, message: dict): |
243 | | - raise NotImplementedError() |
244 | 264 |
|
245 | 265 |
|
246 | | -class InMemoryChannelLayer(BaseChannelLayer): |
| 266 | +class InMemoryChannelLayer(WithFlushExtension, WithGroupsExtension, BaseChannelLayer): |
247 | 267 | """ |
248 | 268 | In-memory channel layer implementation |
249 | 269 | """ |
|
0 commit comments