|
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