mirror of
https://github.com/django/daphne.git
synced 2025-07-14 01:42:17 +03:00
Implement send_channel_session
This commit is contained in:
parent
6e91ea0040
commit
804a4c561e
|
@ -1,5 +1,8 @@
|
||||||
import functools
|
import functools
|
||||||
|
import hashlib
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from channels import channel_backends, DEFAULT_CHANNEL_BACKEND
|
from channels import channel_backends, DEFAULT_CHANNEL_BACKEND
|
||||||
|
@ -24,3 +27,34 @@ def consumer(*channels, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
# TODO: Sessions, auth
|
# TODO: Sessions, auth
|
||||||
|
|
||||||
|
def send_channel_session(func):
|
||||||
|
"""
|
||||||
|
Provides a session-like object called "channel_session" to consumers
|
||||||
|
as a message attribute that will auto-persist across consumers with
|
||||||
|
the same incoming "send_channel" value.
|
||||||
|
"""
|
||||||
|
@functools.wraps(func)
|
||||||
|
def inner(*args, **kwargs):
|
||||||
|
# Make sure there's a send_channel in kwargs
|
||||||
|
if "send_channel" not in kwargs:
|
||||||
|
raise ValueError("No send_channel sent to consumer; this decorator can only be used on messages containing it.")
|
||||||
|
# Turn the send_channel into a valid session key length thing.
|
||||||
|
# We take the last 24 bytes verbatim, as these are the random section,
|
||||||
|
# and then hash the remaining ones onto the start, and add a prefix
|
||||||
|
# TODO: See if there's a better way of doing this
|
||||||
|
session_key = "skt" + hashlib.md5(kwargs['send_channel'][:-24]).hexdigest()[:8] + kwargs['send_channel'][-24:]
|
||||||
|
# Make a session storage
|
||||||
|
session_engine = import_module(settings.SESSION_ENGINE)
|
||||||
|
session = session_engine.SessionStore(session_key=session_key)
|
||||||
|
# If the session does not already exist, save to force our session key to be valid
|
||||||
|
if not session.exists(session.session_key):
|
||||||
|
session.save()
|
||||||
|
kwargs['channel_session'] = session
|
||||||
|
# Run the consumer
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
# Persist session if needed (won't be saved if error happens)
|
||||||
|
if session.modified:
|
||||||
|
session.save()
|
||||||
|
return result
|
||||||
|
return inner
|
||||||
|
|
|
@ -275,7 +275,7 @@ However, that session is based on cookies, and so follows the user round the
|
||||||
site - it's great for information that should persist across all WebSocket and
|
site - it's great for information that should persist across all WebSocket and
|
||||||
HTTP connections, but not great for information that is specific to a single
|
HTTP connections, but not great for information that is specific to a single
|
||||||
WebSocket (such as "which chatroom should this socket be connected to"). For
|
WebSocket (such as "which chatroom should this socket be connected to"). For
|
||||||
this reason, Channels also provides a ``websocker_channel_session`` decorator,
|
this reason, Channels also provides a ``send_channel_session`` decorator,
|
||||||
which adds a ``channel_session`` attribute to the message; this works just like
|
which adds a ``channel_session`` attribute to the message; this works just like
|
||||||
the normal ``session`` attribute, and persists to the same storage, but varies
|
the normal ``session`` attribute, and persists to the same storage, but varies
|
||||||
per-channel rather than per-cookie.
|
per-channel rather than per-cookie.
|
||||||
|
@ -284,10 +284,10 @@ Let's use it now to build a chat server that expects you to pass a chatroom
|
||||||
name in the path of your WebSocket request (we'll ignore auth for now)::
|
name in the path of your WebSocket request (we'll ignore auth for now)::
|
||||||
|
|
||||||
from channels import Channel
|
from channels import Channel
|
||||||
from channels.decorators import consumer, websocket_channel_session
|
from channels.decorators import consumer, send_channel_session
|
||||||
|
|
||||||
@consumer("django.websocket.connect")
|
@consumer("django.websocket.connect")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_connect(channel, send_channel, path, channel_session, **kwargs):
|
def ws_connect(channel, send_channel, path, channel_session, **kwargs):
|
||||||
# Work out room name from path (ignore slashes)
|
# Work out room name from path (ignore slashes)
|
||||||
room = path.strip("/")
|
room = path.strip("/")
|
||||||
|
@ -296,17 +296,17 @@ name in the path of your WebSocket request (we'll ignore auth for now)::
|
||||||
Group("chat-%s" % room).add(send_channel)
|
Group("chat-%s" % room).add(send_channel)
|
||||||
|
|
||||||
@consumer("django.websocket.keepalive")
|
@consumer("django.websocket.keepalive")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_add(channel, send_channel, channel_session, **kwargs):
|
def ws_add(channel, send_channel, channel_session, **kwargs):
|
||||||
Group("chat-%s" % channel_session['room']).add(send_channel)
|
Group("chat-%s" % channel_session['room']).add(send_channel)
|
||||||
|
|
||||||
@consumer("django.websocket.receive")
|
@consumer("django.websocket.receive")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_message(channel, send_channel, content, channel_session, **kwargs):
|
def ws_message(channel, send_channel, content, channel_session, **kwargs):
|
||||||
Group("chat-%s" % channel_session['room']).send(content=content)
|
Group("chat-%s" % channel_session['room']).send(content=content)
|
||||||
|
|
||||||
@consumer("django.websocket.disconnect")
|
@consumer("django.websocket.disconnect")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_disconnect(channel, send_channel, channel_session, **kwargs):
|
def ws_disconnect(channel, send_channel, channel_session, **kwargs):
|
||||||
Group("chat-%s" % channel_session['room']).discard(send_channel)
|
Group("chat-%s" % channel_session['room']).discard(send_channel)
|
||||||
|
|
||||||
|
@ -340,7 +340,7 @@ Let's see what that looks like, assuming we
|
||||||
have a ChatMessage model with ``message`` and ``room`` fields::
|
have a ChatMessage model with ``message`` and ``room`` fields::
|
||||||
|
|
||||||
from channels import Channel
|
from channels import Channel
|
||||||
from channels.decorators import consumer, websocket_channel_session
|
from channels.decorators import consumer, send_channel_session
|
||||||
from .models import ChatMessage
|
from .models import ChatMessage
|
||||||
|
|
||||||
@consumer("chat-messages")
|
@consumer("chat-messages")
|
||||||
|
@ -351,7 +351,7 @@ have a ChatMessage model with ``message`` and ``room`` fields::
|
||||||
Group("chat-%s" % room).send(message)
|
Group("chat-%s" % room).send(message)
|
||||||
|
|
||||||
@consumer("django.websocket.connect")
|
@consumer("django.websocket.connect")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_connect(channel, send_channel, path, channel_session, **kwargs):
|
def ws_connect(channel, send_channel, path, channel_session, **kwargs):
|
||||||
# Work out room name from path (ignore slashes)
|
# Work out room name from path (ignore slashes)
|
||||||
room = path.strip("/")
|
room = path.strip("/")
|
||||||
|
@ -360,18 +360,18 @@ have a ChatMessage model with ``message`` and ``room`` fields::
|
||||||
Group("chat-%s" % room).add(send_channel)
|
Group("chat-%s" % room).add(send_channel)
|
||||||
|
|
||||||
@consumer("django.websocket.keepalive")
|
@consumer("django.websocket.keepalive")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_add(channel, send_channel, channel_session, **kwargs):
|
def ws_add(channel, send_channel, channel_session, **kwargs):
|
||||||
Group("chat-%s" % channel_session['room']).add(send_channel)
|
Group("chat-%s" % channel_session['room']).add(send_channel)
|
||||||
|
|
||||||
@consumer("django.websocket.receive")
|
@consumer("django.websocket.receive")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_message(channel, send_channel, content, channel_session, **kwargs):
|
def ws_message(channel, send_channel, content, channel_session, **kwargs):
|
||||||
# Stick the message onto the processing queue
|
# Stick the message onto the processing queue
|
||||||
Channel("chat-messages").send(room=channel_session['room'], message=content)
|
Channel("chat-messages").send(room=channel_session['room'], message=content)
|
||||||
|
|
||||||
@consumer("django.websocket.disconnect")
|
@consumer("django.websocket.disconnect")
|
||||||
@websocket_channel_session
|
@send_channel_session
|
||||||
def ws_disconnect(channel, send_channel, channel_session, **kwargs):
|
def ws_disconnect(channel, send_channel, channel_session, **kwargs):
|
||||||
Group("chat-%s" % channel_session['room']).discard(send_channel)
|
Group("chat-%s" % channel_session['room']).discard(send_channel)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user