mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 17:31:10 -05:00
okay fine
This commit is contained in:
133
.venv/lib/python3.12/site-packages/channels/consumer.py
Normal file
133
.venv/lib/python3.12/site-packages/channels/consumer.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import functools
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
|
||||
from . import DEFAULT_CHANNEL_LAYER
|
||||
from .db import database_sync_to_async
|
||||
from .exceptions import StopConsumer
|
||||
from .layers import get_channel_layer
|
||||
from .utils import await_many_dispatch
|
||||
|
||||
|
||||
def get_handler_name(message):
|
||||
"""
|
||||
Looks at a message, checks it has a sensible type, and returns the
|
||||
handler name for that type.
|
||||
"""
|
||||
# Check message looks OK
|
||||
if "type" not in message:
|
||||
raise ValueError("Incoming message has no 'type' attribute")
|
||||
# Extract type and replace . with _
|
||||
handler_name = message["type"].replace(".", "_")
|
||||
if handler_name.startswith("_"):
|
||||
raise ValueError("Malformed type in message (leading underscore)")
|
||||
return handler_name
|
||||
|
||||
|
||||
class AsyncConsumer:
|
||||
"""
|
||||
Base consumer class. Implements the ASGI application spec, and adds on
|
||||
channel layer management and routing of events to named methods based
|
||||
on their type.
|
||||
"""
|
||||
|
||||
_sync = False
|
||||
channel_layer_alias = DEFAULT_CHANNEL_LAYER
|
||||
|
||||
async def __call__(self, scope, receive, send):
|
||||
"""
|
||||
Dispatches incoming messages to type-based handlers asynchronously.
|
||||
"""
|
||||
self.scope = scope
|
||||
|
||||
# Initialize channel layer
|
||||
self.channel_layer = get_channel_layer(self.channel_layer_alias)
|
||||
if self.channel_layer is not None:
|
||||
self.channel_name = await self.channel_layer.new_channel()
|
||||
self.channel_receive = functools.partial(
|
||||
self.channel_layer.receive, self.channel_name
|
||||
)
|
||||
# Store send function
|
||||
if self._sync:
|
||||
self.base_send = async_to_sync(send)
|
||||
else:
|
||||
self.base_send = send
|
||||
# Pass messages in from channel layer or client to dispatch method
|
||||
try:
|
||||
if self.channel_layer is not None:
|
||||
await await_many_dispatch(
|
||||
[receive, self.channel_receive], self.dispatch
|
||||
)
|
||||
else:
|
||||
await await_many_dispatch([receive], self.dispatch)
|
||||
except StopConsumer:
|
||||
# Exit cleanly
|
||||
pass
|
||||
|
||||
async def dispatch(self, message):
|
||||
"""
|
||||
Works out what to do with a message.
|
||||
"""
|
||||
handler = getattr(self, get_handler_name(message), None)
|
||||
if handler:
|
||||
await handler(message)
|
||||
else:
|
||||
raise ValueError("No handler for message type %s" % message["type"])
|
||||
|
||||
async def send(self, message):
|
||||
"""
|
||||
Overrideable/callable-by-subclasses send method.
|
||||
"""
|
||||
await self.base_send(message)
|
||||
|
||||
@classmethod
|
||||
def as_asgi(cls, **initkwargs):
|
||||
"""
|
||||
Return an ASGI v3 single callable that instantiates a consumer instance
|
||||
per scope. Similar in purpose to Django's as_view().
|
||||
|
||||
initkwargs will be used to instantiate the consumer instance.
|
||||
"""
|
||||
|
||||
async def app(scope, receive, send):
|
||||
consumer = cls(**initkwargs)
|
||||
return await consumer(scope, receive, send)
|
||||
|
||||
app.consumer_class = cls
|
||||
app.consumer_initkwargs = initkwargs
|
||||
|
||||
# take name and docstring from class
|
||||
functools.update_wrapper(app, cls, updated=())
|
||||
return app
|
||||
|
||||
|
||||
class SyncConsumer(AsyncConsumer):
|
||||
"""
|
||||
Synchronous version of the consumer, which is what we write most of the
|
||||
generic consumers against (for now). Calls handlers in a threadpool and
|
||||
uses CallBouncer to get the send method out to the main event loop.
|
||||
|
||||
It would have been possible to have "mixed" consumers and auto-detect
|
||||
if a handler was awaitable or not, but that would have made the API
|
||||
for user-called methods very confusing as there'd be two types of each.
|
||||
"""
|
||||
|
||||
_sync = True
|
||||
|
||||
@database_sync_to_async
|
||||
def dispatch(self, message):
|
||||
"""
|
||||
Dispatches incoming messages to type-based handlers asynchronously.
|
||||
"""
|
||||
# Get and execute the handler
|
||||
handler = getattr(self, get_handler_name(message), None)
|
||||
if handler:
|
||||
handler(message)
|
||||
else:
|
||||
raise ValueError("No handler for message type %s" % message["type"])
|
||||
|
||||
def send(self, message):
|
||||
"""
|
||||
Overrideable/callable-by-subclasses send method.
|
||||
"""
|
||||
self.base_send(message)
|
||||
Reference in New Issue
Block a user