示例#1
0
    def send(self, channel, message):
        """Send a message to a channel. Join the channel before talking.

        This is the interface of this class and is thread-safe.

        channel and message are unicode strings.
        """
        if len(channel.encode('utf8')) > self._channel_maxlen:
            logger.warning("Channel length limit exceeded, dropping message")
            return
        self._queue.put((channel, message))
示例#2
0
    def _say_messages(self):
        """Try to send as much waiting messages as possible.

        This function is called every "line_sleep" seconds and only do one task
        such as publishing a line, joining a chan or something else.
        """
        # Dequeue everything, creating channel objects if needed
        while not self._queue.empty():
            (channel, message) = self._queue.get()
            # According to the RFC http://tools.ietf.org/html/rfc2812#page-6,
            # Message is admissible only if the IRC client won't eventually
            # have to send a message longer than 512 bytes
            # The message that will be sent by the irc.client module is :
            # 'PRIVMSG {channel} :{message}\r\n', so our message must be at
            # most 512 - 12 - len(channel) long
            max_message_size = 512 - 12 - len(channel.encode('utf-8'))
            if len(message.encode('utf-8')) > max_message_size:
                # The message needs to be split up
                logging.debug(
                    u"Message for channel %s longer than %s bytes, splitting",
                    channel,
                    max_message_size,
                )
                # Without this the message isn't splitted at the right index
                # the 'ignore' argument skip errors caused by utf-8 chars being
                # divided between the two strings.
                # This can make a char disappear.
                utf8_message = message.encode('utf-8')
                message1 = utf8_message[:max_message_size] \
                                .decode('utf-8', 'ignore')
                message2 = utf8_message[max_message_size:] \
                                .decode('utf-8', 'ignore')
                self._queue.put((channel, message1))
                self._queue.put((channel, message2))
            else:
                self._chans[channel].messages.append(message)

        # Don't do anything if server is stopped
        if self._stop.is_set():
            return

        # If we're disconnected, don't do anything and wait for reconnection
        if not self.is_connected():
            return

        # Find the next channel which needs work
        chanstatus = self._chans.find_waiting_channel()
        if chanstatus is None:
            return

        # Join the channel if needed
        if chanstatus.need_join():
            if chanstatus.inc_join_counter(self._max_join_attempts,
                                           self._memory_timeout):
                self.connection.join(chanstatus.name)
            elif self._fallbackchan and chanstatus.name != self._fallbackchan:
                # Channel is blocked. Do fallback !
                logger.warning(u"Channel %s is blocked. Using fallback" %
                            chanstatus.name)
                message = chanstatus.messages.pop(0)
                self._chans[self._fallbackchan].messages.append(message)
            else:
                logger.error(u"Channel %s is blocked. Dropping message")
                message = chanstatus.messages.pop(0)
                logger.error(u"Dropped message was %s" % message)
            return

        # Say first message and unqueue
        message = chanstatus.messages.pop(0)
        logger.info("[%s] say %s" % (chanstatus.name, message))
        self.connection.privmsg(chanstatus.name, message)
示例#3
0
    def _say_messages(self):
        """Try to send as much waiting messages as possible.

        This function is called every "line_sleep" seconds and only do one task
        such as publishing a line, joining a chan or something else.
        """
        # Dequeue everything, creating channel objects if needed
        while not self._queue.empty():
            (channel, message) = self._queue.get()
            # Split message if it is too long
            channel_length = len(channel.encode('utf8'))
            max_message_size = IRC_CHANMSG_MAXLEN - channel_length
            # Need at least 5 characters
            if max_message_size <= 5:
                logger.error("Channel name too long, dropping message")
                continue
            encoded = message.encode('utf-8')
            while len(encoded) > max_message_size:
                left, encoded = utf8_cut(encoded, max_message_size)
                if not left:
                    logger.error("Unable to decode message, dropping it")
                    break
                self._chans[channel].messages.append(left.decode('utf-8'))
            if encoded and len(encoded) <= max_message_size:
                self._chans[channel].messages.append(
                    encoded.decode('utf-8', 'ignore'))

        # Don't do anything if server is stopped
        if self._stop.is_set():
            return

        # If we're disconnected, don't do anything and wait for reconnection
        if not self.is_connected():
            return

        # Find the next channel which needs work
        chanstatus = self._chans.find_waiting_channel()
        if chanstatus is None:
            return

        # Join the channel if needed
        if chanstatus.need_join():
            if chanstatus.inc_join_counter(self._max_join_attempts,
                                           self._memory_timeout):
                self.connection.join(chanstatus.name)
            elif self._fallbackchan and chanstatus.name != self._fallbackchan:
                # Channel is blocked. Do fallback !
                logger.warning("Channel %s is blocked. Using fallback" %
                               chanstatus.name)
                message = chanstatus.messages.pop(0)
                self._chans[self._fallbackchan].messages.append(message)
            else:
                logger.error("Channel %s is blocked. Dropping message" %
                             chanstatus.name)
                message = chanstatus.messages.pop(0)
                logger.error("Dropped message was %s" % message)
            return

        # Say first message and unqueue
        message = chanstatus.messages.pop(0)
        logger.info("[%s] say %s" % (chanstatus.name, message))
        self.connection.privmsg(chanstatus.name, message)