コード例 #1
0
class Irc:
    """A class to manage channels and users on one IRC network
    This class is a wrapper for the IrcSocket class
    """
    def get_messages(self, stop, buffer):
        while 1:
            if stop:
                logging.info('[IRC] Receive thread sent stop signal')
                break
            try:
                lines = self.socket.get_raw()
                for line in lines:
                    # Handle ping and pong here
                    if line[0:4] == 'PING':
                        self.send_raw('PONG' + line[4:])
                        logging.debug('Sent pong successfully')
                        continue
                    buffer.put(line)
            except OSError as err:
                logging.error(err)
                if self.connected:
                    self.buffer.put(f'>>Error receiving messages: {err}')
                    self.disconnect()
                logging.info('[IRC] Socket error in receive thread, stopping...')
                break
            
    def __init__(self, host, port, nick, user, real, get_messages_callback, buffer, tag=False):
        """Create a new IRC instance
        Each instance represents one connection to one server"""
        self.host = host
        self.port = port
        self.nick = nick
        self.user = user
        self.real = real
        self.channels = []
        self.get_messages_callback = get_messages_callback
        self.buffer = buffer
        self.connected = False

        # Assign server tag if none given
        # This works well for host names, is not great for IPs but oh well
        if not tag:
            try:
                self.tag = host.split('.')[:-2]
            except IndexError:
                self.tag = host
        
    def connect(self):
        # Try to connect
        if self.connected:
            buffer.put('>>We are already connected')
        try:
            self.socket = IrcSocket()
            self.socket.connect(self.host, self.port)
            self.socket.put_raw(f"USER {self.user} 0 * :{self.real}")
            # TODO Support alternate nick
            self.socket.put_raw(f"NICK {self.nick}")
            self.stop_thread = False # used to stop the thread when connection dies
            self.receive_thread = threading.Thread(target=self.get_messages, args=(self.stop_thread, self.buffer,), daemon=True)
            self.receive_thread.start()
            self.connected = True

        except OSError as err:
            logging.error(err)
            self.buffer.put(f'>>Connection failed due to error: {err}')
            self.disconnect()

    def disconnect(self):
        """Shut down the socket and run clean up code"""
        try:
            logging.debug('[IRC] Disconnection process started')
            self.connected = False
            self.stop_thread = True # failsafe
            self.socket.disconnect()
        except OSError as err:
            logging.warning('[IRC] IRC socket reported error closing.')
        finally:
            logging.info('[IRC] IRC connection closed')
            logging.debug('[IRC] Disconnection process finished')
            self.buffer.put('>>IRC connection lost')
            self.buffer.put('[wiggleVerse] DROPCON')

    def send_raw(self, message):
        try:
            self.socket.put_raw(message)
        except OSError as err:
            logging.error(f"[IRC] Error sending: {err}")
            buffer.put(f'>>Error sending message: {err}')
            buffer.put('Disconnecting...')
            self.disconnect()

    def is_connected(self):
        return self.connected

    def get_tag(self):
        return self.tag