Giter Club home page Giter Club logo

channelsmultiplexer's People

Contributors

hishnash avatar johnthagen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

channelsmultiplexer's Issues

Websocket close race condition

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.

[Feature] Add support for binary downstream messages

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 dies without exception[BUG]

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):**

  • OS: Windows 10
  • Django version 2.1.4
  • Django channels version 2.1.5
  • Version 0.0.2

Support for Channels 3

Does this project support Django Channels 3? It might be worth mentioning in the README until support is added if not compatible.

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.