class NeuBot: """NeuBot""" def __init__(self): self.eventcontroller = EventController() self.plugincontroller = PluginController() self.ircnetscontroller = IRCNetsController() self.config = ConfigController() self.config.reload() self.quit_event = threading.Event() self.eventcontroller.register_system_event("BOT_QUIT", self.system_quit) def system_quit(self, params): self.quit_event.set() def start(self): # Initialize data store DatastoreController().set_driver(self.config.get('datastore')) Logger.set_loglevel(self.config.get('log.level')) for plugin in self.config.get('coreplugins'): Logger.info("Loading core plugin '%s'" % plugin) self.plugincontroller.load_plugin(plugin, 'core') for plugin in self.config.get('plugins'): Logger.info("Loading plugin '%s'" % plugin) self.plugincontroller.load_plugin(plugin) if len(self.config.get('ircnets')) == 0: raise Exception("There has to be at least one ircnet to connect to") for net in self.config.get('ircnets'): irc = IRCController(self.eventcontroller) irc.set_configuration(net) Logger.info("Connecting to %s..." % irc.get_ircnet_name()) irc.connect() self.ircnetscontroller.add_ircnet(irc.get_ircnet_name(), irc) def stop(self): self.ircnetscontroller.disconnect_all() self.plugincontroller.unload_all()
def __init__(self): self.eventcontroller = EventController() self.plugincontroller = PluginController() self.ircnetscontroller = IRCNetsController() self.config = ConfigController() self.config.reload() self.quit_event = threading.Event() self.eventcontroller.register_system_event("BOT_QUIT", self.system_quit)
def construct(self, eventcontroller = None, configcontroller = None): self._loaded_plugins = {} if eventcontroller: self._eventcontroller = eventcontroller else: self._eventcontroller = EventController() if configcontroller: self._config = configcontroller else: self._config = ConfigController()
def __init__(self): self.event = EventController() self.plugin = PluginController() # Make sure the simulated user have access to all commands ConfigController().get('masters').append('*!*@*') ConfigController().set('irc.rate_limit_wait_time', 0) # Configuration # This must match the values in SimulatedIRCNetworkClient simulated_ircnet = { "ircnet": "SimuNet", "nick": "NeuBot", "altnicks": [], "name": "Simulated Bot", "ident": "neubot", "servers": [ ("irc.example.org", 6667, False, False), ], "channels": [ ("#simulator", None), ] } # Initiate the IRCController and tell it to use our fake clientclass # so that it won't actually connect to a real server irc = IRCController(self.event, clientclass = SimulatedIRCNetworkClient) irc.set_configuration(simulated_ircnet) # Register server with ircnetscontroller IRCNetsController().add_ircnet(irc.get_ircnet_name(), irc) self._irc = irc # Initialize datastore DatastoreController().set_driver("data/simulator.db")
class Simulator: def __init__(self): self.event = EventController() self.plugin = PluginController() # Make sure the simulated user have access to all commands ConfigController().get('masters').append('*!*@*') ConfigController().set('irc.rate_limit_wait_time', 0) # Configuration # This must match the values in SimulatedIRCNetworkClient simulated_ircnet = { "ircnet": "SimuNet", "nick": "NeuBot", "altnicks": [], "name": "Simulated Bot", "ident": "neubot", "servers": [ ("irc.example.org", 6667, False, False), ], "channels": [ ("#simulator", None), ] } # Initiate the IRCController and tell it to use our fake clientclass # so that it won't actually connect to a real server irc = IRCController(self.event, clientclass = SimulatedIRCNetworkClient) irc.set_configuration(simulated_ircnet) # Register server with ircnetscontroller IRCNetsController().add_ircnet(irc.get_ircnet_name(), irc) self._irc = irc # Initialize datastore DatastoreController().set_driver("data/simulator.db") def load_plugin(self, name, search_dir = None): self.plugin.load_plugin(name, search_dir) def feed_data(self, data): self._socket.server_raw(data) def msg_channel(self, message): self._socket.server_user_response("PRIVMSG", "#simulator :" + message) def start(self): self._irc.connect() self._socket = self._irc.get_connection() def stop(self): self._irc.disconnect() self.plugin.unload_all() ## # Wait for all dispatched event threads to complete def wait_for_events(self): self.event.wait_for_pending_events() ## # Wait for all queued output to be sent to the server # (the simulated socket in this case) def flush(self): self._irc.flush_output()
class PluginController(Singleton): def construct(self, eventcontroller = None, configcontroller = None): self._loaded_plugins = {} if eventcontroller: self._eventcontroller = eventcontroller else: self._eventcontroller = EventController() if configcontroller: self._config = configcontroller else: self._config = ConfigController() ## # Unload all loaded plugins def unload_all(self): for plugin in self._loaded_plugins.keys(): self.unload_plugin(plugin) ## # Reload a plugin by name # @note The plugin will be unloaded but not loaded again if it's in a non-standard path def reload_plugin(self, name, search_dir = None): try: self.unload_plugin(name) except: pass return self.load_plugin(name, search_dir) def unload_plugin(self, name): name = name.strip().lower() if not self._loaded_plugins.has_key(name): raise PluginUnloadError("No such plugin loaded") basename, instance, import_name = self._loaded_plugins[name] # Release events related to this plugin self._eventcontroller.release_related(instance) # Try to call Cleanup if it exists try: instance.cleanup() except: pass # Delete instance del instance del self._loaded_plugins[name] for module in sys.modules.keys(): if module.startswith(import_name): del sys.modules[module] return True ## # Retrieve the names of all loaded plugins def get_loaded_plugins(self): return self._loaded_plugins.keys() ## # Generator for all candidate plugins # This will search through the given directory (or the plugin_paths if not specified) # and yield all candidate plugins in the form (path, name) # # @param search_dir Optional search directory. If not specified the plugin_paths from the # configuration will be used def plugin_candidates(self, search_dir = None): if search_dir: search_dirs = [search_dir] else: search_dirs = self._config.get('plugin_paths') ignore = shutil.ignore_patterns("*.pyc", "__init__.py", ".*") for search_dir in search_dirs: for root, dirs, files in os.walk(search_dir): ignored_files = ignore(root, files) files = [f for f in files if f not in ignored_files] # Look for plugins contained in directories for directory in dirs: path = root + "." + directory yield (root, directory) # We don't want to recurse dirs[:] = [] # Replace path separators with dots to allow # it to be loaded directly root = root.replace(os.sep, ".") # Look for plugins containes as single files for filename in files: base = filename.partition(".")[0] path = root + "." + base yield (root, base) ## # Find a plugin by name # # @param name Name of the plugin to search for # @param search_dir Optional search directory. If not specified the plugin_paths from the # configuration will be used def find_plugin(self, name, search_dir = None): for path, candidate_name in self.plugin_candidates(search_dir): if candidate_name.lower() == name.lower(): module_name = path + "." + candidate_name Logger.debug("Candidate plugin '%s'" % module_name) return module_name ## # Load a specified plugin # @param name Name of plugin file (case insensitive) # @param search_dir Directory too look for plugin. If not specified, plugin_path # from the configuration will be used def load_plugin(self, name, search_dir = None): name = name.strip() import_name = None if self._loaded_plugins.has_key(name): raise PluginLoadError("Plugin is already loaded") import_name = self.find_plugin(name, search_dir) if not import_name: raise PluginLoadError("No such plugin") basename = import_name.rpartition(".")[2] try: mod = __import__(import_name) cls = getattr(mod, basename) except Exception as e: # Remove the system-entry if import_name and sys.modules.has_key(import_name): del sys.modules[import_name] Logger.log_traceback(self) raise PluginLoadError("Failed to load " + import_name) # Find the plugin entry point for objname in dir(cls): obj = getattr(cls, objname) if objname != 'Plugin' and type(obj) == types.ClassType and issubclass(obj, Plugin): Logger.debug("Plugin entry is '%s'" % objname) instance = new.instance(obj) # Initialize plugin instance instance.store = DatastoreController().get_store(basename) instance.event = self._eventcontroller instance.config = self._config instance.nets = IRCNetsController() instance.plugin = self instance.__init__() self._loaded_plugins[basename.lower()] = (basename, instance, import_name) return True del sys.modules[import_name] raise PluginLoadError("Unable to find entry point")