Exemple #1
0
    def handle_error(self):
        """Handle any uncaptured error in the core.

        Overrides asyncore's handle_error.

        """
        trace = traceback.format_exc()
        stderr(trace)
        self.debug(
            __file__,
            'Fatal error in core, please review exception log',
            'always'
        )
        # TODO: make not hardcoded
        logfile = codecs.open(
            os.path.join(self.config.logdir, 'exceptions.log'),
            'a',
            encoding='utf-8'
        )
        logfile.write('Fatal error in core, handle_error() was called\n')
        logfile.write('last raw line was %s' % self.raw)
        logfile.write(trace)
        logfile.write('Buffer:\n')
        logfile.write(self.buffer)
        logfile.write('----------------------------------------\n\n')
        logfile.close()
        if self.error_count > 10:
            if (datetime.now() - self.last_error_timestamp).seconds < 5:
                print >> sys.stderr, "Too many errors, can't continue"
                os._exit(1)
        self.last_error_timestamp = datetime.now()
        self.error_count = self.error_count + 1
        if self.config.exit_on_error:
            os._exit(1)
Exemple #2
0
    def handle_error(self):
        """Handle any uncaptured error in the core.

           Overrides asyncore's handle_error."""
        trace = traceback.format_exc()
        stderr(trace)
        self.debug(__file__,
                   'Fatal error in core, please review exception log',
                   'always')
        # TODO: make not hardcoded
        logfile = open(os.path.join(self.config.logdir, 'exceptions.log'),
                       'a',
                       encoding='utf-8')
        logfile.write('Fatal error in core, handle_error() was called\n')
        logfile.write('last raw line was %s' % self.raw)
        logfile.write(trace)
        logfile.write('Buffer:\n')
        logfile.write(self.buffer)
        logfile.write('----------------------------------------\n\n')
        logfile.close()
        if self.error_count > 10:
            if (datetime.now() - self.last_error_timestamp).seconds < 5:
                print >> sys.stderr, "Too many errors, can't continue"
                os._exit(1)
        self.last_error_timestamp = datetime.now()
        self.error_count = self.error_count + 1
        if self.config.exit_on_error:
            os._exit(1)
Exemple #3
0
    def unregister(self, variables):
        """Unregister all lpbot callables in variables, and their bindings.

        When unloading a module, this ensures that the unloaded modules will
        not get called and that the objects can be garbage collected. Objects
        that have not been registered are ignored.

        Args:
        variables -- A list of callable objects from a lpbot module.

        """

        def remove_func(func, commands):
            """Remove all traces of func from commands."""
            for func_list in itervalues(commands):
                if func in func_list:
                    func_list.remove(func)

        for obj in itervalues(variables):
            if obj in self.callables:
                self.callables.remove(obj)
                for commands in itervalues(self.commands):
                    remove_func(obj, commands)
            if obj in self.shutdown_methods:
                try:
                    obj(self)
                except Exception as e:
                    stderr(
                        "Error calling shutdown method for module %s:%s" %
                        (obj.__module__, e)
                    )
                self.shutdown_methods.remove(obj)
Exemple #4
0
    def __init__(self, config):
        ca_certs = '/etc/pki/tls/cert.pem'
        if config.ca_certs is not None:
            ca_certs = config.ca_certs
        elif not os.path.isfile(ca_certs):
            ca_certs = '/etc/ssl/certs/ca-certificates.crt'
        if not os.path.isfile(ca_certs):
            stderr('Could not open CA certificates file. SSL will not '
                   'work properly.')

        if config.log_raw is None:
            # Default is to log raw data, can be disabled in config
            config.log_raw = True
        asynchat.async_chat.__init__(self)
        self.set_terminator(b'\n')
        self.buffer = ''

        self.nick = Identifier(config.nick)
        """lpbot's current ``Identifier``. Changing this while lpbot is running is
        untested."""
        self.user = config.user
        """lpbot's user/ident."""
        self.name = config.name
        """lpbot's "real name", as used for whois."""

        self.channels = []
        """The list of channels lpbot is currently in."""

        self.stack = {}
        self.ca_certs = ca_certs
        self.hasquit = False

        self.sending = threading.RLock()
        self.writing_lock = threading.Lock()
        self.raw = None

        # Right now, only accounting for two op levels.
        # This might be expanded later.
        # These lists are filled in startup.py, as of right now.
        self.ops = dict()
        """
        A dictionary mapping channels to a ``Identifier`` list of their operators.
        """
        self.halfplus = dict()
        """
        A dictionary mapping channels to a ``Identifier`` list of their half-ops and
        ops.
        """
        self.voices = dict()
        """
        A dictionary mapping channels to a ``Identifier`` list of their voices,
        half-ops and ops.
        """

        # We need this to prevent error loops in handle_error
        self.error_count = 0

        self.connection_registered = False
        """ Set to True when a server has accepted the client connection and
Exemple #5
0
    def __init__(self, config):
        ca_certs = '/etc/pki/tls/cert.pem'
        if config.ca_certs is not None:
            ca_certs = config.ca_certs
        elif not os.path.isfile(ca_certs):
            ca_certs = '/etc/ssl/certs/ca-certificates.crt'
        if not os.path.isfile(ca_certs):
            stderr('Could not open CA certificates file. SSL will not '
                   'work properly.')

        if config.log_raw is None:
            # Default is to log raw data, can be disabled in config
            config.log_raw = True
        asynchat.async_chat.__init__(self)
        self.set_terminator(b'\n')
        self.buffer = ''

        self.nick = Identifier(config.nick)
        """lpbot's current ``Identifier``. Changing this while lpbot is running is
        untested."""
        self.user = config.user
        """lpbot's user/ident."""
        self.name = config.name
        """lpbot's "real name", as used for whois."""

        self.channels = []
        """The list of channels lpbot is currently in."""

        self.stack = {}
        self.ca_certs = ca_certs
        self.hasquit = False

        self.sending = threading.RLock()
        self.writing_lock = threading.Lock()
        self.raw = None

        # Right now, only accounting for two op levels.
        # This might be expanded later.
        # These lists are filled in startup.py, as of right now.
        self.ops = dict()
        """
        A dictionary mapping channels to a ``Identifier`` list of their operators.
        """
        self.halfplus = dict()
        """
        A dictionary mapping channels to a ``Identifier`` list of their half-ops and
        ops.
        """
        self.voices = dict()
        """
        A dictionary mapping channels to a ``Identifier`` list of their voices,
        half-ops and ops.
        """

        # We need this to prevent error loops in handle_error
        self.error_count = 0

        self.connection_registered = False
        """ Set to True when a server has accepted the client connection and
Exemple #6
0
 def _timeout_check(self):
     while self.connected or self.connecting:
         if (datetime.now() - self.last_ping_time).seconds > int(self.config.timeout):
             stderr('Ping timeout reached after %s seconds, closing connection' % self.config.timeout)
             self.handle_close()
             break
         else:
             time.sleep(int(self.config.timeout))
Exemple #7
0
    def handle_close(self):
        self.connection_registered = False

        self._shutdown()
        stderr('Closed!')

        # This will eventually call asyncore dispatchers close method, which
        # will release the main thread. This should be called last to avoid
        # race conditions.
        self.close()
Exemple #8
0
    def handle_close(self):
        self.connection_registered = False

        self._shutdown()
        stderr('Closed!')

        # This will eventually call asyncore dispatchers close method, which
        # will release the main thread. This should be called last to avoid
        # race conditions.
        self.close()
Exemple #9
0
 def _timeout_check(self):
     while self.connected or self.connecting:
         if (datetime.now() - self.last_ping_time).seconds > int(
                 self.config.timeout):
             stderr(
                 'Ping timeout reached after %s seconds, closing connection'
                 % self.config.timeout)
             self.handle_close()
             break
         else:
             time.sleep(int(self.config.timeout))
Exemple #10
0
def run(config):
    import lpbot.bot as bot

    # import lpbot.web as web
    import lpbot.logger
    from lpbot.tools import stderr

    if config.core.delay is not None:
        delay = config.core.delay
    else:
        delay = 20

    def signal_handler(sig, frame):
        if sig == signal.SIGUSR1 or sig == signal.SIGTERM:
            stderr("Got quit signal, shutting down.")
            p.quit("Closing")

    while True:
        try:
            p = bot.LpBot(config)
            if hasattr(signal, "SIGUSR1"):
                signal.signal(signal.SIGUSR1, signal_handler)
            if hasattr(signal, "SIGTERM"):
                signal.signal(signal.SIGTERM, signal_handler)
            lpbot.logger.setup_logging(p)
            p.run(config.core.host, int(config.core.port))
        except KeyboardInterrupt:
            break
        except Exception as e:
            trace = traceback.format_exc()
            try:
                stderr(trace)
            except:
                pass
            logfile = open(os.path.join(config.logdir, "exceptions.log"), "a")
            logfile.write("Critical exception in core")
            logfile.write(trace)
            logfile.write("----------------------------------------\n\n")
            logfile.close()
            os.unlink(config.pid_file_path)
            os._exit(1)

        if not isinstance(delay, int):
            break
        if p.hasquit or config.exit_on_error:
            break
        stderr("Warning: Disconnected. Reconnecting in %s seconds..." % delay)
        time.sleep(delay)
    os.unlink(config.pid_file_path)
    os._exit(0)
Exemple #11
0
def run(config):
    import lpbot.bot as bot
    # import lpbot.web as web
    import lpbot.logger
    from lpbot.tools import stderr

    if config.core.delay is not None:
        delay = config.core.delay
    else:
        delay = 20

    def signal_handler(sig, frame):
        if sig == signal.SIGUSR1 or sig == signal.SIGTERM:
            stderr('Got quit signal, shutting down.')
            p.quit('Closing')

    while True:
        try:
            p = bot.LpBot(config)
            if hasattr(signal, 'SIGUSR1'):
                signal.signal(signal.SIGUSR1, signal_handler)
            if hasattr(signal, 'SIGTERM'):
                signal.signal(signal.SIGTERM, signal_handler)
            lpbot.logger.setup_logging(p)
            p.run(config.core.host, int(config.core.port))
        except KeyboardInterrupt:
            break
        except Exception as e:
            trace = traceback.format_exc()
            try:
                stderr(trace)
            except:
                pass
            logfile = open(os.path.join(config.logdir, 'exceptions.log'), 'a')
            logfile.write('Critical exception in core')
            logfile.write(trace)
            logfile.write('----------------------------------------\n\n')
            logfile.close()
            os.unlink(config.pid_file_path)
            os._exit(1)

        if not isinstance(delay, int):
            break
        if p.hasquit or config.exit_on_error:
            break
        stderr('Warning: Disconnected. Reconnecting in %s seconds...' % delay)
        time.sleep(delay)
    os.unlink(config.pid_file_path)
    os._exit(0)
Exemple #12
0
 def initiate_connect(self, host, port):
     stderr('Connecting to %s:%s...' % (host, port))
     source_address = ((self.config.core.bind_host, 0)
                       if self.config.core.bind_host else None)
     self.set_socket(socket.create_connection((host, port),
                                              source_address=source_address))
     if self.config.core.use_ssl:
         self.send = self._ssl_send
         self.recv = self._ssl_recv
     self.connect((host, port))
     try:
         asyncore.loop()
     except KeyboardInterrupt:
         print('KeyboardInterrupt')
         self.quit('KeyboardInterrupt')
Exemple #13
0
 def initiate_connect(self, host, port):
     stderr('Connecting to %s:%s...' % (host, port))
     source_address = ((self.config.core.bind_host,
                        0) if self.config.core.bind_host else None)
     self.set_socket(
         socket.create_connection((host, port),
                                  source_address=source_address))
     if self.config.core.use_ssl:
         self.send = self._ssl_send
         self.recv = self._ssl_recv
     self.connect((host, port))
     try:
         asyncore.loop()
     except KeyboardInterrupt:
         print('KeyboardInterrupt')
         self.quit('KeyboardInterrupt')
Exemple #14
0
 def initiate_connect(self, host, port):
     stderr('Connecting to %s:%s...' % (host, port))
     source_address = ((self.config.core.bind_host, 0)
                       if self.config.core.bind_host else None)
     self.set_socket(socket.create_connection((host, port),
                                              source_address=source_address))
     if self.config.core.use_ssl and has_ssl:
         self.send = self._ssl_send
         self.recv = self._ssl_recv
     elif not has_ssl and self.config.core.use_ssl:
         stderr('SSL is not avilable on your system, attempting connection '
                'without it')
     self.connect((host, port))
     try:
         asyncore.loop()
     except KeyboardInterrupt:
         print('KeyboardInterrupt')
         self.quit('KeyboardInterrupt')
Exemple #15
0
    def error(self, trigger=None):
        """Called internally when a module causes an error."""
        try:
            trace = traceback.format_exc()
            stderr(trace)
            try:
                lines = list(reversed(trace.splitlines()))
                report = [lines[0].strip()]
                for line in lines:
                    line = line.strip()
                    if line.startswith('File "'):
                        report.append(line[0].lower() + line[1:])
                        break
                else:
                    report.append('source unknown')

                signature = '%s (%s)' % (report[0], report[1])
                # TODO: make not hardcoded
                log_filename = os.path.join(self.config.logdir,
                                            'exceptions.log')
                with open(log_filename, 'a', encoding='utf-8') as logfile:
                    logfile.write('Signature: %s\n' % signature)
                    if trigger:
                        logfile.write(
                            'from {} at {}. Message was: {}\n'.format(
                                trigger.nick, str(datetime.now()),
                                trigger.group(0)))
                    logfile.write(trace)
                    logfile.write(
                        '----------------------------------------\n\n')
            except Exception as e:
                stderr("Could not save full traceback!")
                self.debug(
                    __file__, "(From: " + trigger.sender +
                    "), can't save traceback: " + str(e), 'always')

            if trigger:
                self.msg(trigger.sender, signature)
        except Exception as e:
            if trigger:
                self.msg(trigger.sender, "Got an error.")
                self.debug(__file__,
                           "(From: " + trigger.sender + ") " + str(e),
                           'always')
Exemple #16
0
    def found_terminator(self):
        line = self.buffer
        if line.endswith('\r'):
            line = line[:-1]
        self.buffer = ''
        self.last_ping_time = datetime.now()
        pretrigger = PreTrigger(self.nick, line)

        if pretrigger.args[0] == 'PING':
            self.write(('PONG', pretrigger.args[-1]))
        elif pretrigger.args[0] == 'ERROR':
            self.debug(__file__, pretrigger.args[-1], 'always')
            if self.hasquit:
                self.close_when_done()
        elif pretrigger.args[0] == '433':
            stderr('Nickname already in use!')
            self.handle_close()

        self.dispatch(pretrigger)
Exemple #17
0
    def found_terminator(self):
        line = self.buffer
        if line.endswith('\r'):
            line = line[:-1]
        self.buffer = ''
        self.last_ping_time = datetime.now()
        pretrigger = PreTrigger(self.nick, line)

        if pretrigger.args[0] == 'PING':
            self.write(('PONG', pretrigger.args[-1]))
        elif pretrigger.args[0] == 'ERROR':
            self.debug(__file__, pretrigger.args[-1], 'always')
            if self.hasquit:
                self.close_when_done()
        elif pretrigger.args[0] == '433':
            stderr('Nickname already in use!')
            self.handle_close()

        self.dispatch(pretrigger)
Exemple #18
0
    def error(self, trigger=None):
        """Called internally when a module causes an error."""
        try:
            trace = traceback.format_exc()
            if sys.version_info.major < 3:
                trace = trace.decode('utf-8', errors='xmlcharrefreplace')
            stderr(trace)
            try:
                lines = list(reversed(trace.splitlines()))
                report = [lines[0].strip()]
                for line in lines:
                    line = line.strip()
                    if line.startswith('File "'):
                        report.append(line[0].lower() + line[1:])
                        break
                else:
                    report.append('source unknown')

                signature = '%s (%s)' % (report[0], report[1])
                # TODO: make not hardcoded
                log_filename = os.path.join(self.config.logdir, 'exceptions.log')
                with codecs.open(log_filename, 'a', encoding='utf-8') as logfile:
                    logfile.write('Signature: %s\n' % signature)
                    if trigger:
                        logfile.write('from {} at {}. Message was: {}\n'.format(
                            trigger.nick, str(datetime.now()), trigger.group(0)))
                    logfile.write(trace)
                    logfile.write(
                        '----------------------------------------\n\n'
                    )
            except Exception as e:
                stderr("Could not save full traceback!")
                self.debug(__file__, "(From: " + trigger.sender + "), can't save traceback: " + str(e), 'always')

            if trigger:
                self.msg(trigger.sender, signature)
        except Exception as e:
            if trigger:
                self.msg(trigger.sender, "Got an error.")
                self.debug(__file__, "(From: " + trigger.sender + ") " + str(e), 'always')
Exemple #19
0
    def handle_connect(self):
        if self.config.core.use_ssl:
            if not self.config.core.verify_ssl:
                self.ssl = ssl.wrap_socket(self.socket,
                                           do_handshake_on_connect=True,
                                           suppress_ragged_eofs=True)
            else:
                self.ssl = ssl.wrap_socket(self.socket,
                                           do_handshake_on_connect=True,
                                           suppress_ragged_eofs=True,
                                           cert_reqs=ssl.CERT_REQUIRED,
                                           ca_certs=self.ca_certs)
                try:
                    ssl.match_hostname(self.ssl.getpeercert(),
                                       self.config.host)
                except ssl.CertificateError:
                    stderr("Invalid certficate, hostname mismatch!")
                    os.unlink(self.config.pid_file_path)
                    os._exit(1)
            self.set_socket(self.ssl)

        if self.config.core.server_password is not None:
            self.write(('PASS', self.config.core.server_password))
        self.write(('NICK', self.nick))
        self.write(('USER', self.user, '+iw', self.nick), self.name)

        stderr('Connected.')
        self.last_ping_time = datetime.now()
        timeout_check_thread = threading.Thread(target=self._timeout_check)
        timeout_check_thread.start()
        ping_thread = threading.Thread(target=self._send_ping)
        ping_thread.start()

        # Request list of server capabilities. IRCv3 servers will respond with
        # CAP * LS (which we handle in coretasks). v2 servers will respond with
        # 421 Unknown command, which we'll ignore
        # This needs to come after Authentication as it can cause connection
        # Issues
        self.write(('CAP', 'LS'))
Exemple #20
0
    def handle_connect(self):
        if self.config.core.use_ssl and has_ssl:
            if not self.config.core.verify_ssl:
                self.ssl = ssl.wrap_socket(self.socket,
                                           do_handshake_on_connect=True,
                                           suppress_ragged_eofs=True)
            else:
                self.ssl = ssl.wrap_socket(self.socket,
                                           do_handshake_on_connect=True,
                                           suppress_ragged_eofs=True,
                                           cert_reqs=ssl.CERT_REQUIRED,
                                           ca_certs=self.ca_certs)
                try:
                    ssl.match_hostname(self.ssl.getpeercert(), self.config.host)
                except ssl.CertificateError:
                    stderr("Invalid certficate, hostname mismatch!")
                    os.unlink(self.config.pid_file_path)
                    os._exit(1)
            self.set_socket(self.ssl)

        if self.config.core.server_password is not None:
            self.write(('PASS', self.config.core.server_password))
        self.write(('NICK', self.nick))
        self.write(('USER', self.user, '+iw', self.nick), self.name)

        stderr('Connected.')
        self.last_ping_time = datetime.now()
        timeout_check_thread = threading.Thread(target=self._timeout_check)
        timeout_check_thread.start()
        ping_thread = threading.Thread(target=self._send_ping)
        ping_thread.start()

        # Request list of server capabilities. IRCv3 servers will respond with
        # CAP * LS (which we handle in coretasks). v2 servers will respond with
        # 421 Unknown command, which we'll ignore
        # This needs to come after Authentication as it can cause connection
        # Issues
        self.write(('CAP', 'LS'))
Exemple #21
0
    def _shutdown(self):
        stderr(
            'Calling shutdown for %d modules.' % (len(self.shutdown_methods),)
        )

        for shutdown_method in self.shutdown_methods:
            try:
                stderr(
                    "calling %s.%s" % (
                        shutdown_method.__module__, shutdown_method.__name__,
                    )
                )
                shutdown_method(self)
            except Exception as e:
                stderr(
                    "Error calling shutdown method for module %s:%s" % (
                        shutdown_method.__module__, e
                    )
                )
Exemple #22
0
 def log_raw(self, line, prefix):
     """Log raw line to the raw log."""
     if not self.config.core.log_raw:
         return
     if not self.config.core.logdir:
         self.config.core.logdir = os.path.join(self.config.dotdir, 'logs')
     if not os.path.isdir(self.config.core.logdir):
         try:
             os.mkdir(self.config.core.logdir)
         except Exception as e:
             stderr('There was a problem creating the logs directory.')
             stderr('%s %s' % (str(e.__class__), str(e)))
             stderr('Please fix this and then run lpbot again.')
             os._exit(1)
     #TODO: make path not hardcoded
     with open(os.path.join(self.config.core.logdir, 'raw.log'),
               'a',
               encoding='utf-8') as rawlog:
         rawlog.write(prefix + str(time.time()) + "\t")
         rawlog.write(line.replace('\n', ''))
         rawlog.write('\n')
Exemple #23
0
 def log_raw(self, line, prefix):
     """Log raw line to the raw log."""
     if not self.config.core.log_raw:
         return
     if not self.config.core.logdir:
         self.config.core.logdir = os.path.join(self.config.dotdir,
                                                'logs')
     if not os.path.isdir(self.config.core.logdir):
         try:
             os.mkdir(self.config.core.logdir)
         except Exception as e:
             stderr('There was a problem creating the logs directory.')
             stderr('%s %s' % (str(e.__class__), str(e)))
             stderr('Please fix this and then run lpbot again.')
             os._exit(1)
     #TODO: make path not hardcoded
     with open(os.path.join(self.config.core.logdir, 'raw.log'),
              'a', 
              encoding='utf-8') as rawlog:
         rawlog.write(prefix + str(time.time()) + "\t")
         rawlog.write(line.replace('\n', ''))
         rawlog.write('\n')
Exemple #24
0
 def signal_handler(sig, frame):
     if sig == signal.SIGUSR1 or sig == signal.SIGTERM:
         stderr('Got quit signal, shutting down.')
         p.quit('Closing')
Exemple #25
0
 def run(self, host, port=6667):
     try:
         self.initiate_connect(host, port)
     except socket.error as e:
         stderr('Connection error: %s' % e)
         self.hasquit = True
Exemple #26
0
# Original code copyright:
# Copyright 2008, Sean B. Palmer, inamidst.com
# Copyright © 2012-2014, Elad Alfassa <*****@*****.**>
# Licensed under the Eiffel Forum License 2.

from __future__ import unicode_literals
from __future__ import print_function

import sys

from lpbot.tools import stderr


if sys.version_info.major < 3:
    stderr('Requires python 3')
    sys.exit(1)

import os
import argparse
import signal

from lpbot.__init__ import run, __version__
from lpbot.config import Config, create_config, ConfigurationError, wizard
import lpbot.tools as tools

homedir = os.path.join(os.path.expanduser('~'), '.lpbot')


def enumerate_configs(extension='.cfg'):
    configfiles = []
Exemple #27
0
    def setup(self):
        stderr("\nWelcome to lpbot. Loading modules...\n\n")
        self.callables = set()
        self.shutdown_methods = set()

        filenames = self.config.enumerate_modules()
        # Coretasks is special. No custom user coretasks.
        this_dir = os.path.dirname(os.path.abspath(__file__))
        filenames['coretasks'] = os.path.join(this_dir, 'coretasks.py')

        modules = []
        error_count = 0
        for name, filename in iteritems(filenames):
            try:
                module = imp.load_source(name, filename)
            except Exception as e:
                error_count = error_count + 1
                filename, lineno = tools.get_raising_file_and_line()
                rel_path = os.path.relpath(filename, os.path.dirname(__file__))
                raising_stmt = "%s:%d" % (rel_path, lineno)
                stderr("Error loading %s: %s (%s)" % (name, e, raising_stmt))
            else:
                try:
                    if hasattr(module, 'setup'):
                        module.setup(self)
                    self.register(vars(module))
                    modules.append(name)
                except Exception as e:
                    error_count = error_count + 1
                    filename, lineno = tools.get_raising_file_and_line()
                    rel_path = os.path.relpath(
                        filename, os.path.dirname(__file__)
                    )
                    raising_stmt = "%s:%d" % (rel_path, lineno)
                    stderr("Error in %s setup procedure: %s (%s)"
                           % (name, e, raising_stmt))

        if modules:
            stderr('\n\nRegistered %d modules,' % (len(modules) - 1))
            stderr('%d modules failed to load\n\n' % error_count)
        else:
            stderr("Warning: Couldn't find any modules")

        self.bind_commands()
Exemple #28
0
 def run(self, host, port=6667):
     try:
         self.initiate_connect(host, port)
     except socket.error as e:
         stderr('Connection error: %s' % e)
         self.hasquit = True
Exemple #29
0
 def signal_handler(sig, frame):
     if sig == signal.SIGUSR1 or sig == signal.SIGTERM:
         stderr("Got quit signal, shutting down.")
         p.quit("Closing")
Exemple #30
0
def main(argv=None):
    global homedir
    # Step One: Parse The Command Line
    try:
        parser = argparse.ArgumentParser(description='lpbot IRC Bot',
                                         usage='%(prog)s [options]')
        parser.add_argument('-c',
                            '--config',
                            metavar='filename',
                            help='use a specific configuration file')
        parser.add_argument("-d",
                            '--fork',
                            action="store_true",
                            dest="deamonize",
                            help="Deamonize lpbot")
        parser.add_argument("-q",
                            '--quit',
                            action="store_true",
                            dest="quit",
                            help="Gracefully quit lpbot")
        parser.add_argument("-k",
                            '--kill',
                            action="store_true",
                            dest="kill",
                            help="Kill lpbot")
        parser.add_argument('--exit-on-error',
                            action="store_true",
                            dest="exit_on_error",
                            help=("Exit immediately on every error instead of "
                                  "trying to recover"))
        parser.add_argument("-l",
                            '--list',
                            action="store_true",
                            dest="list_configs",
                            help="List all config files found")
        parser.add_argument("-m",
                            '--migrate',
                            action="store_true",
                            dest="migrate_configs",
                            help="Migrate config files to the new format")
        parser.add_argument('--quiet',
                            action="store_true",
                            dest="quiet",
                            help="Supress all output")
        parser.add_argument('-w',
                            '--configure-all',
                            action='store_true',
                            dest='wizard',
                            help='Run the configuration wizard.')
        parser.add_argument(
            '--configure-modules',
            action='store_true',
            dest='mod_wizard',
            help=('Run the configuration wizard, but only for the '
                  'module configuration options.'))
        parser.add_argument(
            '--configure-database',
            action='store_true',
            dest='db_wizard',
            help=('Run the configuration wizard, but only for the '
                  'database configuration options.'))
        parser.add_argument('-v',
                            '--version',
                            action="store_true",
                            dest="version",
                            help="Show version number and exit")
        opts = parser.parse_args()

        try:
            if os.getuid() == 0 or os.geteuid() == 0:
                stderr("Don't run the bot as root")
                sys.exit(1)
        except AttributeError:
            # Windows doesn't have os.getuid/os.geteuid
            pass

        if opts.version:
            py_ver = '%s.%s.%s' % (sys.version_info.major,
                                   sys.version_info.minor,
                                   sys.version_info.micro)
            print('lpbot %s (running on python %s)' % (__version__, py_ver))
            return
        elif opts.wizard:
            wizard('all', opts.config)
            return
        elif opts.mod_wizard:
            wizard('mod', opts.config)
            return
        elif opts.db_wizard:
            wizard('db', opts.config)
            return

        if opts.list_configs:
            configs = enumerate_configs()
            print('Config files in ~/.lpbot:')
            if len(configs) is 0:
                print('\tNone found')
            else:
                for config in configs:
                    print('\t%s' % config)
            print('-------------------------')
            return

        config_name = opts.config or 'default'

        configpath = find_config(config_name)
        if not os.path.isfile(configpath):
            print(
                "Welcome to lpbot!\nI can't seem to find the configuration file, so let's generate it!\n"
            )
            if not configpath.endswith('.cfg'):
                configpath = configpath + '.cfg'
            create_config(configpath)
            configpath = find_config(config_name)
        try:
            config_module = Config(configpath)
        except ConfigurationError as e:
            stderr(e)
            sys.exit(2)

        if config_module.core.not_configured:
            stderr('Bot is not configured, can\'t start')
            # exit with code 2 to prevent auto restart on fail by systemd
            sys.exit(2)

        if not config_module.has_option('core', 'homedir'):
            config_module.dotdir = homedir
            config_module.homedir = homedir
        else:
            homedir = config_module.core.homedir
            config_module.dotdir = config_module.core.homedir

        if not config_module.core.logdir:
            config_module.core.logdir = os.path.join(homedir, 'logs')
        logfile = os.path.os.path.join(config_module.logdir, 'stdio.log')
        if not os.path.isdir(config_module.logdir):
            os.mkdir(config_module.logdir)

        config_module.exit_on_error = opts.exit_on_error
        config_module._is_deamonized = opts.deamonize

        sys.stderr = tools.OutputRedirect(logfile, True, opts.quiet)
        sys.stdout = tools.OutputRedirect(logfile, False, opts.quiet)

        # Handle --quit, --kill and saving the PID to file
        pid_dir = config_module.core.pid_dir or homedir
        if opts.config is None:
            pid_file_path = os.path.join(pid_dir, 'lpbot.pid')
        else:
            basename = os.path.basename(opts.config)
            if basename.endswith('.cfg'):
                basename = basename[:-4]
            pid_file_path = os.path.join(pid_dir, 'lpbot-%s.pid' % basename)
        if os.path.isfile(pid_file_path):
            with open(pid_file_path, 'r') as pid_file:
                try:
                    old_pid = int(pid_file.read())
                except ValueError:
                    old_pid = None
            if old_pid is not None and tools.check_pid(old_pid):
                if not opts.quit and not opts.kill:
                    stderr(
                        'There\'s already a lpbot instance running with this config file'
                    )
                    stderr('Try using the --quit or the --kill options')
                    sys.exit(1)
                elif opts.kill:
                    stderr('Killing the lpbot')
                    os.kill(old_pid, signal.SIGKILL)
                    sys.exit(0)
                elif opts.quit:
                    stderr('Signaling lpbot to stop gracefully')
                    if hasattr(signal, 'SIGUSR1'):
                        os.kill(old_pid, signal.SIGUSR1)
                    else:
                        os.kill(old_pid, signal.SIGTERM)
                    sys.exit(0)
            elif not tools.check_pid(old_pid) and (opts.kill or opts.quit):
                stderr('lpbot is not running!')
                sys.exit(1)
        elif opts.quit or opts.kill:
            stderr('lpbot is not running!')
            sys.exit(1)
        if opts.deamonize:
            child_pid = os.fork()
            if child_pid is not 0:
                sys.exit()
        with open(pid_file_path, 'w') as pid_file:
            pid_file.write(str(os.getpid()))
        config_module.pid_file_path = pid_file_path

        # Step Five: Initialise And Run lpbot
        run(config_module)
    except KeyboardInterrupt:
        print("\n\nInterrupted")
        os._exit(1)
Exemple #31
0
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

# Original code copyright:
# Copyright 2008, Sean B. Palmer, inamidst.com
# Copyright © 2012-2014, Elad Alfassa <*****@*****.**>
# Licensed under the Eiffel Forum License 2.

import sys

from lpbot.tools import stderr

if sys.version_info.major < 3:
    stderr('Requires python 3')
    sys.exit(1)

import os
import argparse
import signal

from lpbot.__init__ import run, __version__
from lpbot.config import Config, create_config, ConfigurationError, wizard
import lpbot.tools as tools

homedir = os.path.join(os.path.expanduser('~'), '.lpbot')


def enumerate_configs(extension='.cfg'):
    configfiles = []
    if os.path.isdir(homedir):
        willie_dotdirfiles = os.listdir(homedir)  # Preferred
Exemple #32
0
 def signal_handler(sig, frame):
     if sig == signal.SIGUSR1 or sig == signal.SIGTERM:
         stderr('Got quit signal, shutting down.')
         p.quit('Closing')
Exemple #33
0
def main(argv=None):
    global homedir
    # Step One: Parse The Command Line
    try:
        parser = argparse.ArgumentParser(description='lpbot IRC Bot',
                                         usage='%(prog)s [options]')
        parser.add_argument('-c', '--config', metavar='filename',
                            help='use a specific configuration file')
        parser.add_argument("-d", '--fork', action="store_true",
                            dest="deamonize", help="Deamonize lpbot")
        parser.add_argument("-q", '--quit', action="store_true", dest="quit",
                            help="Gracefully quit lpbot")
        parser.add_argument("-k", '--kill', action="store_true", dest="kill",
                            help="Kill lpbot")
        parser.add_argument('--exit-on-error', action="store_true",
                            dest="exit_on_error", help=(
                "Exit immediately on every error instead of "
                "trying to recover"))
        parser.add_argument("-l", '--list', action="store_true",
                            dest="list_configs",
                            help="List all config files found")
        parser.add_argument("-m", '--migrate', action="store_true",
                            dest="migrate_configs",
                            help="Migrate config files to the new format")
        parser.add_argument('--quiet', action="store_true", dest="quiet",
                            help="Supress all output")
        parser.add_argument('-w', '--configure-all', action='store_true',
                            dest='wizard', help='Run the configuration wizard.')
        parser.add_argument('--configure-modules', action='store_true',
                            dest='mod_wizard', help=(
                'Run the configuration wizard, but only for the '
                'module configuration options.'))
        parser.add_argument('--configure-database', action='store_true',
                            dest='db_wizard', help=(
                'Run the configuration wizard, but only for the '
                'database configuration options.'))
        parser.add_argument('-v', '--version', action="store_true",
                            dest="version", help="Show version number and exit")
        opts = parser.parse_args()

        try:
            if os.getuid() == 0 or os.geteuid() == 0:
                stderr("Don't runt he bot as root")
                sys.exit(1)
        except AttributeError:
            # Windows doesn't have os.getuid/os.geteuid
            pass

        if opts.version:
            py_ver = '%s.%s.%s' % (sys.version_info.major,
                                   sys.version_info.minor,
                                   sys.version_info.micro)
            print('lpbot %s (running on python %s)' % (__version__, py_ver))
            return
        elif opts.wizard:
            wizard('all', opts.config)
            return
        elif opts.mod_wizard:
            wizard('mod', opts.config)
            return
        elif opts.db_wizard:
            wizard('db', opts.config)
            return

        if opts.list_configs:
            configs = enumerate_configs()
            print('Config files in ~/.lpbot:')
            if len(configs) is 0:
                print('\tNone found')
            else:
                for config in configs:
                    print('\t%s' % config)
            print('-------------------------')
            return

        config_name = opts.config or 'default'

        configpath = find_config(config_name)
        if not os.path.isfile(configpath):
            print("Welcome to lpbot!\nI can't seem to find the configuration file, so let's generate it!\n")
            if not configpath.endswith('.cfg'):
                configpath = configpath + '.cfg'
            create_config(configpath)
            configpath = find_config(config_name)
        try:
            config_module = Config(configpath)
        except ConfigurationError as e:
            stderr(e)
            sys.exit(2)

        if config_module.core.not_configured:
            stderr('Bot is not configured, can\'t start')
            # exit with code 2 to prevent auto restart on fail by systemd
            sys.exit(2)

        if not config_module.has_option('core', 'homedir'):
            config_module.dotdir = homedir
            config_module.homedir = homedir
        else:
            homedir = config_module.core.homedir
            config_module.dotdir = config_module.core.homedir

        if not config_module.core.logdir:
            config_module.core.logdir = os.path.join(homedir, 'logs')
        logfile = os.path.os.path.join(config_module.logdir, 'stdio.log')
        if not os.path.isdir(config_module.logdir):
            os.mkdir(config_module.logdir)

        config_module.exit_on_error = opts.exit_on_error
        config_module._is_deamonized = opts.deamonize

        sys.stderr = tools.OutputRedirect(logfile, True, opts.quiet)
        sys.stdout = tools.OutputRedirect(logfile, False, opts.quiet)

        # Handle --quit, --kill and saving the PID to file
        pid_dir = config_module.core.pid_dir or homedir
        if opts.config is None:
            pid_file_path = os.path.join(pid_dir, 'lpbot.pid')
        else:
            basename = os.path.basename(opts.config)
            if basename.endswith('.cfg'):
                basename = basename[:-4]
            pid_file_path = os.path.join(pid_dir, 'lpbot-%s.pid' % basename)
        if os.path.isfile(pid_file_path):
            with open(pid_file_path, 'r') as pid_file:
                try:
                    old_pid = int(pid_file.read())
                except ValueError:
                    old_pid = None
            if old_pid is not None and tools.check_pid(old_pid):
                if not opts.quit and not opts.kill:
                    stderr('There\'s already a lpbot instance running with this config file')
                    stderr('Try using the --quit or the --kill options')
                    sys.exit(1)
                elif opts.kill:
                    stderr('Killing the lpbot')
                    os.kill(old_pid, signal.SIGKILL)
                    sys.exit(0)
                elif opts.quit:
                    stderr('Signaling lpbot to stop gracefully')
                    if hasattr(signal, 'SIGUSR1'):
                        os.kill(old_pid, signal.SIGUSR1)
                    else:
                        os.kill(old_pid, signal.SIGTERM)
                    sys.exit(0)
            elif not tools.check_pid(old_pid) and (opts.kill or opts.quit):
                stderr('lpbot is not running!')
                sys.exit(1)
        elif opts.quit or opts.kill:
            stderr('lpbot is not running!')
            sys.exit(1)
        if opts.deamonize:
            child_pid = os.fork()
            if child_pid is not 0:
                sys.exit()
        with open(pid_file_path, 'w') as pid_file:
            pid_file.write(str(os.getpid()))
        config_module.pid_file_path = pid_file_path

        # Step Five: Initialise And Run lpbot
        run(config_module)
    except KeyboardInterrupt:
        print("\n\nInterrupted")
        os._exit(1)
Exemple #34
0
# Original code copyright:
# Copyright 2008, Sean B. Palmer, inamidst.com
# Copyright © 2012-2014, Elad Alfassa <*****@*****.**>
# Licensed under the Eiffel Forum License 2.

from __future__ import unicode_literals
from __future__ import print_function

import sys

from lpbot.tools import stderr


if sys.version_info < (2, 7):
    stderr('Error: Requires Python 2.7')
    sys.exit(1)
if sys.version_info.major == 3:
    stderr('Python 3 is not supported. Check out original code for python 3 support')
    sys.exit(1)

import os
import argparse
import signal

from lpbot.__init__ import run, __version__
from lpbot.config import Config, create_config, ConfigurationError, wizard
import lpbot.tools as tools

homedir = os.path.join(os.path.expanduser('~'), '.lpbot')