django / channels Goto Github PK
View Code? Open in Web Editor NEWDeveloper-friendly asynchrony for Django
Home Page: https://channels.readthedocs.io
License: BSD 3-Clause "New" or "Revised" License
Developer-friendly asynchrony for Django
Home Page: https://channels.readthedocs.io
License: BSD 3-Clause "New" or "Revised" License
Rather than just printing them out.
Running tox
from the commandline or Travis CI results in failures in most or all python/django version combinations.
See https://travis-ci.org/DanLipsitt/channels/builds/102221657 for log.
I've submitted PR #65 to create a Travis config for the project so these issues are more visible.
Just for the conversation and to poll interest, would it be possible to allow the use of messagepack as an alternative to json encoding?
http://msgpack.org/
Messagepack (or msgpack
) is a compact json protocol where values like true
or «file element list» are encoded so the final and global value size is reduced.
There is a good python encoder and it could improve channel performance overall.
I will consider doing this myself but I would love some feedback to know if it is interesting or just some crazy idea.
We migrated from channels 0.8 to 0.9.x (currently on master).
(So maybe I missed sth. that changed from 0.8 to 0.9.x)
Daphne is updated and on master too.
Django 1.9.4
Python 3.4.3
runserver with --noasgi works as expected.
but with asgi every websocket connection results in:
File "/usr/local/lib/python3.4/dist-packages/twisted/python/log.py", line 101, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/local/lib/python3.4/dist-packages/twisted/python/log.py", line 84, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/local/lib/python3.4/dist-packages/twisted/python/context.py", line 118, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/local/lib/python3.4/dist-packages/twisted/python/context.py", line 81, in callWithContext
return func(*args,**kw)
--- <exception caught here> ---
File "/usr/local/lib/python3.4/dist-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
why = selectable.doRead()
File "/usr/local/lib/python3.4/dist-packages/twisted/internet/tcp.py", line 209, in doRead
return self._dataReceived(data)
File "/usr/local/lib/python3.4/dist-packages/twisted/internet/tcp.py", line 215, in _dataReceived
rval = self.protocol.dataReceived(data)
File "/usr/local/lib/python3.4/dist-packages/twisted/protocols/basic.py", line 571, in dataReceived
why = self.lineReceived(line)
File "/usr/local/lib/python3.4/dist-packages/twisted/web/http.py", line 1720, in lineReceived
self.allContentReceived()
File "/usr/local/lib/python3.4/dist-packages/twisted/web/http.py", line 1799, in allContentReceived
req.requestReceived(command, path, version)
File "/usr/local/lib/python3.4/dist-packages/twisted/web/http.py", line 832, in requestReceived
self.process()
File "/usr/local/lib/python3.4/dist-packages/daphne/http_protocol.py", line 67, in process
protocol = self.factory.ws_factory.buildProtocol(self.transport.getPeer())
File "/usr/local/lib/python3.4/dist-packages/twisted/internet/protocol.py", line 135, in buildProtocol
p = self.protocol()
File "/usr/local/lib/python3.4/dist-packages/autobahn/websocket/protocol.py", line 665, in __init__
self.is_closed = txaio.create_future()
File "/usr/local/lib/python3.4/dist-packages/txaio/_unframework.py", line 43, in _throw_usage_error
"To use txaio, you must first select a framework "
builtins.RuntimeError: To use txaio, you must first select a framework with .use_twisted() or .use_asyncio()
How can we set use_twisted() or use_asyncio() ?
Daphne seems to require twisted. Why use twisted if there is asyncio (py3.4+)?
I'm very new. I like to fire message from view. How to do that ?
After finishing Running with Channels
I checked with javascript socket.send("hello world")
and its working but what I want is using python how to send ?
i.e)
def bot_submit(request):
bot_result = request.POST
# I need bot_result content on frontend how to do that ?
return HttpResponse('ok')
After the initial discussion on django-developers, and with django-channels progressing but not yet in django itself. Is there a preferred location for discussing django-channels or since the plan is to move django-channels into django itself, should the discussion just take place in django-developers?
Especially large ones, that won't fit in the 1MB message limit. Not sure they can be chunked like the responses can, given that would need perfect ordering.
Since the core of channels are JSON messages it'd be cool if we could swap the JSON encoder of the default backends.
My use-case for this is using an encoder that supports inlining the bytes of a pre-encoded JSON objects into a larger dynamic JSON structure (we use metamagic.json
package). This saves a cubic ton of CPU cycles on JSON decoding/encoding if you re-use a lot of cachable sub-structures.
Anyway, maybe a json.dumps
setting would be good, like a importable path to a callable (defaulting to standard json.dumps
). Alternately we could override the default backends but that's a bit too much.
A bonus this also saves the project from the endless json/simplejson/ujson/whateverfastestjsonoftheday debates. 😉
In the master branch, channels.backends.database.DatabaseChannelBackend
inherits from BaseChannelBackend
, which appears not to exist anymore.
create a universal wheel distribution
Likely via a new interface server - perhaps one that can also support WebSockets and HTTP1 all in one big go. Needs some research into the current state of python HTTP2 support.
A redis://
URL is a great shorthand for redis hostname & port settings, and it can easily be stored in an environment variable. It's very handy for Docker/Dokku deployments and is used in other Django + redis libraries (Celery, django-redis)
Rather than:
...
"HOSTS": [("redis-channel-1", 6379), ("redis-channel-2", 6379)],
...
It would look like this:
...
"HOSTS": ["redis://redis-channel-1:6379/0", "redis://redis-channel-2:6379/0"],
...
Which crashes with the following stack trace:
Traceback:
File "path/venv/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
223. response = middleware_method(request, response)
File "path/venv/lib/python3.5/site-packages/debug_toolbar/middleware.py" in process_response
131. bits[-2] += toolbar.render_toolbar()
File "path/venv/lib/python3.5/site-packages/debug_toolbar/toolbar.py" in render_toolbar
60. if not self.should_render_panels():
File "path/venv/lib/python3.5/site-packages/debug_toolbar/toolbar.py" in should_render_panels
81. render_panels = self.request.META['wsgi.multiprocess']
Exception Type: KeyError at /api/v1/path
Exception Value: 'wsgi.multiprocess'
Plus chunking for large responses to keep messages under a megabyte. Already spec'd out, just needs support in the request encoder and decoder.
I love this project! It solves a couple of big problems I've been having.
This is a nit, but when specifying the redis backend, the current docs say:
CHANNEL_BACKENDS = {
"default": {
"BACKEND": "channels.backends.redis.RedisChannelBackend",
I had to use:
"BACKEND": "channels.backends.redis_py.RedisChannelBackend",
Adding stuff to registries as an import-time side-effect of decorators is an anti-pattern. It impedes testability, and it causes behavior changes depending on which modules have been imported.
Django already contains this anti-pattern (for signals and for admin, and in even more convoluted fashion for models), and django-channels requires expanding it to even more modules in order to catch decorated consumers.
I think there are two better options:
Relying an decorators and import side effects for signal registration has been deprecated in favor of explicitly registering signal handlers in AppConfig.ready
. The same technique could be recommended here (instead of using decorators).
If the convenience of a decorator is important, we could rely on the venusian package (http://venusian.readthedocs.org/en/latest/), which solves this problem. A venusian-based decorator doesn't have any side effects, all it does is annotate the decorated function with some metadata. Then you run a venusian "scan" at a well-defined point in your code, which walks the module tree and imports all modules, looking for functions which have been annotated with venusian metadata and running a callback on them. That callback can do whatever needs to be done (e.g. put the function in a registry). This avoids import-time side effects and changes in behavior depending on the timing of module imports. All modules are checked for decorated functions, and the scan happens at a clearly-defined point (which would fit in well with the new django.setup()
in 1.7+). Venusian is a solid and battle-tested solution to this problem (all decorators in the Pyramid web framework use it).
Environment:
Request Method: GET
Request URL: http://localhost:8000/admin/jsi18n/
Django Version: 1.9.4
Python Version: 3.5.1
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
149. response = self.process_exception_by_middleware(e, request)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/channels/handler.py" in process_exception_by_middleware
194. return super(AsgiHandler, self).process_exception_by_middleware(exception, request)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
147. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/contrib/admin/sites.py" in wrapper
265. return self.admin_view(view, cacheable)(*args, **kwargs)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/utils/decorators.py" in _wrapped_view
149. response = view_func(request, *args, **kwargs)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/contrib/admin/sites.py" in inner
244. return view(request, *args, **kwargs)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/contrib/admin/sites.py" in i18n_javascript
359. return javascript_catalog(request, packages=['django.conf', 'django.contrib.admin'])
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/views/i18n.py" in javascript_catalog
326. locale = _get_locale(request)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/views/i18n.py" in _get_locale
294. return to_locale(language)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/utils/translation/__init__.py" in to_locale
195. return _trans.to_locale(language)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/utils/translation/trans_real.py" in to_locale
71. p = language.find('-')
Exception Type: AttributeError at /admin/jsi18n/
Exception Value: 'NoneType' object has no attribute 'find'
Environment
Python 3.5.1
django==1.9.4
channels==0.9.5
Error processing message with consumer <channels.adapters.UrlConsumer object at 0x7f9d09c81f10>:
Traceback (most recent call last):
File "/home/yyy/xxx/local/lib/python2.7/site-packages/channels/worker.py", line 34, in run
consumer(message)
File "/home/yyy/xxx/local/lib/python2.7/site-packages/channels/adapters.py", line 24, in call
message.reply_channel.send(response.channel_encode())
File "/home/yyy/xxx/local/lib/python2.7/site-packages/channels/response.py", line 11, in encode_response
"content": response.content,
File "/home/yyy/xxx/local/lib/python2.7/site-packages/django/http/response.py", line 409, in content
"Use streaming_content
instead." % self.class.name)
AttributeError: This FileResponse instance has no content
attribute. Use streaming_content
instead.
Pardon - I accidentally hit CTRL + Return and submitted this without info...
With default settings for the http.request
channel, when I try to log into the admin using my test user whose username and password are both admin
, I sometimes run into this situation where I can't login, no matter how many times I enter or copy/paste the username / password in. I can hard-refresh the page, ensuring there isn't a cached version of CSRF or something fishy going on. The funny part is that is actually logging me in, but then redirecting me back to the login screen immediately thereafter.
This is me trying over and over again, to see if perhaps this was some sort of "client needs to connect to the same process on the GET after the POST login" type of bug:
[2016/03/13 15:48:37] HTTP POST /admin/login/ 302 [0.10, 127.0.0.1:53134]
[2016/03/13 15:48:37] HTTP GET /admin/ 302 [0.05, 127.0.0.1:53134]
[2016/03/13 15:48:37] HTTP GET /admin/login/ 200 [0.04, 127.0.0.1:53134]
[2016/03/13 15:48:42] HTTP POST /admin/login/ 302 [0.10, 127.0.0.1:53134]
[2016/03/13 15:48:42] HTTP GET /admin/ 302 [0.05, 127.0.0.1:53134]
[2016/03/13 15:48:42] HTTP GET /admin/login/ 200 [0.04, 127.0.0.1:53134]
[2016/03/13 15:48:53] HTTP POST /admin/login/ 302 [0.10, 127.0.0.1:53134]
[2016/03/13 15:48:53] HTTP GET /admin/ 302 [0.05, 127.0.0.1:53134]
[2016/03/13 15:48:53] HTTP GET /admin/login/ 200 [0.05, 127.0.0.1:53134]
[2016/03/13 15:48:58] HTTP POST /admin/login/ 302 [0.10, 127.0.0.1:53134]
[2016/03/13 15:48:58] HTTP GET /admin/ 302 [0.05, 127.0.0.1:53134]
[2016/03/13 15:48:58] HTTP GET /admin/login/ 200 [0.05, 127.0.0.1:53134]
[2016/03/13 15:49:01] HTTP POST /admin/login/ 302 [0.10, 127.0.0.1:53134]
[2016/03/13 15:49:01] HTTP GET /admin/ 302 [0.05, 127.0.0.1:53134]
[2016/03/13 15:49:01] HTTP GET /admin/login/ 200 [0.05, 127.0.0.1:53134]
settings.py
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'asgiref.inmemory.ChannelLayer',
'ROUTING': 'spam.routing.channel_routing'
}
}
routing.py
channel_routing = {
'websocket.connect': 'spam.apps.spams.consumers.connect',
'websocket.receive': 'spam.apps.spams.consumers.receive',
'websocket.disconnect': 'spam.apps.spams.consumers.disconnect'
}
Python 3.5.1
django==1.9.4
channels==0.9.5
I just reproduced it with channel_routing = {}
in routing.py
.
I'm not able to reproduce when I remove the CHANNEL_LAYERS
setting.
I noticed during my quick testing of daphne / runworker that there is no automatic support for static files. I know that, in the ideal world, static files are served from a CDN, but over the past few years it's become very common practice to serve static files from your application's front-end server (e.g., using WhiteNoise - also see their IAQ).
With that said, is there a way to serve static in production with Daphne? Or, is that something you'd be interested in merging, if I was to find a reasonable way to add WhiteNoise-like functionality in a fork?
According to this similar thread, this issue might be an "inherent issue with multi-threading." So I'm not sure if it requires attention, but I figured it might be good to put on the radar.
[2016/03/03 17:04:54] WebSocket CONNECT /liveblog [127.0.0.1:62988]
Exception in thread Thread-4:
Traceback (most recent call last):
File "/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/Users/cbodkin/.virtualenvs/p2p-liveblog/lib/python2.7/site-packages/channels/management/commands/runserver.py", line 151, in run
worker.run()
File "/Users/cbodkin/.virtualenvs/p2p-liveblog/lib/python2.7/site-packages/channels/worker.py", line 29, in run
channel, content = self.channel_layer.receive_many(channels, block=True)
File "/Users/cbodkin/.virtualenvs/p2p-liveblog/lib/python2.7/site-packages/asgiref/inmemory.py", line 47, in receive_many
self._clean_expired()
File "/Users/cbodkin/.virtualenvs/p2p-liveblog/lib/python2.7/site-packages/asgiref/inmemory.py", line 109, in _clean_expired
while queue and queue[0][0] < time.time():
IndexError: deque index out of range
I'm currently a bit unhappy with the error handling in the messages.
The websocket connect message for example... any error or exception happening in there will keep the connection open and the client will be able to continue sending messages.
It should be possible to drop the connection attempt by raising permission denied for example or it should fail with a error 500 on other exceptions.
Bastian
I noticed that oauth login was not working with the modified runserver because HttpRequest.build_absolute_uri(location)
(https://docs.djangoproject.com/en/1.9/ref/request-response/#django.http.HttpRequest.build_absolute_uri) cuts all query parameters.
when the expected result ist http://localhost:9000/api/callback/?code=Z7VNafOdj5oYuri2yD1OvKH&state=zEpKuXdqldmo
with the modifed runserver it's only http://localhost:9000/api/callback/
Just curious if channels provides a way to write a custom router/broadcaster that can accept/listen to some protocol other than http and websockets?
I try to transition an existing django app to channel, in dev/debug mode.
Apparently serving static files with the default DatabaseChannelLayer quickly hogs the database, my sqlite file makes a few 10s of Megs only after a few request ( I am serving my static files through django .. default debug/dev mode .. ).
My understanding is that all my static assets ( large js/css app) is copied at each request in the database. Fine . But then daphne fails with : ( purging the database solve this for the next 2 requests ..).
daphne/http_protocol.py", line 136, in serverResponse
raise ValueError("Got multiple Response messages!")
I can see why channels should not be used for static files and a proper production setup will use a proper webserver for static assets, but is there a hidden usable "quick and dirty for dev mode" way of serving static files with channels that I could not see in the help ?
I guess we could have runserver spawning a separate static file server, but at least I think it should be mentionned in the doc somewhere like "DON'T serve statics with channels / DatabaseChannelLayer"
Let me know how I could help.
I upgraded the channels version today. And look like multiple things not working correctly. After reading the docs and I found need to update asgi.py
file and running daphne gives me below error..
(venv)simon@simon-OptiPlex-780:~/Workspace/buildsys$ daphne -b 127.0.0.1 -p 9000 buildsys.asgi:channel_layer
Traceback (most recent call last):
File "/home/simon/Workspace/venv/bin/daphne", line 9, in <module>
load_entry_point('daphne==0.9', 'console_scripts', 'daphne')()
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/daphne/cli.py", line 53, in entrypoint
cls().run(sys.argv[1:])
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/daphne/cli.py", line 74, in run
channel_layer = importlib.import_module(module_path)
File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
File "./buildsys/asgi.py", line 6, in <module>
channel_layer = get_channel_layer()
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/channels/asgi.py", line 83, in get_channel_layer
django.setup(set_prefix=False)
TypeError: setup() takes no arguments (1 given)
And running runserver also gives me below error :>
Unhandled Error
Traceback (most recent call last):
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/channels/management/commands/runserver.py", line 81, in inner_run
action_logger=self.log_action,
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/daphne/server.py", line 23, in run
reactor.run(installSignalHandlers=self.signal_handlers)
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 1194, in run
self.mainLoop()
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 1203, in mainLoop
self.runUntilCurrent()
--- <exception caught here> ---
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 825, in runUntilCurrent
call.func(*call.args, **call.kw)
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/daphne/server.py", line 40, in backend_reader
self.factory.dispatch_reply(channel, message)
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/daphne/http_protocol.py", line 197, in dispatch_reply
self.reply_protocols[channel].serverResponse(message)
File "/home/simon/Workspace/venv/local/lib/python2.7/site-packages/daphne/http_protocol.py", line 136, in serverResponse
raise ValueError("Got multiple Response messages!")
exceptions.ValueError: Got multiple Response messages!
Looks like something is picking up query parameters as lists instead of strings, which is messing up the inbuilt sessions.
For example the session key in the url
localhost:8000?session_key=33tj3gak0cnu0fur11arxga3mklgwa27
is actually getting picked up as "['33tj3gak0cnu0fur11arxga3mklgwa27']"
in the message content instead of "33tj3gak0cnu0fur11arxga3mklgwa27"
.
So when the http_session tries to import from the Session Store it returns an empty session:
session = session_engine.SessionStore(session_key=session_key)
I've had a dig around, but I can't see what actually creates the message.content
so I'm not sure how to troubleshoot this further.
I wonder if it makes sense to seperate the locking and messages backend. I think if you would want to use rabbitmq for example for messages you might still want to use redis or memcache for locking?
Traceback (most recent call last):
File ".../lib/python3.4/site-packages/channels/worker.py", line 34, in run
consumer(message)
File ".../lib/python3.4/site-packages/channels/decorators.py", line 54, in inner
session_key = "skt" + hashlib.md5(reply_name[:-24]).hexdigest()[:8] + reply_name[-24:]
TypeError: Unicode-objects must be encoded before hashing
I'll try to send a merge request for you
Django REST Framework (version 3.3.1) tries to access the _stream
attribute on HttpRequests, which crashes with the following stack trace:
Traceback (most recent call last):
File "path/venv/lib/python3.5/site-packages/rest_framework/request.py", line 357, in __getattribute__
return getattr(self._request, attr)
AttributeError: 'HttpRequest' object has no attribute 'data'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "path/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 132, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "path/venv/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "path/venv/lib/python3.5/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "path/venv/lib/python3.5/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "path/venv/lib/python3.5/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "path/venv/lib/python3.5/site-packages/rest_framework/generics.py", line 262, in patch
return self.partial_update(request, *args, **kwargs)
File "path/venv/lib/python3.5/site-packages/rest_framework/mixins.py", line 78, in partial_update
return self.update(request, *args, **kwargs)
File "path/venv/lib/python3.5/site-packages/rest_framework/mixins.py", line 68, in update
serializer = self.get_serializer(instance, data=request.data, partial=partial)
File "path/venv/lib/python3.5/site-packages/rest_framework/request.py", line 359, in __getattribute__
six.reraise(info[0], info[1], info[2].tb_next)
File "path/venv/lib/python3.5/site-packages/django/utils/six.py", line 658, in reraise
raise value.with_traceback(tb)
File "path/venv/lib/python3.5/site-packages/rest_framework/request.py", line 183, in data
self._load_data_and_files()
File "path/venv/lib/python3.5/site-packages/rest_framework/request.py", line 243, in _load_data_and_files
self._data, self._files = self._parse()
File "path/venv/lib/python3.5/site-packages/rest_framework/request.py", line 289, in _parse
parsed = parser.parse(stream, media_type, self.parser_context)
File "path/venv/lib/python3.5/site-packages/djangorestframework_camel_case/parser.py", line 15, in parse
data = stream.read().decode(encoding)
File "path/venv/lib/python3.5/site-packages/django/http/request.py", line 293, in read
return self._stream.read(*args, **kwargs)
AttributeError: 'HttpRequest' object has no attribute '_stream'
Hey,
I have a local Redis server running and the following configurations - trying to follow the chat tutorial
settings.py:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgi_redis.RedisChannelLayer",
"ROUTING": "App.routing.channel_routing",
},
}
routing.py
channel_routing = {
"websocket.connect": ws_connect,
"websocket.receive": ws_message,
"websocket.disconnect": ws_disconnect,
}
and the consumer.py is identical to the tutorial code in http://channels.readthedocs.org/en/latest/getting-started.html#persisting-data
connecting seems to work fine, I see redis being updated etc. but when trying to send a message - this line will run but no message will be received by the client
Group("chat-%s" % message.channel_session['room']).send(message.content)
I am connecting to ws://localhost:8000/lmao
Any idea why or how I can troubleshoot it?
Hi,
I've played around with channels a few weeks back, but I can see that a lot have changed since then :-)
I have a use case in which I must assure that only a single command is executed per account at a given time.
Can I leverage the response channels (!account1,!account2), in a way that the matching workers will process them one at a time and in orders?
Will this use case be addressed as a part of the channels framework?
Best,
Erik.
I think we should make a paradigm shift and move to use WebRTC instead of Websockets. This allows many interesting properties:
There is a great open source project already available which provides both client server suppor: https://github.com/feross/simple-peer
Some interesting links to read:
while continuing the getting startet tutorial I stumbled when I added the linearize decorator:
ERROR django.channels Error processing message with consumer cm_base.consumers.ws_message:
Traceback (most recent call last):
File "/home/vagrant/pyenv/src/channels/channels/worker.py", line 37, in run
consumer(message)
File "/home/vagrant/pyenv/src/channels/channels/decorators.py", line 26, in inner
locked = message.channel_backend.lock_channel(message.reply_channel)
File "/home/vagrant/pyenv/src/channels/channels/backends/redis_py.py", line 177, in lock_channel
return bool(self.connection(self.consistent_hash(channel)).setnx(key, "1"))
File "/home/vagrant/pyenv/src/channels/channels/backends/redis_py.py", line 41, in consistent_hash
bigval = binascii.crc32(value) & 0xffffffff
TypeError: 'Channel' does not support the buffer interface
Hi,
I'm currently playing with django channels and it looks really great. I have tried several other websocket stuff in the last weeks, like crossbar (http://crossbar.io) and something I have build with tornado.
I have added following snippet to my nginx configuration:
location /ws/ {
rewrite ^/(.*) /$1 break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://localhost:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
which works fine with other websocket servers, but it looks like it won't work with runwsserver.
(I tried asyncio and twisted).
The error I see in the browser is: WebSocket connection to 'ws://localhost/ws/asd' failed: Error during WebSocket handshake: Unexpected response code: 400
I can see that the websocket server is reached since it prints some debug lines:
INFO asyncio poll 1.000 took 1.001 seconds
DEBUG asyncio poll 1.000 took 0.817 seconds
DEBUG asyncio poll 0.000 took 0.000 seconds
DEBUG asyncio poll 0.000 took 0.000 seconds
DEBUG asyncio poll 0.000 took 0.000 seconds
DEBUG asyncio poll 0.181 took 0.182 seconds
but thats not really helpful ;)
I'll try to dig into the code at the weekend, but maybe someone can help me before that ;)
Thanks,
Bastian
Hi,
Kudos for the great job!
This will be definitely take django to the next level!
Are you planning to include support for scheduled jobs? Like celery beat?
Any suggested workarounds?
Best,
Erik.
Hi... Currently I'm doing this.. I need more efficient way to pass dict and get it from frontend .. thanks
In my django views file I have this
messenger['content'] = '{' + '"name" :"{}", "ip_address" :"{}"'.format(name, ip_address) + '}'
result['message'] = "Ip Address associated with {} deleted".format(name)
Group("chat").send(messenger)
And in the html I have this to parse the string ...
var result = JSON.parse(e.data);
console.log(result);
So I guess this is not the correct way. Then what is the good way ?
I'm getting the following with runserver
:
Traceback (most recent call last):
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/django/utils/autoreload.py", line 226, in wrapper
fn(*args, **kwargs)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/channels/management/commands/runserver.py", line 37, in inner_run
self.channel_layer = channel_layers[DEFAULT_CHANNEL_LAYER]
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/channels/asgi.py", line 53, in __getitem__
self.backends[key] = self.make_backend(key)
File "/Users/mva/.virtualenvs/spam/lib/python3.5/site-packages/channels/asgi.py", line 33, in make_backend
raise InvalidChannelLayerError("No BACKEND specified for %s" % name)
channels.asgi.InvalidChannelLayerError: No BACKEND specified for default
I was reading http://channels.readthedocs.org/en/latest/getting-started.html#first-consumers where it mentions that, by default, Channels effectively delegates to Django via WSGI.
Using a string for the path
regex argument to route()
under Python leads to the following exception:
Traceback (most recent call last):
File "/Users/ulo/.pythonz/pythons/CPython-3.4.3/lib/python3.4/threading.py", line 920, in _bootstrap_inner
self.run()
File "/Users/ulo/Envs/dali/lib/python3.4/site-packages/channels/management/commands/runserver.py", line 152, in run
worker.run()
File "/Users/ulo/Envs/dali/lib/python3.4/site-packages/channels/worker.py", line 69, in run
match = self.channel_layer.router.match(message)
File "/Users/ulo/Envs/dali/lib/python3.4/site-packages/channels/routing.py", line 50, in match
match = route.match(message)
File "/Users/ulo/Envs/dali/lib/python3.4/site-packages/channels/routing.py", line 133, in match
match = re.match(value, message[name])
File "/Users/ulo/Envs/dali/lib/python3.4/re.py", line 160, in match
return _compile(pattern, flags).match(string)
TypeError: can't use a string pattern on a bytes-like object
Changing the value of path
to bytes
appears to fix the problem.
Edit: This also leads to any captured keyword arguments becoming bytes as well.
Versions used:
In particular, it should just accept a reference to a dict object, and that should be {"channel": function reference} - no lazy loading of channel consumers.
Hi,
in one of my projects I'm using a middleware that changes the request to allow easy url routing from javascript.
Unfortunately it requires request.environ, which is part of WSGIRequest but not part of HttpRequest. (https://github.com/django/django/blob/master/django/core/handlers/wsgi.py#L80)
Is it possible to still use WSGIRequest in the patched runserver ?
Bastian
After installing channels and creating a shell Django website I am unable to get a basic runserver started due to the following error:
Unhandled exception in thread started by <pydev_monkey._NewThreadStartupWithTrace instance at 0x7f69673e13f8>
Traceback (most recent call last):
File "/usr/lib/pycharm-4.5.3/helpers/pydev/pydev_monkey.py", line 427, in __call__
return self.original_func(*self.args, **self.kwargs)
File "/home/ricomoss/.virtualenvs/dc2/local/lib/python2.7/site-packages/django/utils/autoreload.py", line 229, in wrapper
fn(*args, **kwargs)
File "/home/ricomoss/workspace/channels/channels/management/commands/runserver.py", line 25, in inner_run
self.channel_backend = channel_backends[DEFAULT_CHANNEL_BACKEND]
File "/home/ricomoss/workspace/channels/channels/backends/__init__.py", line 32, in __getitem__
self.backends[key] = self.make_backend(key)
File "/home/ricomoss/workspace/channels/channels/backends/__init__.py", line 26, in make_backend
instance = backend_class(**{k.lower(): v for k, v in self.configs[name].items() if k != "BACKEND"})
TypeError: __init__() takes at least 2 arguments (1 given)
After investigating I was able to see that the default channel backend is going to be channels.backends.memory.InMemoryChannelBackend
, which expects a route
to instantiate. The dictionary comprehension above is empty.
I'd love to contribute to this project but have just started and do not have the full context of intent here. Can you please provide some guidance as to what can be done to fix this problem?
Using the Redis backend with Python 3 seems to break channels
. My project is set up as follows:
CHANNEL_BACKENDS = {
"default": {
"BACKEND": "channels.backends.redis_py.RedisChannelBackend",
"HOST": "localhost",
"ROUTING": "project.routing.channel_routing",
},
}
Trying to access any page via HTTP raises the following error:
Stacktrace
Traceback (most recent call last):
File "/usr/lib/python3.4/wsgiref/handlers.py", line 137, in run
self.result = application(self.environ, self.start_response)
File "/home/user/.local/share/virtualenvs/project/lib/python3.4/site-packages/django/contrib/staticfiles/handlers.py", line 63, in __call__
return self.application(environ, start_response)
File "/home/user/.local/share/virtualenvs/project/lib/python3.4/site-packages/django/core/handlers/wsgi.py", line 189, in __call__
response = self.get_response(request)
File "/home/user/.local/share/virtualenvs/project/lib/python3.4/site-packages/channels/interfaces/wsgi.py", line 19, in get_response
Channel("http.request", channel_backend=self.channel_backend).send(request.channel_encode())
File "/home/user/.local/share/virtualenvs/project/lib/python3.4/site-packages/channels/channel.py", line 35, in send
self.channel_backend.send(self.name, content)
File "/home/user/.local/share/virtualenvs/project/lib/python3.4/site-packages/channels/backends/redis_py.py", line 31, in send
key = self.prefix + uuid.uuid4().get_hex()
AttributeError: 'UUID' object has no attribute 'get_hex'
A dumb search for that error shows me it's probably a Python 2/3 compat issue, and
replacing get_hex()
with hex
should solve the problem.
Also, I wanted to thank you for the quality of this project : I tried to integrate it on one of my project and it works exactly as shown in the docs. I really like your approach to solve this problem and even if I probably won't use it in production until it's ready, it's nice to know there is a clean solution around that support WebSockets directly in Django.
While it is not that complicated to write routes for the CHANNEL_LAYERS['ROUTING']
setting, the Django Admin and some 3rd party apps (like Django Rest Framework) generate routes to be included into a URLConf.
Is it possible to just hook up Django's URL resolving system into Channel's routing system? Like:
channel_routing = {
'http.request': DjangoURLConfConsumer(),
# Websocket stuff:
'websocket.connect': consumers.ws_connect,
'websocket.receive': consumers.ws_receive,
'websocket.disconnect': consumers.ws_disconnect,
}
where DjangoURLConfConsumer
is a function/class that would load Django's URLConf and dispatch the message to the traditional (as in synchronous) views.
Maybe Channels already does this?
It's possible that a request could open and immediately send data, such that the connect message is still being handled when the receive message gets handled. The channel_session decorator should be able to handle this; current idea is that it sets a value when first encountered with data and then the other ones check/wait for this value to appear.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.