hishnash / channelsmultiplexer Goto Github PK
View Code? Open in Web Editor NEWChannels v3 Multiplerxer
License: MIT License
Channels v3 Multiplerxer
License: MIT License
When my consumer calls self.close(code=3000)
the close event is sent to the browser, and the browser interprets "3000" to mean "authentication is required, redirect to login".
However, when close()
is called, the demultiplexer calls websocket_close
which removes that consumer's stream from applications_accepting_frames
.
This creates a race condition if the browser sends a message to the server from that stream after close()
is called, but before the browser receives the "websocket is closed" message.
When that happens the error "stream not mapped" occurs, resulting in the websocket being closed with non-3000 code so the browser does not know to redirect to login.
So this race condition causes any self.close(code=...)
to trigger a close without a code.
Thanks for making this :)
I solved the "what to do if binary" comment in the following way:
import base64
from channelsmultiplexer import AsyncJsonWebsocketDemultiplexer
class Demultiplexer(AsyncJsonWebsocketDemultiplexer):
applications = {
...
}
async def websocket_send(self, message, stream_name):
if 'bytes' in message:
message['bytes'] = base64.b64encode(
message['bytes']
).decode('ascii')
elif 'text' in message:
message['text'] = await self.decode_json(message['text'])
data = {
"stream": stream_name,
"payload": message
}
await self.send_json(data)
then the browser does this in the websocket:
base64ToArrayBuffer(base64) {
var binary_string = atob(base64);
var bytes = new Uint8Array(binary_string.length);
for (var i = 0; i < binary_string.length; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
handleMessage = (event) => {
const message = JSON.parse(event.data);
let payload;
// data in bytes is assumed to binary data encoded as base64
if (message.payload.bytes) {
payload = this.base64ToArrayBuffer(message.payload.bytes);
} else if (message.payload.text) {
payload = message.payload.text;
}
this.store.dispatch(
actions.websocketMessageRecieve(message.stream, payload)
);
}
For context, this facilitates me to send audio data from Alexa back to the browser through the multiplexer to be played. I'm using channelsmultiplexer
in conjunction with Alexa Browser Client to make a super-powered open source alternative to Echo Show that runs on the browser of any tablet.
If you like the base64 encoding solution I can make a Pull Request to this repo adding it?
Disconnect method stop working without exception. Condions: 1. Many consumers 2. db access in sync_func
Bug doesn't reproduce every time. When there are multiple db access calls and db modification calls, it reproduces more often.
import logging
l = logging.getLogger('django.db.backends')
l.setLevel(logging.DEBUG)
l.addHandler(logging.StreamHandler())
class TestConsumer(AsyncJsonWebsocketConsumer):
async def disconnect(self, close_code):
l.debug('before sync call')
await self.sync_func()
l.debug('after sync call')
await super().disconnect(close_code)
@database_sync_to_async
def sync_func(self):
l.debug('sync_func start')
get_user_model().objects.count()
l.debug('sync_func end')
class DemultiplexerAsyncJson(AsyncJsonWebsocketDemultiplexer):
applications = {
"test":TestConsumer,
"test2": TestConsumer
}
Logs
(0.001) SELECT "authtoken_token"."key", "authtoken_token"."user_id", "authtoken_token"."created" FROM "authtoken_token" WHERE "authtoken_token"."key" = '276d1578d208f6c4bb7a4cee755cc0f9c8280f3a'; args=('276d1578d208f6c4bb7a4cee755cc0f9c8280f3a',)
(0.001) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1; args=(1,)
WebSocket HANDSHAKING /ws/ [127.0.0.1:53291]
WebSocket CONNECT /ws/ [127.0.0.1:53291]
WebSocket DISCONNECT /ws/ [127.0.0.1:53291]
before sync call
before sync call
sync_func start
sync_func start
(0.001) SELECT COUNT(*) AS "__count" FROM "auth_user"; args=()
sync_func end
after sync call
(0.003) SELECT COUNT(*) AS "__count" FROM "auth_user"; args=()
sync_func end
(0.001) SELECT "authtoken_token"."key", "authtoken_token"."user_id", "authtoken_token"."created" FROM "authtoken_token" WHERE "authtoken_token"."key" = '276d1578d208f6c4bb7a4cee755cc0f9c8280f3a'; args=('276d1578d208f6c4bb7a4cee755cc0f9c8280f3a',)
(0.001) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1; args=(1,)
WebSocket HANDSHAKING /ws/ [127.0.0.1:53295]
WebSocket CONNECT /ws/ [127.0.0.1:53295]
Second 'after sync call' message missed in log.
** Platform (please complete the following information):**
Does this project support Django Channels 3? It might be worth mentioning in the README until support is added if not compatible.
Thanks.
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.