mirror of
https://github.com/django/daphne.git
synced 2025-04-21 01:02:06 +03:00
Remove middleware approach, change to simpler one
This commit is contained in:
parent
0fcb93acc2
commit
db0d2975a0
|
@ -3,7 +3,6 @@ from __future__ import unicode_literals
|
|||
from django.utils import six
|
||||
|
||||
from channels import DEFAULT_CHANNEL_LAYER, channel_layers
|
||||
from .signals import message_sent
|
||||
|
||||
|
||||
class Channel(object):
|
||||
|
@ -37,7 +36,6 @@ class Channel(object):
|
|||
if not isinstance(content, dict):
|
||||
raise TypeError("You can only send dicts as content on channels.")
|
||||
self.channel_layer.send(self.name, content)
|
||||
message_sent.send(sender=self.__class__, channel=self.name, keys=list(content.keys()))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import importlib
|
||||
import threading
|
||||
import warnings
|
||||
from django.conf import settings
|
||||
|
||||
from .exceptions import DenyConnection
|
||||
from .signals import consumer_started, consumer_finished, message_sent
|
||||
|
||||
|
||||
class ConsumerMiddlewareRegistry(object):
|
||||
"""
|
||||
Handles registration (via settings object) and generation of consumer
|
||||
middleware stacks
|
||||
"""
|
||||
|
||||
fixed_middleware = ["channels.consumer_middleware.ConvenienceMiddleware"]
|
||||
|
||||
def __init__(self):
|
||||
# Load middleware callables from settings
|
||||
middleware_paths = self.fixed_middleware + getattr(settings, "CONSUMER_MIDDLEWARE", [])
|
||||
self.middleware_instances = []
|
||||
for path in middleware_paths:
|
||||
module_name, variable_name = path.rsplit(".", 1)
|
||||
try:
|
||||
self.middleware_instances.append(getattr(importlib.import_module(module_name), variable_name))
|
||||
except (ImportError, AttributeError) as e:
|
||||
raise ImproperlyConfigured("Cannot import consumer middleware %r: %s" % (path, e))
|
||||
|
||||
def make_chain(self, consumer, kwargs):
|
||||
"""
|
||||
Returns an instantiated chain of middleware around a final consumer.
|
||||
"""
|
||||
next_layer = lambda message: consumer(message, **kwargs)
|
||||
for middleware_instance in reversed(self.middleware_instances):
|
||||
next_layer = middleware_instance(next_layer)
|
||||
return next_layer
|
||||
|
||||
|
||||
class ConvenienceMiddleware(object):
|
||||
"""
|
||||
Standard middleware which papers over some more explicit parts of ASGI.
|
||||
"""
|
||||
|
||||
runtime_data = threading.local()
|
||||
|
||||
def __init__(self, consumer):
|
||||
self.consumer = consumer
|
||||
|
||||
def __call__(self, message):
|
||||
if message.channel.name == "websocket.connect":
|
||||
# Websocket connect acceptance helper
|
||||
try:
|
||||
self.consumer(message)
|
||||
except DenyConnection:
|
||||
message.reply_channel.send({"accept": False})
|
||||
else:
|
||||
replies_sent = [msg for chan, msg in self.get_messages() if chan == message.reply_channel.name]
|
||||
# If they sent no replies, send implicit acceptance
|
||||
if not replies_sent:
|
||||
warnings.warn("AAAAAAAAAAA", RuntimeWarning)
|
||||
message.reply_channel.send({"accept": True})
|
||||
else:
|
||||
# General path
|
||||
return self.consumer(message)
|
||||
|
||||
@classmethod
|
||||
def reset_messages(cls, **kwargs):
|
||||
"""
|
||||
Tied to the consumer started/ended signal to reset the messages list.
|
||||
"""
|
||||
cls.runtime_data.sent_messages = []
|
||||
|
||||
consumer_started.connect(lambda **kwargs: ConvenienceMiddleware.reset_messages(), weak=False)
|
||||
consumer_finished.connect(lambda **kwargs: ConvenienceMiddleware.reset_messages(), weak=False)
|
||||
|
||||
@classmethod
|
||||
def sent_message(cls, channel, keys, **kwargs):
|
||||
"""
|
||||
Called by message sending interfaces when messages are sent,
|
||||
for convenience errors only. Should not be relied upon to get
|
||||
all messages.
|
||||
"""
|
||||
cls.runtime_data.sent_messages = getattr(cls.runtime_data, "sent_messages", []) + [(channel, keys)]
|
||||
|
||||
message_sent.connect(lambda channel, keys, **kwargs: ConvenienceMiddleware.sent_message(channel, keys), weak=False)
|
||||
|
||||
@classmethod
|
||||
def get_messages(cls):
|
||||
return getattr(cls.runtime_data, "sent_messages", [])
|
|
@ -7,9 +7,5 @@ consumer_finished = Signal()
|
|||
worker_ready = Signal()
|
||||
worker_process_ready = Signal()
|
||||
|
||||
# Called when a message is sent directly to a channel. Not called for group
|
||||
# sends or direct ASGI usage. For convenience/nicer errors only.
|
||||
message_sent = Signal(providing_args=["channel", "keys"])
|
||||
|
||||
# Connect connection closer to consumer finished as well
|
||||
consumer_finished.connect(close_old_connections)
|
||||
|
|
|
@ -9,11 +9,10 @@ import multiprocessing
|
|||
import threading
|
||||
|
||||
from .signals import consumer_started, consumer_finished
|
||||
from .exceptions import ConsumeLater
|
||||
from .exceptions import ConsumeLater, DenyConnection
|
||||
from .message import Message
|
||||
from .utils import name_that_thing
|
||||
from .signals import worker_ready
|
||||
from .consumer_middleware import ConsumerMiddlewareRegistry
|
||||
|
||||
logger = logging.getLogger('django.channels')
|
||||
|
||||
|
@ -41,7 +40,6 @@ class Worker(object):
|
|||
self.exclude_channels = exclude_channels
|
||||
self.termed = False
|
||||
self.in_job = False
|
||||
self.middleware_registry = ConsumerMiddlewareRegistry()
|
||||
|
||||
def install_signal_handler(self):
|
||||
signal.signal(signal.SIGTERM, self.sigterm_handler)
|
||||
|
@ -119,8 +117,12 @@ class Worker(object):
|
|||
# Send consumer started to manage lifecycle stuff
|
||||
consumer_started.send(sender=self.__class__, environ={})
|
||||
# Run consumer
|
||||
chain = self.middleware_registry.make_chain(consumer, kwargs)
|
||||
chain(message)
|
||||
consumer(message, **kwargs)
|
||||
except DenyConnection:
|
||||
# They want to deny a WebSocket connection.
|
||||
if message.channel.name != "websocket.connect":
|
||||
raise ValueError("You cannot DenyConnection from a non-websocket.connect handler.")
|
||||
message.reply_channel.send({"accept": False})
|
||||
except ConsumeLater:
|
||||
# They want to not handle it yet. Re-inject it with a number-of-tries marker.
|
||||
content['__retries__'] = content.get("__retries__", 0) + 1
|
||||
|
|
|
@ -790,6 +790,9 @@ is received to say if the connection should be accepted or dropped.
|
|||
|
||||
Behaviour on WebSocket rejection is defined in the Connection section above.
|
||||
|
||||
If received while the socket is already accepted, the protocol server should
|
||||
log an error, but not do anything.
|
||||
|
||||
Channel: ``websocket.send!``
|
||||
|
||||
Keys:
|
||||
|
|
Loading…
Reference in New Issue
Block a user