mirror of
https://github.com/django/daphne.git
synced 2025-07-10 16:02:18 +03:00
Rename channels and change message format docs
This commit is contained in:
parent
fc52e3c5a2
commit
70caf7d171
|
@ -11,7 +11,7 @@ from channels import Channel, channel_backends, DEFAULT_CHANNEL_BACKEND
|
||||||
class InterfaceProtocol(WebSocketServerProtocol):
|
class InterfaceProtocol(WebSocketServerProtocol):
|
||||||
"""
|
"""
|
||||||
Protocol which supports WebSockets and forwards incoming messages to
|
Protocol which supports WebSockets and forwards incoming messages to
|
||||||
the django.websocket channels.
|
the websocket channels.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def onConnect(self, request):
|
def onConnect(self, request):
|
||||||
|
@ -23,22 +23,22 @@ class InterfaceProtocol(WebSocketServerProtocol):
|
||||||
|
|
||||||
def onOpen(self):
|
def onOpen(self):
|
||||||
# Make sending channel
|
# Make sending channel
|
||||||
self.reply_channel = Channel.new_name("!django.websocket.send")
|
self.reply_channel = Channel.new_name("!websocket.send")
|
||||||
self.request_info["reply_channel"] = self.reply_channel
|
self.request_info["reply_channel"] = self.reply_channel
|
||||||
self.last_keepalive = time.time()
|
self.last_keepalive = time.time()
|
||||||
self.factory.protocols[self.reply_channel] = self
|
self.factory.protocols[self.reply_channel] = self
|
||||||
# Send news that this channel is open
|
# Send news that this channel is open
|
||||||
Channel("django.websocket.connect").send(self.request_info)
|
Channel("websocket.connect").send(self.request_info)
|
||||||
|
|
||||||
def onMessage(self, payload, isBinary):
|
def onMessage(self, payload, isBinary):
|
||||||
if isBinary:
|
if isBinary:
|
||||||
Channel("django.websocket.receive").send(dict(
|
Channel("websocket.receive").send(dict(
|
||||||
self.request_info,
|
self.request_info,
|
||||||
content = payload,
|
content = payload,
|
||||||
binary = True,
|
binary = True,
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
Channel("django.websocket.receive").send(dict(
|
Channel("websocket.receive").send(dict(
|
||||||
self.request_info,
|
self.request_info,
|
||||||
content = payload.decode("utf8"),
|
content = payload.decode("utf8"),
|
||||||
binary = False,
|
binary = False,
|
||||||
|
@ -62,13 +62,13 @@ class InterfaceProtocol(WebSocketServerProtocol):
|
||||||
def onClose(self, wasClean, code, reason):
|
def onClose(self, wasClean, code, reason):
|
||||||
if hasattr(self, "reply_channel"):
|
if hasattr(self, "reply_channel"):
|
||||||
del self.factory.protocols[self.reply_channel]
|
del self.factory.protocols[self.reply_channel]
|
||||||
Channel("django.websocket.disconnect").send(self.request_info)
|
Channel("websocket.disconnect").send(self.request_info)
|
||||||
|
|
||||||
def sendKeepalive(self):
|
def sendKeepalive(self):
|
||||||
"""
|
"""
|
||||||
Sends a keepalive packet on the keepalive channel.
|
Sends a keepalive packet on the keepalive channel.
|
||||||
"""
|
"""
|
||||||
Channel("django.websocket.keepalive").send(self.request_info)
|
Channel("websocket.keepalive").send(self.request_info)
|
||||||
self.last_keepalive = time.time()
|
self.last_keepalive = time.time()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class WSGIInterface(WSGIHandler):
|
||||||
super(WSGIInterface, self).__init__(*args, **kwargs)
|
super(WSGIInterface, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def get_response(self, request):
|
def get_response(self, request):
|
||||||
request.reply_channel = Channel.new_name("django.wsgi.response")
|
request.reply_channel = Channel.new_name("http.response")
|
||||||
Channel("django.wsgi.request", channel_backend=self.channel_backend).send(request.channel_encode())
|
Channel("http.request", channel_backend=self.channel_backend).send(request.channel_encode())
|
||||||
channel, message = self.channel_backend.receive_many_blocking([request.reply_channel])
|
channel, message = self.channel_backend.receive_many_blocking([request.reply_channel])
|
||||||
return HttpResponse.channel_decode(message)
|
return HttpResponse.channel_decode(message)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.http.cookie import SimpleCookie
|
|
||||||
from six import PY3
|
from six import PY3
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +11,7 @@ def encode_response(response):
|
||||||
"content": response.content,
|
"content": response.content,
|
||||||
"status_code": response.status_code,
|
"status_code": response.status_code,
|
||||||
"headers": list(response._headers.values()),
|
"headers": list(response._headers.values()),
|
||||||
"cookies": {k: v.output(header="") for k, v in response.cookies.items()}
|
"cookies": [v.output(header="") for _, v in response.cookies.items()]
|
||||||
}
|
}
|
||||||
if PY3:
|
if PY3:
|
||||||
value["content"] = value["content"].decode('utf8')
|
value["content"] = value["content"].decode('utf8')
|
||||||
|
@ -29,9 +28,9 @@ def decode_response(value):
|
||||||
content_type = value['content_type'],
|
content_type = value['content_type'],
|
||||||
status = value['status_code'],
|
status = value['status_code'],
|
||||||
)
|
)
|
||||||
for cookie in value['cookies'].values():
|
for cookie in value['cookies']:
|
||||||
response.cookies.load(cookie)
|
response.cookies.load(cookie)
|
||||||
response._headers = {k.lower: (k, v) for k, v in value['headers']}
|
response._headers = {k.lower(): (k, v) for k, v in value['headers']}
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ and producers running in different processes or on different machines.
|
||||||
|
|
||||||
Inside a network, we identify channels uniquely by a name string - you can
|
Inside a network, we identify channels uniquely by a name string - you can
|
||||||
send to any named channel from any machine connected to the same channel
|
send to any named channel from any machine connected to the same channel
|
||||||
backend. If two different machines both write to the ``django.wsgi.request``
|
backend. If two different machines both write to the ``http.request``
|
||||||
channel, they're writing into the same channel.
|
channel, they're writing into the same channel.
|
||||||
|
|
||||||
How do we use channels?
|
How do we use channels?
|
||||||
|
@ -102,12 +102,12 @@ slightly more complex abstraction than that presented by Django views.
|
||||||
A view takes a request and returns a response; a consumer takes a channel
|
A view takes a request and returns a response; a consumer takes a channel
|
||||||
message and can write out zero to many other channel messages.
|
message and can write out zero to many other channel messages.
|
||||||
|
|
||||||
Now, let's make a channel for requests (called ``django.wsgi.request``),
|
Now, let's make a channel for requests (called ``http.request``),
|
||||||
and a channel per client for responses (e.g. ``django.wsgi.response.o4F2h2Fd``),
|
and a channel per client for responses (e.g. ``http.response.o4F2h2Fd``),
|
||||||
with the response channel a property (``reply_channel``) of the request message.
|
with the response channel a property (``reply_channel``) of the request message.
|
||||||
Suddenly, a view is merely another example of a consumer::
|
Suddenly, a view is merely another example of a consumer::
|
||||||
|
|
||||||
# Listens on django.wsgi.request.
|
# Listens on http.request
|
||||||
def my_consumer(message):
|
def my_consumer(message):
|
||||||
# Decode the request from JSON-compat to a full object
|
# Decode the request from JSON-compat to a full object
|
||||||
django_request = Request.decode(message.content)
|
django_request = Request.decode(message.content)
|
||||||
|
@ -154,7 +154,7 @@ to the channel server they're listening on.
|
||||||
|
|
||||||
For this reason, Channels treats these as two different *channel types*, and
|
For this reason, Channels treats these as two different *channel types*, and
|
||||||
denotes a *response channel* by having the first character of the channel name
|
denotes a *response channel* by having the first character of the channel name
|
||||||
be the character ``!`` - e.g. ``!django.wsgi.response.f5G3fE21f``. *Normal
|
be the character ``!`` - e.g. ``!http.response.f5G3fE21f``. *Normal
|
||||||
channels* have no special prefix, but along with the rest of the response
|
channels* have no special prefix, but along with the rest of the response
|
||||||
channel name, they must contain only the characters ``a-z A-Z 0-9 - _``,
|
channel name, they must contain only the characters ``a-z A-Z 0-9 - _``,
|
||||||
and be less than 200 characters long.
|
and be less than 200 characters long.
|
||||||
|
@ -186,14 +186,14 @@ set of channels (here, using Redis) to send updates to::
|
||||||
content=instance.content,
|
content=instance.content,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Connected to django.websocket.connect
|
# Connected to websocket.connect
|
||||||
def ws_connect(message):
|
def ws_connect(message):
|
||||||
# Add to reader set
|
# Add to reader set
|
||||||
redis_conn.sadd("readers", message.reply_channel.name)
|
redis_conn.sadd("readers", message.reply_channel.name)
|
||||||
|
|
||||||
While this will work, there's a small problem - we never remove people from
|
While this will work, there's a small problem - we never remove people from
|
||||||
the ``readers`` set when they disconnect. We could add a consumer that
|
the ``readers`` set when they disconnect. We could add a consumer that
|
||||||
listens to ``django.websocket.disconnect`` to do that, but we'd also need to
|
listens to ``websocket.disconnect`` to do that, but we'd also need to
|
||||||
have some kind of expiry in case an interface server is forced to quit or
|
have some kind of expiry in case an interface server is forced to quit or
|
||||||
loses power before it can send disconnect signals - your code will never
|
loses power before it can send disconnect signals - your code will never
|
||||||
see any disconnect notification but the response channel is completely
|
see any disconnect notification but the response channel is completely
|
||||||
|
@ -222,7 +222,7 @@ we don't need to; Channels has it built in, as a feature called Groups::
|
||||||
content=instance.content,
|
content=instance.content,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Connected to django.websocket.connect and django.websocket.keepalive
|
# Connected to websocket.connect and websocket.keepalive
|
||||||
def ws_connect(message):
|
def ws_connect(message):
|
||||||
# Add to reader group
|
# Add to reader group
|
||||||
Group("liveblog").add(message.reply_channel)
|
Group("liveblog").add(message.reply_channel)
|
||||||
|
|
|
@ -12,7 +12,7 @@ First Consumers
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Now, by default, Django will run things through Channels but it will also
|
Now, by default, Django will run things through Channels but it will also
|
||||||
tie in the URL router and view subsystem to the default ``django.wsgi.request``
|
tie in the URL router and view subsystem to the default ``http.request``
|
||||||
channel if you don't provide another consumer that listens to it - remember,
|
channel if you don't provide another consumer that listens to it - remember,
|
||||||
only one consumer can listen to any given channel.
|
only one consumer can listen to any given channel.
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ custom consumer we wrote above. Here's what that looks like::
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "channels.backends.database.DatabaseChannelBackend",
|
"BACKEND": "channels.backends.database.DatabaseChannelBackend",
|
||||||
"ROUTING": {
|
"ROUTING": {
|
||||||
"django.wsgi.request": "myproject.myapp.consumers.http_consumer",
|
"http.request": "myproject.myapp.consumers.http_consumer",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -74,19 +74,19 @@ serve HTTP requests from now on - and make this WebSocket consumer instead::
|
||||||
def ws_add(message):
|
def ws_add(message):
|
||||||
Group("chat").add(message.reply_channel)
|
Group("chat").add(message.reply_channel)
|
||||||
|
|
||||||
Hook it up to the ``django.websocket.connect`` channel like this::
|
Hook it up to the ``websocket.connect`` channel like this::
|
||||||
|
|
||||||
CHANNEL_BACKENDS = {
|
CHANNEL_BACKENDS = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "channels.backends.database.DatabaseChannelBackend",
|
"BACKEND": "channels.backends.database.DatabaseChannelBackend",
|
||||||
"ROUTING": {
|
"ROUTING": {
|
||||||
"django.websocket.connect": "myproject.myapp.consumers.ws_add",
|
"websocket.connect": "myproject.myapp.consumers.ws_add",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Now, let's look at what this is doing. It's tied to the
|
Now, let's look at what this is doing. It's tied to the
|
||||||
``django.websocket.connect`` channel, which means that it'll get a message
|
``websocket.connect`` channel, which means that it'll get a message
|
||||||
whenever a new WebSocket connection is opened by a client.
|
whenever a new WebSocket connection is opened by a client.
|
||||||
|
|
||||||
When it gets that message, it takes the ``reply_channel`` attribute from it, which
|
When it gets that message, it takes the ``reply_channel`` attribute from it, which
|
||||||
|
@ -100,12 +100,12 @@ don't keep track of the open/close states of the potentially thousands of
|
||||||
connections you have open at any one time.
|
connections you have open at any one time.
|
||||||
|
|
||||||
The solution to this is that the WebSocket interface servers will send
|
The solution to this is that the WebSocket interface servers will send
|
||||||
periodic "keepalive" messages on the ``django.websocket.keepalive`` channel,
|
periodic "keepalive" messages on the ``websocket.keepalive`` channel,
|
||||||
so we can hook that up to re-add the channel (it's safe to add the channel to
|
so we can hook that up to re-add the channel (it's safe to add the channel to
|
||||||
a group it's already in - similarly, it's safe to discard a channel from a
|
a group it's already in - similarly, it's safe to discard a channel from a
|
||||||
group it's not in)::
|
group it's not in)::
|
||||||
|
|
||||||
# Connected to django.websocket.keepalive
|
# Connected to websocket.keepalive
|
||||||
def ws_keepalive(message):
|
def ws_keepalive(message):
|
||||||
Group("chat").add(message.reply_channel)
|
Group("chat").add(message.reply_channel)
|
||||||
|
|
||||||
|
@ -114,8 +114,8 @@ just route both channels to the same consumer::
|
||||||
|
|
||||||
...
|
...
|
||||||
"ROUTING": {
|
"ROUTING": {
|
||||||
"django.websocket.connect": "myproject.myapp.consumers.ws_add",
|
"websocket.connect": "myproject.myapp.consumers.ws_add",
|
||||||
"django.websocket.keepalive": "myproject.myapp.consumers.ws_add",
|
"websocket.keepalive": "myproject.myapp.consumers.ws_add",
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ And, even though channels will expire out, let's add an explicit ``disconnect``
|
||||||
handler to clean up as people disconnect (most channels will cleanly disconnect
|
handler to clean up as people disconnect (most channels will cleanly disconnect
|
||||||
and get this called)::
|
and get this called)::
|
||||||
|
|
||||||
# Connected to django.websocket.disconnect
|
# Connected to websocket.disconnect
|
||||||
def ws_disconnect(message):
|
def ws_disconnect(message):
|
||||||
Group("chat").discard(message.reply_channel)
|
Group("chat").discard(message.reply_channel)
|
||||||
|
|
||||||
|
@ -134,15 +134,15 @@ any message sent in to all connected clients. Here's all the code::
|
||||||
|
|
||||||
from channels import Channel, Group
|
from channels import Channel, Group
|
||||||
|
|
||||||
# Connected to django.websocket.connect and django.websocket.keepalive
|
# Connected to websocket.connect and websocket.keepalive
|
||||||
def ws_add(message):
|
def ws_add(message):
|
||||||
Group("chat").add(message.reply_channel)
|
Group("chat").add(message.reply_channel)
|
||||||
|
|
||||||
# Connected to django.websocket.receive
|
# Connected to websocket.receive
|
||||||
def ws_message(message):
|
def ws_message(message):
|
||||||
Group("chat").send(message.content)
|
Group("chat").send(message.content)
|
||||||
|
|
||||||
# Connected to django.websocket.disconnect
|
# Connected to websocket.disconnect
|
||||||
def ws_disconnect(message):
|
def ws_disconnect(message):
|
||||||
Group("chat").discard(message.reply_channel)
|
Group("chat").discard(message.reply_channel)
|
||||||
|
|
||||||
|
@ -152,10 +152,10 @@ And what our routing should look like in ``settings.py``::
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "channels.backends.database.DatabaseChannelBackend",
|
"BACKEND": "channels.backends.database.DatabaseChannelBackend",
|
||||||
"ROUTING": {
|
"ROUTING": {
|
||||||
"django.websocket.connect": "myproject.myapp.consumers.ws_add",
|
"websocket.connect": "myproject.myapp.consumers.ws_add",
|
||||||
"django.websocket.keepalive": "myproject.myapp.consumers.ws_add",
|
"websocket.keepalive": "myproject.myapp.consumers.ws_add",
|
||||||
"django.websocket.receive": "myproject.myapp.consumers.ws_message",
|
"websocket.receive": "myproject.myapp.consumers.ws_message",
|
||||||
"django.websocket.disconnect": "myproject.myapp.consumers.ws_disconnect",
|
"websocket.disconnect": "myproject.myapp.consumers.ws_disconnect",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -332,7 +332,7 @@ 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 channel_session
|
from channels.decorators import channel_session
|
||||||
|
|
||||||
# Connected to django.websocket.connect
|
# Connected to websocket.connect
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_connect(message):
|
def ws_connect(message):
|
||||||
# Work out room name from path (ignore slashes)
|
# Work out room name from path (ignore slashes)
|
||||||
|
@ -341,17 +341,17 @@ name in the path of your WebSocket request (we'll ignore auth for now)::
|
||||||
message.channel_session['room'] = room
|
message.channel_session['room'] = room
|
||||||
Group("chat-%s" % room).add(message.reply_channel)
|
Group("chat-%s" % room).add(message.reply_channel)
|
||||||
|
|
||||||
# Connected to django.websocket.keepalive
|
# Connected to websocket.keepalive
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_add(message):
|
def ws_add(message):
|
||||||
Group("chat-%s" % message.channel_session['room']).add(message.reply_channel)
|
Group("chat-%s" % message.channel_session['room']).add(message.reply_channel)
|
||||||
|
|
||||||
# Connected to django.websocket.receive
|
# Connected to websocket.receive
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_message(message):
|
def ws_message(message):
|
||||||
Group("chat-%s" % message.channel_session['room']).send(content)
|
Group("chat-%s" % message.channel_session['room']).send(content)
|
||||||
|
|
||||||
# Connected to django.websocket.disconnect
|
# Connected to websocket.disconnect
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_disconnect(message):
|
def ws_disconnect(message):
|
||||||
Group("chat-%s" % message.channel_session['room']).discard(message.reply_channel)
|
Group("chat-%s" % message.channel_session['room']).discard(message.reply_channel)
|
||||||
|
@ -400,7 +400,7 @@ have a ChatMessage model with ``message`` and ``room`` fields::
|
||||||
"content": message.content['message'],
|
"content": message.content['message'],
|
||||||
})
|
})
|
||||||
|
|
||||||
# Connected to django.websocket.connect
|
# Connected to websocket.connect
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_connect(message):
|
def ws_connect(message):
|
||||||
# Work out room name from path (ignore slashes)
|
# Work out room name from path (ignore slashes)
|
||||||
|
@ -409,12 +409,12 @@ have a ChatMessage model with ``message`` and ``room`` fields::
|
||||||
message.channel_session['room'] = room
|
message.channel_session['room'] = room
|
||||||
Group("chat-%s" % room).add(message.reply_channel)
|
Group("chat-%s" % room).add(message.reply_channel)
|
||||||
|
|
||||||
# Connected to django.websocket.keepalive
|
# Connected to websocket.keepalive
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_add(message):
|
def ws_add(message):
|
||||||
Group("chat-%s" % message.channel_session['room']).add(message.reply_channel)
|
Group("chat-%s" % message.channel_session['room']).add(message.reply_channel)
|
||||||
|
|
||||||
# Connected to django.websocket.receive
|
# Connected to websocket.receive
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_message(message):
|
def ws_message(message):
|
||||||
# Stick the message onto the processing queue
|
# Stick the message onto the processing queue
|
||||||
|
@ -423,7 +423,7 @@ have a ChatMessage model with ``message`` and ``room`` fields::
|
||||||
"message": content,
|
"message": content,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Connected to django.websocket.disconnect
|
# Connected to websocket.disconnect
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_disconnect(message):
|
def ws_disconnect(message):
|
||||||
Group("chat-%s" % message.channel_session['room']).discard(message.reply_channel)
|
Group("chat-%s" % message.channel_session['room']).discard(message.reply_channel)
|
||||||
|
|
|
@ -2,13 +2,27 @@ Message Standards
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Some standardised message formats are used for common message types - they
|
Some standardised message formats are used for common message types - they
|
||||||
are detailed below.
|
are detailed below. Message formats are meant to be generic and offload as
|
||||||
|
much protocol-specific processing to the interface server as is reasonable;
|
||||||
|
thus, they should generally represent things at as high a level as makes sense.
|
||||||
|
|
||||||
Note: All consumers also receive the channel name as the keyword argument
|
In addition to the standards outlined below, each message may contain a
|
||||||
"channel", so there is no need for separate type information to let
|
``reply_channel``, which details where to send responses. Protocols with
|
||||||
multi-channel consumers distinguish.
|
separate connection and data receiving messages (like WebSockets) will only
|
||||||
|
contain the connection and detailed client information in the first message;
|
||||||
|
use the ``@channel_session`` decorator to persist this data to consumers of
|
||||||
|
the received data (the decorator will take care of handling persistence and
|
||||||
|
ordering guarantees on messages).
|
||||||
|
|
||||||
The length limit on channel names will be 200 characters.
|
All messages must be able to be encoded as JSON; channel backends don't
|
||||||
|
necessarily have to use JSON, but we consider it the lowest common denominator
|
||||||
|
for serialisation format compatability.
|
||||||
|
|
||||||
|
The size limit on messages is 1MB (while channel backends may support larger
|
||||||
|
sizes, all message formats should stay under this limit, which might include
|
||||||
|
multi-part messages where large content must be transferred).
|
||||||
|
|
||||||
|
The length limit on channel names is 200 printable ASCII characters.
|
||||||
|
|
||||||
|
|
||||||
HTTP Request
|
HTTP Request
|
||||||
|
@ -16,29 +30,45 @@ HTTP Request
|
||||||
|
|
||||||
Represents a full-fledged, single HTTP request coming in from a client.
|
Represents a full-fledged, single HTTP request coming in from a client.
|
||||||
|
|
||||||
|
Standard channel name is ``http.request``.
|
||||||
|
|
||||||
Contains the following keys:
|
Contains the following keys:
|
||||||
|
|
||||||
* GET: List of (key, value) tuples of GET variables
|
* GET: List of (key, value) tuples of GET variables (keys and values are strings)
|
||||||
* POST: List of (key, value) tuples of POST variables
|
* POST: List of (key, value) tuples of POST variables (keys and values are strings)
|
||||||
* COOKIES: Same as ``request.COOKIES``
|
* COOKIES: Dict of cookies as {cookie_name: cookie_value} (names and values are strings)
|
||||||
* META: Same as ``request.META``
|
* META: Dict of HTTP headers and info as defined in the Django Request docs (names and values are strings)
|
||||||
* path: Same as ``request.path``
|
* path: String, full path to the requested page, without query string or domain
|
||||||
* path_info: Same as ``request.path_info``
|
* path_info: String, like ``path`` but without any script prefix. Often just ``path``.
|
||||||
* method: Upper-cased HTTP method
|
* method: String, upper-cased HTTP method
|
||||||
* response_channel: Channel name to write response to
|
|
||||||
|
Should come with an associated ``reply_channel`` which accepts HTTP Responses.
|
||||||
|
|
||||||
|
|
||||||
HTTP Response
|
HTTP Response
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Sends a whole response to a client.
|
Sends either a part of a response or a whole response to a HTTP client - to do
|
||||||
|
streaming responses, several response messages are sent with ``more_content: True``
|
||||||
|
and the final one has the key omitted. Normal, single-shot responses do not
|
||||||
|
need the key at all.
|
||||||
|
|
||||||
Contains the following keys:
|
Due to the 1MB size limit on messages, some larger responses will have to be
|
||||||
|
sent multi-part to stay within the limit.
|
||||||
|
|
||||||
|
Only sent on reply channels.
|
||||||
|
|
||||||
|
Keys that must only be in the first message of a set:
|
||||||
|
|
||||||
|
* content_type: String, mimetype of content
|
||||||
|
* status_code: Integer, numerical HTTP status code
|
||||||
|
* cookies: List of cookies to set (as encoded cookie strings suitable for headers)
|
||||||
|
* headers: Dictionary of headers (key is header name, value is value, both strings)
|
||||||
|
|
||||||
|
All messages in a set can the following keys:
|
||||||
|
|
||||||
* content: String of content to send
|
* content: String of content to send
|
||||||
* content_type: Mimetype of content
|
* more_content: Boolean, signals the interface server should wait for another response chunk to stream.
|
||||||
* status_code: Numerical HTTP status code
|
|
||||||
* headers: Dictionary of headers (key is header name, value is value)
|
|
||||||
|
|
||||||
|
|
||||||
HTTP Disconnect
|
HTTP Disconnect
|
||||||
|
@ -47,7 +77,9 @@ HTTP Disconnect
|
||||||
Send when a client disconnects early, before the response has been sent.
|
Send when a client disconnects early, before the response has been sent.
|
||||||
Only sent by long-polling-capable HTTP interface servers.
|
Only sent by long-polling-capable HTTP interface servers.
|
||||||
|
|
||||||
Contains the same keys as HTTP Request.
|
Standard channel name is ``http.disconnect``.
|
||||||
|
|
||||||
|
Contains no keys.
|
||||||
|
|
||||||
|
|
||||||
WebSocket Connection
|
WebSocket Connection
|
||||||
|
@ -55,14 +87,9 @@ WebSocket Connection
|
||||||
|
|
||||||
Sent when a new WebSocket is connected.
|
Sent when a new WebSocket is connected.
|
||||||
|
|
||||||
Contains the following keys:
|
Standard channel name is ``websocket.connect``.
|
||||||
|
|
||||||
* GET: List of (key, value) tuples of GET variables
|
Contains the same keys as HTTP Request, without the ``POST`` or ``method`` keys.
|
||||||
* COOKIES: Same as ``request.COOKIES``
|
|
||||||
* META: Same as ``request.META``
|
|
||||||
* path: Same as ``request.path``
|
|
||||||
* path_info: Same as ``request.path_info``
|
|
||||||
* reply_channel: Channel name to send responses on
|
|
||||||
|
|
||||||
|
|
||||||
WebSocket Receive
|
WebSocket Receive
|
||||||
|
@ -70,10 +97,12 @@ WebSocket Receive
|
||||||
|
|
||||||
Sent when a datagram is received on the WebSocket.
|
Sent when a datagram is received on the WebSocket.
|
||||||
|
|
||||||
Contains the same keys as WebSocket Connection, plus:
|
Standard channel name is ``websocket.receive``.
|
||||||
|
|
||||||
* content: String content of the datagram
|
Contains the following keys:
|
||||||
* binary: If the content is to be interpreted as text or binary
|
|
||||||
|
* content: String content of the datagram.
|
||||||
|
* binary: Boolean, saying if the content is binary. If not present or false, content is a UTF8 string.
|
||||||
|
|
||||||
|
|
||||||
WebSocket Client Close
|
WebSocket Client Close
|
||||||
|
@ -81,25 +110,22 @@ WebSocket Client Close
|
||||||
|
|
||||||
Sent when the WebSocket is closed by either the client or the server.
|
Sent when the WebSocket is closed by either the client or the server.
|
||||||
|
|
||||||
Contains the same keys as WebSocket Connection, including reply_channel,
|
Standard channel name is ``websocket.disconnect``.
|
||||||
though nothing should be sent on it.
|
|
||||||
|
Contains no keys.
|
||||||
|
|
||||||
|
|
||||||
WebSocket Send
|
WebSocket Send/Close
|
||||||
--------------
|
--------------------
|
||||||
|
|
||||||
Sent by a Django consumer to send a message back over the WebSocket to
|
Sent by a Django consumer to send a message back over the WebSocket to
|
||||||
the client.
|
the client or close the client connection. The content is optional if close
|
||||||
|
is set, and close will happen after any content is sent, if some is present.
|
||||||
|
|
||||||
|
Only sent on reply channels.
|
||||||
|
|
||||||
Contains the keys:
|
Contains the keys:
|
||||||
|
|
||||||
* content: String content of the datagram
|
* content: String content of the datagram.
|
||||||
* binary: If the content is to be interpreted as text or binary
|
* binary: If the content is to be interpreted as text or binary.
|
||||||
|
* close: Boolean. If set to True, will close the client connection.
|
||||||
|
|
||||||
WebSocket Server Close
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Sent by a Django consumer to close the client's WebSocket.
|
|
||||||
|
|
||||||
Contains no keys.
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user