Esempio n. 1
0
 async def send(self, channel, message):
     """
     Send a message onto a (general or specific) channel.
     """
     # Typecheck
     assert isinstance(message, dict), "message is not a dict"
     assert self.valid_channel_name(channel), "Channel name not valid"
     # Make sure the message does not contain reserved keys
     assert "__asgi_channel__" not in message
     # If it's a process-local channel, strip off local part and stick full name in message
     channel_non_local_name = channel
     if "!" in channel:
         message = dict(message.items())
         message["__asgi_channel__"] = channel
         channel_non_local_name = self.non_local_name(channel)
     # Write out message into expiring key (avoids big items in list)
     channel_key = self.prefix + channel_non_local_name
     # Pick a connection to the right server - consistent for specific
     # channels, random for general channels
     if "!" in channel:
         index = self.consistent_hash(channel)
     else:
         index = next(self._send_index_generator)
     async with self.connection(index) as connection:
         # Check the length of the list before send
         # This can allow the list to leak slightly over capacity, but that's fine.
         if await connection.llen(channel_key) >= self.get_capacity(channel):
             raise ChannelFull()
         # Push onto the list then set it to expire in case it's not consumed
         await connection.rpush(channel_key, self.serialize(message))
         await connection.expire(channel_key, int(self.expiry))
    async def send(self, channel, asgi_channel, message):
        """
        Send a message onto a (generic or specific) channel.

        This publishes through RabbitMQ even when sending from localhost to
        localhost. This gives approximate global ordering.

        Usage:

            connection.send({'foo': 'bar'})
        """
        message["__asgi_channel__"] = asgi_channel
        message = msgpack.packb(message, use_bin_type=True)

        queue_name = channel_to_queue_name(asgi_channel)

        # Publish with publisher_confirms=True. Assume the server is configured
        # with `overflow: reject-publish`, so we get a basic.nack if the queue
        # length is exceeded.
        try:
            logger.debug("publish %r on %s", message, queue_name)
            await channel.publish(message, "", queue_name)
        except PublishFailed:
            raise ChannelFull()
        logger.debug("ok")
Esempio n. 3
0
    async def send(self, channel: str, message: Scope) -> None:
        """
        Send a message onto a (general or specific) channel.
        """
        # Typecheck
        assert isinstance(message, dict), "message is not a dict"
        assert self.valid_channel_name(channel), "Channel name not valid"
        # If it's a process-local channel, strip off local part and stick full name in message
        assert "__asgi_channel__" not in message

        queue = self.channels.setdefault(channel, asyncio.Queue())
        # Are we full
        if queue.qsize() >= self.capacity:
            raise ChannelFull(channel)

        # Add message
        await queue.put((time.time() + self.expiry, deepcopy(message)))