def error(self, origin=None, 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 origin: logfile.write( 'from %s at %s:\n' % ( origin.sender, str(datetime.now()) ) ) if trigger: logfile.write( 'Message was: <%s> %s\n' % ( trigger.nick, trigger.group(0) ) ) logfile.write(trace) logfile.write( '----------------------------------------\n\n' ) except Exception as e: stderr("Could not save full traceback!") self.debug(__file__, "(From: " + origin.sender + "), can't save traceback: " + str(e), 'always') if origin: #self.msg(origin.sender, signature) # Don't send the file name self.msg(origin.sender, report[0]) except Exception as e: if origin: self.msg(origin.sender, "Got an error.") self.debug( __file__, "(From: " + origin.sender + ") " + str(e), 'always' )
def _modules(self): home = os.getcwd() modules_dir = os.path.join(home, 'modules') filenames = willie.loader.enumerate_modules(self) os.sys.path.insert(0, modules_dir) for name, mod_spec in iteritems(filenames): path, type_ = mod_spec try: module, _ = willie.loader.load_module(name, path, type_) except Exception as e: filename, lineno = willie.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: if hasattr(module, 'configure'): prompt = name + ' module' if module.__doc__: doc = module.__doc__.split('\n', 1)[0] if doc: prompt = doc prompt = 'Configure {} (y/n)? [n]'.format(prompt) do_configure = get_input(prompt) do_configure = do_configure and do_configure.lower() == 'y' if do_configure: module.configure(self) self.save()
def unregister(self, variables): """Unregister all willie 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 willie 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)
def handle_error(self): """Handle any uncaptured error in the core. Overrides asyncore's handle_error. """ trace = traceback.format_exc() stderr(trace) LOGGER.error('Fatal error in core, please review exception log') # 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)
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)
def unregister(self, variables): """Unregister all willie 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 willie 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) hostmask = "%s!%s@%s" % (self.nick, self.user, socket.gethostname()) willie = self.WillieWrapper(self, irc.Origin(self, hostmask, [], {})) 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(willie) except Exception as e: stderr( "Error calling shutdown method for module %s:%s" % (obj.__module__, e) ) self.shutdown_methods.remove(obj)
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 = Nick(config.nick) """Willie's current ``Nick``. Changing this while Willie is running is untested.""" self.user = config.user """Willie's user/ident.""" self.name = config.name """Willie's "real name", as used for whois.""" self.channels = [] """The list of channels Willie 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 ``Nick`` list of their operators. """ self.halfplus = dict() """ A dictionary mapping channels to a ``Nick`` list of their half-ops and ops. """ self.voices = dict() """ A dictionary mapping channels to a ``Nick`` 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
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))
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()
def _timeout_check(self): while True: 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))
def run(config): if config.core.delay is not None: delay = config.core.delay elif config.core.timeout is not None: delay = 2 * int(config.core.timeout) else: delay = 300 # Inject ca_certs from config to web for SSL validation of web requests if hasattr(config, 'ca_certs') and config.ca_certs is not None: web.ca_certs = config.ca_certs else: web.ca_certs = '/etc/pki/tls/certs/ca-bundle.crt' 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.Willie(config) if hasattr(signal, 'SIGUSR1'): signal.signal(signal.SIGUSR1, signal_handler) if hasattr(signal, 'SIGTERM'): signal.signal(signal.SIGTERM, signal_handler) 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)
def error(self, origin=None, 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 origin: logfile.write('from %s at %s:\n' % (origin.sender, str(datetime.now()))) if trigger: logfile.write('Message was: <%s> %s\n' % (trigger.nick, trigger.group(0))) logfile.write(trace) logfile.write( '----------------------------------------\n\n') except Exception as e: stderr("Could not save full traceback!") self.debug( __file__, "(From: " + origin.sender + "), can't save traceback: " + str(e), 'always') if origin: #self.msg(origin.sender, signature) # Don't send the file name self.msg(origin.sender, report[0]) except Exception as e: if origin: self.msg(origin.sender, "Got an error.") self.debug(__file__, "(From: " + origin.sender + ") " + str(e), 'always')
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_address 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")
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!") LOGGER.error("Could not save traceback from %s to file: %s", trigger.sender, str(e)) if trigger: #self.msg(trigger.sender, signature) self.msg(trigger.sender, "I\'m afraid I can\'t do that.") print(signature) except Exception as e: if trigger: self.msg(trigger.sender, "Got an error.") LOGGER.error("Exception from %s: %s", trigger.sender, str(e))
def found_terminator(self): line = self.buffer if line.endswith('\r'): line = line[:-1] self.buffer = '' 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)
def found_terminator(self): line = self.buffer if line.endswith("\r"): line = line[:-1] self.buffer = "" self.raw = line # Break off IRCv3 message tags, if present tags = {} if line.startswith("@"): tagstring, line = line.split(" ", 1) for tag in tagstring[1:].split(";"): tag = tag.split("=", 1) if len(tag) > 1: tags[tag[0]] = tag[1] else: tags[tag[0]] = None if line.startswith(":"): source, line = line[1:].split(" ", 1) else: source = None if " :" in line: argstr, text = line.split(" :", 1) args = argstr.split(" ") args.append(text) else: args = line.split(" ") text = args[-1] self.last_ping_time = datetime.now() if args[0] == "PING": self.write(("PONG", text)) elif args[0] == "ERROR": self.debug(__file__, text, "always") if self.hasquit: self.close_when_done() elif args[0] == "433": stderr("Nickname already in use!") self.handle_close() origin = Origin(self, source, args, tags) self.dispatch(origin, text, args)
def found_terminator(self): line = self.buffer if line.endswith('\r'): line = line[:-1] self.buffer = '' self.raw = line # Break off IRCv3 message tags, if present tags = {} if line.startswith('@'): tagstring, line = line.split(' ', 1) for tag in tagstring[1:].split(';'): tag = tag.split('=', 1) if len(tag) > 1: tags[tag[0]] = tag[1] else: tags[tag[0]] = None if line.startswith(':'): source, line = line[1:].split(' ', 1) else: source = None if ' :' in line: argstr, text = line.split(' :', 1) args = argstr.split(' ') args.append(text) else: args = line.split(' ') text = args[-1] self.last_ping_time = datetime.now() if args[0] == 'PING': self.write(('PONG', text)) elif args[0] == 'ERROR': self.debug(__file__, text, 'always') if self.hasquit: self.close_when_done() elif args[0] == '433': stderr('Nickname already in use!') self.handle_close() origin = Origin(self, source, args, tags) self.dispatch(origin, text, args)
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.event == 'PING': self.write(('PONG', pretrigger.args[-1])) elif pretrigger.event == 'ERROR': LOGGER.error("ERROR recieved from server: %s", pretrigger.args[-1]) if self.hasquit: self.close_when_done() elif pretrigger.event == '433': stderr('Nickname already in use!') self.handle_close() self.dispatch(pretrigger)
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')
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!") LOGGER.error("Could not save traceback from %s to file: %s", trigger.sender, str(e)) if trigger: #self.msg(trigger.sender, signature) self.msg(trigger.sender, "I\'m afraid I can\'t do that.") print(signature) except Exception as e: if trigger: self.msg(trigger.sender, "Got an error.") LOGGER.error("Exception from %s: %s", trigger.sender, str(e))
def _shutdown(self): stderr( 'Calling shutdown for %d modules.' % (len(self.shutdown_methods),) ) for moduleName in self.config.enumerate_modules(): module = sys.modules[moduleName] if hasattr(module, "shutdown"): module.shutdown(self) hostmask = "%s!%s@%s" % (self.nick, self.user, socket.gethostname()) willie = self.WillieWrapper(self, irc.Origin(self, hostmask, [], {})) for shutdown_method in self.shutdown_methods: try: stderr( "calling %s.%s" % ( shutdown_method.__module__, shutdown_method.__name__, ) ) shutdown_method(willie) except Exception as e: stderr( "Error calling shutdown method for module %s:%s" % ( shutdown_method.__module__, e ) )
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) # 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 self.write(('CAP', 'LS')) if self.config.core.auth_method == 'server' or self.config.core.server_password: password = self.config.core.auth_password or self.config.core.server_password self.write(('PASS', 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()
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'))
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))
def run(config): import willie.bot as bot import willie.web as web from willie.tools import stderr if config.core.delay is not None: delay = config.core.delay else: delay = 20 # Inject ca_certs from config to web for SSL validation of web requests web.ca_certs = "/etc/pki/tls/certs/ca-bundle.crt" if hasattr(config, "ca_certs") and config.ca_certs is not None: web.ca_certs = config.ca_certs elif not os.path.isfile(web.ca_certs): web.ca_certs = "/etc/ssl/certs/ca-certificates.crt" if not os.path.isfile(web.ca_certs): stderr("Could not open CA certificates file. SSL will not " "work properly.") 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.Willie(config) if hasattr(signal, "SIGUSR1"): signal.signal(signal.SIGUSR1, signal_handler) if hasattr(signal, "SIGTERM"): signal.signal(signal.SIGTERM, signal_handler) 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)
def run(config, pid_file, daemon=False): import willie.bot as bot import willie.web as web import willie.logger from willie.tools import stderr delay = 20 # Inject ca_certs from config to web for SSL validation of web requests if not config.core.ca_certs: stderr('Could not open CA certificates file. SSL will not ' 'work properly.') web.ca_certs = config.core.ca_certs 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.Willie(config, daemon=daemon) if hasattr(signal, 'SIGUSR1'): signal.signal(signal.SIGUSR1, signal_handler) if hasattr(signal, 'SIGTERM'): signal.signal(signal.SIGTERM, signal_handler) willie.logger.setup_logging(p) p.run(config.core.host, int(config.core.port)) except KeyboardInterrupt: break except Exception: trace = traceback.format_exc() try: stderr(trace) except: pass logfile = open(os.path.join(config.core.logdir, 'exceptions.log'), 'a') logfile.write('Critical exception in core') logfile.write(trace) logfile.write('----------------------------------------\n\n') logfile.close() os.unlink(pid_file) os._exit(1) if not isinstance(delay, int): break if p.hasquit: break stderr('Warning: Disconnected. Reconnecting in %s seconds...' % delay) time.sleep(delay) os.unlink(pid_file) os._exit(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))
def _shutdown(self): stderr('Calling shutdown for %d modules.' % (len(self.shutdown_methods), )) hostmask = "%s!%s@%s" % (self.nick, self.user, socket.gethostname()) willie = self.WillieWrapper(self, irc.Origin(self, hostmask, [], {})) for shutdown_method in self.shutdown_methods: try: stderr("calling %s.%s" % ( shutdown_method.__module__, shutdown_method.__name__, )) shutdown_method(willie) except Exception as e: stderr("Error calling shutdown method for module %s:%s" % (shutdown_method.__module__, e))
def log_raw(self, line, prefix): """Log raw line to the raw log.""" if not self.config.core.log_raw: return 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 Willie again.') os._exit(1) f = codecs.open(os.path.join(self.config.core.logdir, 'raw.log'), 'a', encoding='utf-8') f.write(prefix + unicode(time.time()) + "\t") temp = line.replace('\n', '') f.write(temp) f.write("\n") f.close()
def _shutdown(self): stderr( 'Calling shutdown for %d modules.' % (len(self.shutdown_methods),) ) hostmask = "%s!%s@%s" % (self.nick, self.user, socket.gethostname()) willie = self.WillieWrapper(self, irc.Origin(self, hostmask, [], {})) for shutdown_method in self.shutdown_methods: try: stderr( "calling %s.%s" % ( shutdown_method.__module__, shutdown_method.__name__, ) ) shutdown_method(willie) except Exception as e: stderr( "Error calling shutdown method for module %s:%s" % ( shutdown_method.__module__, e ) )
def _shutdown(self): stderr('Calling shutdown for %d modules.' % (len(self.shutdown_methods), )) for moduleName in self.config.enumerate_modules(): module = sys.modules[moduleName] if hasattr(module, "shutdown"): module.shutdown(self) hostmask = "%s!%s@%s" % (self.nick, self.user, socket.gethostname()) willie = self.WillieWrapper(self, irc.Origin(self, hostmask, [], {})) for shutdown_method in self.shutdown_methods: try: stderr("calling %s.%s" % ( shutdown_method.__module__, shutdown_method.__name__, )) shutdown_method(willie) except Exception as e: stderr("Error calling shutdown method for module %s:%s" % (shutdown_method.__module__, e))
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 Willie again.") os._exit(1) f = codecs.open(os.path.join(self.config.core.logdir, "raw.log"), "a", encoding="utf-8") f.write(prefix + unicode(time.time()) + "\t") temp = line.replace("\n", "") f.write(temp) f.write("\n") f.close()
def setup(self): stderr("\nWelcome to Willie. Loading modules...\n\n") modules = willie.loader.enumerate_modules(self.config) error_count = 0 success_count = 0 for name in modules: path, type_ = modules[name] try: module, _ = willie.loader.load_module(name, path, type_) 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) relevant_parts = willie.loader.clean_module( module, self.config) 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)) else: self.register(*relevant_parts) success_count += 1 if len(modules) > 2: # coretasks is counted stderr('\n\nRegistered %d modules,' % (success_count - 1)) stderr('%d modules failed to load\n\n' % error_count) else: stderr("Warning: Couldn't load any modules")
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
def signal_handler(sig, frame): if sig == signal.SIGUSR1 or sig == signal.SIGTERM: stderr('Got quit signal, shutting down.') p.quit('Closing')
""" Willie - An IRC Bot Copyright 2008, Sean B. Palmer, inamidst.com Copyright © 2012-2014, Elad Alfassa <*****@*****.**> Licensed under the Eiffel Forum License 2. http://willie.dftba.net """ from __future__ import unicode_literals from __future__ import print_function import sys from willie.tools import stderr if sys.version_info < (2, 7): stderr('Error: Requires Python 2.7 or later. Try python2.7 willie') sys.exit(1) if sys.version_info.major == 3 and sys.version_info.minor < 3: stderr('Error: When running on Python 3, Python 3.3 is required.') sys.exit(1) import os import argparse import signal from willie.__init__ import run from willie.config import Config, create_config, ConfigurationError, wizard import willie.tools as tools import willie.web homedir = os.path.join(os.path.expanduser('~'), '.willie')
def main(argv=None): global homedir # Step One: Parse The Command Line try: parser = optparse.OptionParser('%prog [options]') parser.add_option('-c', '--config', metavar='filename', help='use a specific configuration file') parser.add_option("-d", '--fork', action="store_true", dest="deamonize", help="Deamonize willie") parser.add_option("-q", '--quit', action="store_true", dest="quit", help="Gracefully quit Willie") parser.add_option("-k", '--kill', action="store_true", dest="kill", help="Kill Willie") parser.add_option('--exit-on-error', action="store_true", dest="exit_on_error", help="Exit immediately on every error instead of trying to recover") parser.add_option("-l", '--list', action="store_true", dest="list_configs", help="List all config files found") parser.add_option("-m", '--migrate', action="store_true", dest="migrate_configs", help="Migrate config files to the new format") parser.add_option('--quiet', action="store_true", dest="quiet", help="Supress all output") parser.add_option('-w', '--configure-all', action='store_true', dest='wizard', help='Run the configuration wizard.') parser.add_option('--configure-modules', action='store_true', dest='mod_wizard', help='Run the configuration wizard, but only for the module configuration options.') parser.add_option('--configure-database', action='store_true', dest='db_wizard', help='Run the configuration wizard, but only for the database configuration options.') opts, args = parser.parse_args(argv) if 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 check_python_version() if opts.list_configs is not None: configs = enumerate_configs() print 'Config files in ~/.willie:' if len(configs[0]) 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 Willie!\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) if opts.exit_on_error: config_module.exit_on_error = True else: config_module.exit_on_error = False if opts.quiet is None: opts.quiet = False 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, 'willie.pid') else: basename = os.path.basename(opts.config) if basename.endswith('.cfg'): basename = basename[:-4] pid_file_path = os.path.join(pid_dir, 'willie-%s.pid' % basename) if os.path.isfile(pid_file_path): pid_file = open(pid_file_path, 'r') old_pid = int(pid_file.read()) pid_file.close() if tools.check_pid(old_pid): if opts.quit is None and opts.kill is None: stderr('There\'s already a Willie instance running with this config file') stderr('Try using the --quit or the --kill options') sys.exit(1) elif opts.kill: stderr('Killing the willie') os.kill(old_pid, signal.SIGKILL) sys.exit(0) elif opts.quit: stderr('Signaling Willie 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('Willie is not running!') sys.exit(1) elif opts.quit is not None or opts.kill is not None: stderr('Willie is not running!') sys.exit(1) if opts.deamonize is not None: child_pid = os.fork() if child_pid is not 0: sys.exit() pid_file = open(pid_file_path, 'w') pid_file.write(str(os.getpid())) pid_file.close() config_module.pid_file_path = pid_file_path # Step Five: Initialise And Run willie run(config_module) except KeyboardInterrupt: print "\n\nInterrupted" os._exit(1)
def check_python_version(): if sys.version_info < (2, 7): stderr('Error: Requires Python 2.7 or later. Try python2.7 willie') sys.exit(1)
def main(argv=None): # Step One: Parse The Command Line try: parser = optparse.OptionParser('%prog [options]') parser.add_option('-c', '--config', metavar='filename', help='use a specific configuration file') parser.add_option("-d", '--fork', action="store_true", dest="deamonize", help="Deamonize willie") parser.add_option("-q", '--quit', action="store_true", dest="quit", help="Gracefully quit Willie") parser.add_option("-k", '--kill', action="store_true", dest="kill", help="Kill Willie") parser.add_option("-l", '--list', action="store_true", dest="list_configs", help="List all config files found") parser.add_option("-m", '--migrate', action="store_true", dest="migrate_configs", help="Migrate config files to the new format") parser.add_option('--quiet', action="store_true", dest="quiet", help="Supress all output") parser.add_option('-w', '--configure-all', action='store_true', dest='wizard', help='Run the configuration wizard.') parser.add_option('--configure-modules', action='store_true', dest='mod_wizard', help='Run the configuration wizard, but only for the module configuration options.') parser.add_option('--configure-database', action='store_true', dest='db_wizard', help='Run the configuration wizard, but only for the database configuration options.') opts, args = parser.parse_args(argv) if 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 check_python_version() if opts.list_configs is not None: configs = enumerate_configs() stdout('Config files in ~/.willie:') if len(configs[0]) is 0: stdout('\tNone found') else: for config in configs[0]: stdout('\t%s' % config) stdout('-------------------------') stdout('Config files in ~/.jenni:') if len(configs[1]) is 0: stdout('\tNone found') else: for config in configs[1]: stdout('\t%s' % config) stdout('-------------------------') stdout('Config files in ~/.phenny:') if len(configs[2]) is 0: stdout('\tNone found') else: for config in configs[2]: stdout('\t%s' % config) stdout('-------------------------') return config_name = opts.config or 'default' if opts.migrate_configs is not None: configpath = find_config(config_name, '.py') new_configpath = configpath[:-2]+'cfg' if os.path.isfile(new_configpath): valid_answer = False while not valid_answer: answer = raw_input('Warning, new config file already exists. Overwrite? [y/n]') if answer is 'n' or answer == 'no': return elif answer == 'y' or answer == 'yes': valid_answer = True old_cfg = imp.load_source('Config', configpath) new_cfg = Config(new_configpath, load=False) new_cfg.add_section('core') for attrib in dir(old_cfg): if not attrib.startswith('_'): value = getattr(old_cfg, attrib) if value is None: continue #Skip NoneTypes if type(value) is list: #Parse lists parsed_value = ','.join(value) else: parsed_value = str(value) if attrib == 'password': attrib = 'nickserv_password' if attrib == 'serverpass': attrib = 'server_password' setattr(new_cfg.core, attrib, parsed_value) new_cfg.save() print 'Configuration migrated sucessfully, starting Willie' configpath = find_config(config_name) if not os.path.isfile(configpath): stdout("Welcome to Willie!\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(1) config_module.dotdir = dotdir if not config_module.core.logdir: config_module.core.logdir = os.path.join(dotdir, '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) if opts.quiet is None: opts.quiet = False 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 if opts.config is None: pid_file_path = os.path.join(dotdir, '.pid-default') else: pid_file_path = os.path.join(dotdir, '.pid-%s' % opts.config) if os.path.isfile(pid_file_path): pid_file = open(pid_file_path, 'r') old_pid = int(pid_file.read()) pid_file.close() if tools.check_pid(old_pid): if opts.quit is None and opts.kill is None: stderr('There\'s already a Willie instance running with this config file') stderr('Try using the --quit or the --kill options') sys.exit(1) elif opts.kill: stderr('Killing the willie') os.kill(old_pid, signal.SIGKILL) sys.exit(0) elif opts.quit: stderr('Singaling Willie to stop gracefully') os.kill(old_pid, signal.SIGUSR1) sys.exit(0) elif not tools.check_pid(old_pid) and (opts.kill or opts.quit): stderr('Willie is not running!') sys.exit(1) elif opts.quit is not None or opts.kill is not None: stderr('Willie is not running!') sys.exit(1) if opts.deamonize is not None: child_pid = os.fork() if child_pid is not 0: sys.exit() pid_file = open(pid_file_path, 'w') pid_file.write(str(os.getpid())) pid_file.close() config_module.pid_file_path = pid_file_path # Step Five: Initialise And Run willie run(config_module) except KeyboardInterrupt: stdout("\n\nInterrupted") os._exit(1)
def check_python_version(): if sys.version_info < (2, 7): stderr(u'Error: You need at least Python 2.7!') sys.exit(1)
def setup(self): stderr("\nWelcome to Willie. 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()
def main(argv=None): global homedir # Step One: Parse The Command Line try: parser = optparse.OptionParser("%prog [options]") parser.add_option("-c", "--config", metavar="filename", help="use a specific configuration file") parser.add_option("-d", "--fork", action="store_true", dest="deamonize", help="Deamonize willie") parser.add_option("-q", "--quit", action="store_true", dest="quit", help="Gracefully quit Willie") parser.add_option("-k", "--kill", action="store_true", dest="kill", help="Kill Willie") parser.add_option( "--exit-on-error", action="store_true", dest="exit_on_error", help=("Exit immediately on every error instead of " "trying to recover"), ) parser.add_option("-l", "--list", action="store_true", dest="list_configs", help="List all config files found") parser.add_option( "-m", "--migrate", action="store_true", dest="migrate_configs", help="Migrate config files to the new format", ) parser.add_option("--quiet", action="store_true", dest="quiet", help="Supress all output") parser.add_option( "-w", "--configure-all", action="store_true", dest="wizard", help="Run the configuration wizard." ) parser.add_option( "--configure-modules", action="store_true", dest="mod_wizard", help=("Run the configuration wizard, but only for the " "module configuration options."), ) parser.add_option( "--configure-database", action="store_true", dest="db_wizard", help=("Run the configuration wizard, but only for the " "database configuration options."), ) opts, args = parser.parse_args(argv) if 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 check_python_version() if opts.list_configs is not None: configs = enumerate_configs() print "Config files in ~/.willie:" if len(configs[0]) 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 Willie!\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) if opts.exit_on_error: config_module.exit_on_error = True else: config_module.exit_on_error = False if opts.quiet is None: opts.quiet = False 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, "willie.pid") else: basename = os.path.basename(opts.config) if basename.endswith(".cfg"): basename = basename[:-4] pid_file_path = os.path.join(pid_dir, "willie-%s.pid" % basename) if os.path.isfile(pid_file_path): pid_file = open(pid_file_path, "r") old_pid = int(pid_file.read()) pid_file.close() if tools.check_pid(old_pid): if opts.quit is None and opts.kill is None: stderr("There's already a Willie instance running with this config file") stderr("Try using the --quit or the --kill options") sys.exit(1) elif opts.kill: stderr("Killing the willie") os.kill(old_pid, signal.SIGKILL) sys.exit(0) elif opts.quit: stderr("Signaling Willie 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("Willie is not running!") sys.exit(1) elif opts.quit is not None or opts.kill is not None: stderr("Willie is not running!") sys.exit(1) if opts.deamonize is not None: child_pid = os.fork() if child_pid is not 0: sys.exit() pid_file = open(pid_file_path, "w") pid_file.write(str(os.getpid())) pid_file.close() config_module.pid_file_path = pid_file_path # Step Five: Initialise And Run willie run(config_module) except KeyboardInterrupt: print "\n\nInterrupted" os._exit(1)
def shutdown(bot): stderr("Shutdown ran!")
def main(argv=None): global homedir # Step One: Parse The Command Line try: parser = argparse.ArgumentParser(description='Willie 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 willie") parser.add_argument("-q", '--quit', action="store_true", dest="quit", help="Gracefully quit Willie") parser.add_argument("-k", '--kill', action="store_true", dest="kill", help="Kill Willie") 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('-v', '--version', action="store_true", dest="version", help="Show version number and exit") opts = parser.parse_args() # Step Two: "Do not run as root" checks. try: # Linux/Mac if os.getuid() == 0 or os.geteuid() == 0: stderr('Error: Do not run Willie with root privileges.') sys.exit(1) except AttributeError: # Windows if os.environ.get("USERNAME") == "Administrator": stderr('Error: Do not run Willie as Administrator.') sys.exit(1) if opts.version: py_ver = '%s.%s.%s' % (sys.version_info.major, sys.version_info.minor, sys.version_info.micro) print('Willie %s (running on python %s)' % (__version__, py_ver)) print('http://willie.dftba.net/') return elif opts.wizard: wizard('all', opts.config) return elif opts.mod_wizard: wizard('mod', opts.config) return if opts.list_configs: configs = enumerate_configs() print('Config files in ~/.willie:') 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 Willie!\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, 'willie.pid') else: basename = os.path.basename(opts.config) if basename.endswith('.cfg'): basename = basename[:-4] pid_file_path = os.path.join(pid_dir, 'willie-%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 Willie instance running with this config file') stderr('Try using the --quit or the --kill options') sys.exit(1) elif opts.kill: stderr('Killing the willie') os.kill(old_pid, signal.SIGKILL) sys.exit(0) elif opts.quit: stderr('Signaling Willie 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('Willie is not running!') sys.exit(1) elif opts.quit or opts.kill: stderr('Willie 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 willie run(config_module) except KeyboardInterrupt: print("\n\nInterrupted") os._exit(1)
def f_reload(bot, trigger): """Reloads a module, for use by admins only.""" if not trigger.admin: stderr('joku prkl yritti reloadata') return name = trigger.group(2) if name == bot.config.owner: return bot.reply('What?') if (not name) or (name == '*') or (name.upper() == 'ALL THE THINGS'): # Calling the shutdown methods of the modules for moduleName in bot.config.enumerate_modules(): module = sys.modules[moduleName] if hasattr(module, "shutdown"): module.shutdown(bot) bot.callables = None bot.commands = None bot.setup() return bot.reply('done reloading') if not name in sys.modules: return bot.reply('%s: no such module!' % name) old_module = sys.modules[name] old_callables = {} for obj_name, obj in iteritems(vars(old_module)): if bot.is_callable(obj) or bot.is_shutdown(obj): old_callables[obj_name] = obj # Call the shutdown method of the module if hasattr(old_module, "shutdown"): old_module.shutdown(bot) bot.unregister(old_callables) # Also remove all references to willie callables from top level of the # module, so that they will not get loaded again if reloading the # module does not override them. for obj_name in old_callables.keys(): delattr(old_module, obj_name) # Also delete the setup and shutdown function if hasattr(old_module, "setup"): delattr(old_module, "setup") if hasattr(old_module, "shutdown"): delattr(old_module, "shutdown") # Thanks to moot for prodding me on this path = old_module.__file__ if path.endswith('.pyc') or path.endswith('.pyo'): path = path[:-1] if not os.path.isfile(path): return bot.reply('Found %s, but not the source file' % name) module = imp.load_source(name, path) sys.modules[name] = module if hasattr(module, 'setup'): module.setup(bot) mtime = os.path.getmtime(module.__file__) modified = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(mtime)) bot.register(vars(module)) bot.bind_commands() bot.reply('%r (version: %s)' % (module, modified))
def setup(self): stderr("\nWelcome to Willie. 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()
def setup(bot): stderr("setup ran!")
def include(bot, filename): try: with open(filename) as f: bot.config.parser.readfp(f, filename) except Exception as exc: stderr("Failed to read included config file {}: {}".format(filename, exc))
def check_python_version(): if sys.version_info < (2, 7): stderr("Error: Requires Python 2.7 or later. Try python2.7 willie") sys.exit(1)