def __init__(self, bot, server_timeout=None, ping_timeout=None, **kwargs): AbstractIRCBackend.__init__(self, bot) asynchat.async_chat.__init__(self) self.set_terminator(b'\n') self.buffer = '' self.server_timeout = server_timeout or 120 self.ping_timeout = ping_timeout or (self.server_timeout / 2) self.last_event_at = None self.host = None self.port = None self.source_address = None ping_job = Job(self.ping_timeout, _send_ping) timeout_job = Job(self.server_timeout, _check_timeout) self.timeout_scheduler = JobScheduler(self) self.timeout_scheduler.add_job(ping_job) self.timeout_scheduler.add_job(timeout_job)
class AsynchatBackend(AbstractIRCBackend, asynchat.async_chat): def __init__(self, bot, server_timeout=None, ping_timeout=None, **kwargs): AbstractIRCBackend.__init__(self, bot) asynchat.async_chat.__init__(self) self.set_terminator(b'\n') self.buffer = '' self.server_timeout = server_timeout or 120 self.ping_timeout = ping_timeout or (self.server_timeout / 2) self.last_event_at = None self.host = None self.port = None self.source_address = None ping_job = Job(self.ping_timeout, _send_ping) timeout_job = Job(self.server_timeout, _check_timeout) self.timeout_scheduler = JobScheduler(self) self.timeout_scheduler.add_job(ping_job) self.timeout_scheduler.add_job(timeout_job) def run_forever(self): asyncore.loop() def initiate_connect(self, host, port, source_address): self.host = host self.port = port self.source_address = source_address LOGGER.info('Connecting to %s:%s...', host, port) try: LOGGER.debug('Set socket') self.set_socket( socket.create_connection((host, port), source_address=source_address)) LOGGER.debug('Connection attempt') self.connect((host, port)) except socket.error as e: LOGGER.exception('Connection error: %s', e) self.handle_close() def handle_connect(self): """Called when the active opener's socket actually makes a connection.""" LOGGER.info('Connection accepted by the server...') self.timeout_scheduler.start() self.bot.on_connect() def handle_close(self): """Called when the socket is closed""" self.timeout_scheduler.stop() self.timeout_scheduler.join(timeout=15) LOGGER.info('Connection closed...') try: self.bot.on_close() finally: if self.socket: LOGGER.debug('Closing socket') self.close() LOGGER.info('Closed!') def handle_error(self): """Called when an exception is raised and not otherwise handled.""" LOGGER.info('Connection error...') self.bot.on_error() def collect_incoming_data(self, data): # We can't trust clients to pass valid unicode. try: data = unicode(data, encoding='utf-8') except UnicodeDecodeError: # not unicode, let's try cp1252 try: data = unicode(data, encoding='cp1252') except UnicodeDecodeError: # Okay, let's try ISO8859-1 try: data = unicode(data, encoding='iso8859-1') except UnicodeDecodeError: # Discard line if encoding is unknown return if data: self.bot.log_raw(data, '<<') self.buffer += data self.last_event_at = datetime.datetime.utcnow() def found_terminator(self): line = self.buffer if line.endswith('\r'): line = line[:-1] self.buffer = '' self.bot.on_message(line) def on_scheduler_error(self, scheduler, exc): """Called when the Job Scheduler fails.""" LOGGER.exception('Error with the timeout scheduler: %s', exc) self.handle_close() def on_job_error(self, scheduler, job, exc): """Called when a job from the Job Scheduler fails.""" LOGGER.exception('Error with the timeout scheduler: %s', exc) self.handle_close()
class AsynchatBackend(AbstractIRCBackend, asynchat.async_chat): """IRC backend implementation using :mod:`asynchat` (:mod:`asyncore`). :param bot: a Sopel instance :type bot: :class:`sopel.bot.Sopel` :param int server_timeout: connection timeout in seconds :param int ping_timeout: ping timeout in seconds """ def __init__(self, bot, server_timeout=None, ping_timeout=None, **kwargs): AbstractIRCBackend.__init__(self, bot) asynchat.async_chat.__init__(self) self.set_terminator(b'\n') self.buffer = '' self.server_timeout = server_timeout or 120 self.ping_timeout = ping_timeout or (self.server_timeout / 2) self.last_event_at = None self.host = None self.port = None self.source_address = None ping_job = Job(self.ping_timeout, _send_ping) timeout_job = Job(self.server_timeout, _check_timeout) self.timeout_scheduler = JobScheduler(self) self.timeout_scheduler.add_job(ping_job) self.timeout_scheduler.add_job(timeout_job) def run_forever(self): """Run forever.""" asyncore.loop() def initiate_connect(self, host, port, source_address): """Initiate IRC connection. :param str host: IRC server hostname :param int port: IRC server port :param str source_address: the source address from which to initiate the connection attempt """ self.host = host self.port = port self.source_address = source_address LOGGER.info('Connecting to %s:%s...', host, port) try: LOGGER.debug('Set socket') self.set_socket(socket.create_connection((host, port), source_address=source_address)) LOGGER.debug('Connection attempt') self.connect((host, port)) except socket.error as e: LOGGER.exception('Connection error: %s', e) self.handle_close() def handle_connect(self): """Called when the active opener's socket actually makes a connection.""" LOGGER.info('Connection accepted by the server...') self.timeout_scheduler.start() self.bot.on_connect() def handle_close(self): """Called when the socket is closed.""" self.timeout_scheduler.stop() if current_thread() is not self.timeout_scheduler: self.timeout_scheduler.join(timeout=15) LOGGER.info('Connection closed...') try: self.bot.on_close() finally: if self.socket: LOGGER.debug('Closing socket') self.close() LOGGER.info('Closed!') def handle_error(self): """Called when an exception is raised and not otherwise handled.""" LOGGER.info('Connection error...') self.bot.on_error() def collect_incoming_data(self, data): """Try to make sense of incoming data as Unicode. :param bytes data: the incoming raw bytes The incoming line is discarded (and thus ignored) if guessing the text encoding and decoding it fails. """ # We can't trust clients to pass valid Unicode. try: data = unicode(data, encoding='utf-8') except UnicodeDecodeError: # not Unicode; let's try CP-1252 try: data = unicode(data, encoding='cp1252') except UnicodeDecodeError: # Okay, let's try ISO 8859-1 try: data = unicode(data, encoding='iso8859-1') except UnicodeDecodeError: # Discard line if encoding is unknown return if data: self.bot.log_raw(data, '<<') self.buffer += data self.last_event_at = datetime.datetime.utcnow() def found_terminator(self): """Handle the end of an incoming message.""" line = self.buffer if line.endswith('\r'): line = line[:-1] self.buffer = '' self.bot.on_message(line) def on_scheduler_error(self, scheduler, exc): """Called when the Job Scheduler fails.""" LOGGER.exception('Error with the timeout scheduler: %s', exc) self.handle_close() def on_job_error(self, scheduler, job, exc): """Called when a job from the Job Scheduler fails.""" LOGGER.exception('Error with the timeout scheduler: %s', exc) self.handle_close()