def setUp(self): self.conn = Queue.Queue() self.conn.out = '' self.wrapper = IrcWrapper(self.conn, 'test', 'tester', None, ['#test'], None) self.assertTrue(self.wrapper.nick == 'test') self.assertTrue(self.wrapper.realname == 'tester') self.assertTrue(self.wrapper.channels == ['#test'])
def _create_connection(self): self.connection = TcpClient(self.config['SERVER'], self.config['PORT'], self.config['SSL'], self.config['TIMEOUT'], logger=self.logger) self.irc = IrcWrapper(self.connection, self.config['NICK'], self.config['REALNAME'], self.config['PASSWORD'], self.config['CHANNELS'], logger=self.logger, user=self.config['USER'])
def setUp(self): self.conn = Queue.Queue() self.conn.out = "" self.wrapper = IrcWrapper(self.conn, "test", "tester", ["#test"], None) self.assertTrue(self.wrapper.nick == "test") self.assertTrue(self.wrapper.realname == "tester") self.assertTrue(self.wrapper.channels == ["#test"])
def _create_connection(self): self.connection = TcpClient(self.config['SERVER'], self.config['PORT'], self.config['SSL'], self.config['TIMEOUT'], logger=self.logger) self.irc = IrcWrapper(self.connection, self.config['NICK'], self.config['REALNAME'], self.config['PASSWORD'], self.config['CHANNELS'], logger=self.logger)
class IrcWrapperTestCase(unittest.TestCase): '''This test case is used to test the IRC wrapper methods.''' def setUp(self): self.conn = Queue.Queue() self.conn.out = '' self.wrapper = IrcWrapper(self.conn, 'test', 'tester', None, ['#test'], None) self.assertTrue(self.wrapper.nick == 'test') self.assertTrue(self.wrapper.realname == 'tester') self.assertTrue(self.wrapper.channels == ['#test']) def test_register(self): self.wrapper._register() nick = 'NICK test\r\n' user = '******' self.assertTrue(nick in self.wrapper.out_buffer and user in self.wrapper.out_buffer) self.assertEqual(nick, self.wrapper.out_buffer.split('\r\n')[0] + '\r\n') self.assertEqual(user, self.wrapper.out_buffer.split('\r\n')[1] + '\r\n') def test_send(self): pass def test_recv(self): pass def test_parse_line(self): line = 'PRIVMSG #testing :test message' prefix, command, args = self.wrapper._parse_line(line) self.assertEqual(prefix, '') self.assertEqual(command, 'PRIVMSG') self.assertEqual(args, ['#testing', 'test message']) line = ':server.example.net NOTICE Auth :*** Looking up your hostname...' prefix, command, args = self.wrapper._parse_line(line) self.assertEqual(prefix, 'server.example.net') self.assertEqual(command, 'NOTICE') self.assertEqual(args, ['Auth', '*** Looking up your hostname...']) def test_send_line(self): line = 'test' self.wrapper._send_line(line) self.assertEqual('test\r\n', self.wrapper.out_buffer) def test_send_lines(self): lines = ['foo', 'bar', 'baz'] expected_result = 'foo\r\nbar\r\nbaz\r\n' self.wrapper._send_lines(lines) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_run(self): pass def test_send_command(self): command = 'PRIVMSG' args = ['#test' + ' :' + 'test'] expected_result = 'PRIVMSG #test :test\r\n' self.wrapper.send_command(command, args) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_send_message(self): recipient = '#test' message = 'test' expected_result = 'PRIVMSG #test :test\r\n' self.wrapper.send_message(recipient, message) self.assertEqual(expected_result, self.wrapper.out_buffer) self.wrapper.out_buffer = '' recipient = '#test' message = 'dances' expected_result = 'PRIVMSG #test :\x01ACTION dances\x01\r\n' self.wrapper.send_message(recipient, message, action=True) self.assertEqual(expected_result, self.wrapper.out_buffer) self.wrapper.out_buffer = '' recipient = '#test' message = 'attention!' expected_result = 'NOTICE #test :attention!\r\n' self.wrapper.send_message(recipient, message, notice=True) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_send_notice(self): pass def test_send_action(self): pass
class Bot(object): # used to track the instance of the Bot class __shared_state = {} # initialize the logger as None logger = None # initlialize the config as None config = None # initalize the plugin as None plugin = None # initalize the reloader as None reloader = None # set our root path root_path = os.path.abspath('') # base configuration default_config = {'SERVER': '', 'PORT': 6667, 'PASSWORD': None, 'SSL': False, 'TIMEOUT': 300, 'NICK': '', 'USER': None, 'REALNAME': '', 'CHANNELS': [], 'PLUGINS': [], 'EVENTS': [], 'REGEX': [], 'MAX_WORKERS': 7, 'MIN_WORKERS': 3, 'CMD_PREFIX': '.'} def __init__(self): self.__dict__ = self.__shared_state if self.logger is None: self.logger = create_logger() # configure the bot instance if self.config is None: self.config = Config(self, self.root_path, self.default_config) else: # make sure we clear these upon reloads self.config['PLUGINS'] = [] self.config['EVENTS'] = [] self.config['REGEX'] = [] # initialize the plugin handler if self.plugin is None: self.plugin = PluginHandler(self) # initalize the reload handler if self.reloader is None: self.reloader = ReloadHandler(self) def _create_connection(self): self.connection = TcpClient(self.config['SERVER'], self.config['PORT'], self.config['SSL'], self.config['TIMEOUT'], logger=self.logger) self.irc = IrcWrapper(self.connection, self.config['NICK'], self.config['REALNAME'], self.config['PASSWORD'], self.config['CHANNELS'], logger=self.logger, user=self.config['USER']) def _parse_input(self, wait=0.01): '''This internal method handles the parsing of commands and events. Hooks for commands are prefixed with a character, by default `.`. This may be overriden by specifying `prefix`. A context is maintained by our IRC wrapper, `IrcWrapper`; referenced as `self.irc`. In order to prevent a single line from being parsed repeatedly a variable `stale` is set to either True or False. If the context is fresh, i.e. not `stale`, we loop over the line looking for matches to plugins. Once the context is consumed, we set the context variable `stale` to True. ''' prefix = self.config['CMD_PREFIX'] while True: time.sleep(wait) with self.irc.lock: args = self.irc.context.get('args') command = self.irc.context.get('command') message = self.irc.context.get('message') raw = self.irc.context.get('raw') while not self.context_stale and args: # process regex for regex in self.config['REGEX']: hook = regex['hook'] search = re.search(hook, raw) if not search: continue regex['context'] = dict(self.irc.context) regex['context']['regex_search'] = search self.plugin.enqueue_plugin(regex, hook, raw, regex=True) # process for a message if message.startswith(prefix): for plugin in self.config['PLUGINS']: plugin['context'] = dict(self.irc.context) hook = prefix + plugin['hook'] self.plugin.enqueue_plugin(plugin, hook, message) # process for a command if command and command.isupper(): for event in self.config['EVENTS']: event['context'] = dict(self.irc.context) hook = event['hook'] self.plugin.enqueue_plugin(event, hook, command) # irc context consumed; mark it as such self.irc.context['stale'] = True @property def context_stale(self): return self.irc.context.get('stale', True) def command(self, hook=None, **kwargs): '''This method provides a decorator that can be used to load a function into the global plugins list. If the `hook` parameter is provided the decorator will assign the hook key to the value of `hook`, update the `plugin` dict, and then return the wrapped function to the wrapper. Therein the plugin dictionary is updated with the `func` key whose value is set to the wrapped function. Otherwise if no `hook` parameter is passed the, `hook` is assumed to be the wrapped function and handled accordingly. ''' plugin = {} def wrapper(func): plugin.setdefault('hook', func.func_name) plugin['funcs'] = [func] self.plugin._update_plugin(plugin, 'PLUGINS') return func if kwargs or not inspect.isfunction(hook): if hook: plugin['hook'] = hook plugin.update(kwargs) return wrapper else: return wrapper(hook) def event(self, hook, **kwargs): '''This method provides a decorator that can be used to load a function into the global events list. It assumes one parameter, `hook`, i.e. the event you wish to bind this wrapped function to. For example, JOIN, which would call the function on all JOIN events. ''' plugin = {} def wrapper(func): plugin['funcs'] = [func] self.plugin._update_plugin(plugin, 'EVENTS') return func plugin['hook'] = hook plugin.update(kwargs) return wrapper def regex(self, hook, **kwargs): '''Takes a regular expression as a hook.''' plugin = {} def wrapper(func): plugin['funcs'] = [func] self.plugin._update_plugin(plugin, 'REGEX') return func plugin['hook'] = hook plugin.update(kwargs) return wrapper def add_command(self, hook, func): self.plugin._add_plugin(hook, func, command=True) def add_event(self, hook, func): self.plugin._add_plugin(hook, func, event=True) def add_regex(self, hook, func): self.plugin._add_plugin(hook, func, regex=True) def remove_command(self, hook, func): self.plugin._remove_plugin(hook, func, command=True) def remove_event(self, hook, func): self.plugin._remove_plugin(hook, func, event=True) def remove_regex(self, hook, func): self.plugin._remove_plugin(hook, func, regex=True) def reply(self, message, context, action=False, notice=False, recipient=None, line_limit=400): # conditionally set the recipient automatically if recipient is None: if context['sender'].startswith('#'): recipient = context['sender'] else: recipient = context['user'] def messages(message): message, extra = message[:line_limit], message[line_limit:] yield message if extra: for message in messages(extra): yield message for message in messages(message): self.irc.send_message(recipient, message, action, notice) def run(self, wait=0.1): # create connection self._create_connection() # connect self.connection.connect() # start the irc wrapper self.irc.run() # start the input parsing loop in a new thread thread.start_new_thread(self._parse_input, ()) while True: time.sleep(wait)
class Bot(object): # used to track the instance of the Bot class __shared_state = {} # initialize the logger as None logger = None # initlialize the config as None config = None # initalize the plugin as None plugin = None # initalize the reloader as None reloader = None # set our root path root_path = os.path.abspath('') # base configuration default_config = { 'SERVER': '', 'PORT': 6667, 'PASSWORD': None, 'SSL': False, 'TIMEOUT': 300, 'NICK': '', 'USER': None, 'REALNAME': '', 'CHANNELS': [], 'PLUGINS': [], 'EVENTS': [], 'REGEX': [], 'MAX_WORKERS': 7, 'MIN_WORKERS': 3, 'CMD_PREFIX': '.' } def __init__(self): self.__dict__ = self.__shared_state if self.logger is None: self.logger = create_logger() # configure the bot instance if self.config is None: self.config = Config(self, self.root_path, self.default_config) else: # make sure we clear these upon reloads self.config['PLUGINS'] = [] self.config['EVENTS'] = [] self.config['REGEX'] = [] # initialize the plugin handler if self.plugin is None: self.plugin = PluginHandler(self) # initalize the reload handler if self.reloader is None: self.reloader = ReloadHandler(self) def _create_connection(self): self.connection = TcpClient(self.config['SERVER'], self.config['PORT'], self.config['SSL'], self.config['TIMEOUT'], logger=self.logger) self.irc = IrcWrapper(self.connection, self.config['NICK'], self.config['REALNAME'], self.config['PASSWORD'], self.config['CHANNELS'], logger=self.logger, user=self.config['USER']) def _parse_input(self, wait=0.01): '''This internal method handles the parsing of commands and events. Hooks for commands are prefixed with a character, by default `.`. This may be overriden by specifying `prefix`. A context is maintained by our IRC wrapper, `IrcWrapper`; referenced as `self.irc`. In order to prevent a single line from being parsed repeatedly a variable `stale` is set to either True or False. If the context is fresh, i.e. not `stale`, we loop over the line looking for matches to plugins. Once the context is consumed, we set the context variable `stale` to True. ''' prefix = self.config['CMD_PREFIX'] while True: time.sleep(wait) with self.irc.lock: args = self.irc.context.get('args') command = self.irc.context.get('command') message = self.irc.context.get('message') raw = self.irc.context.get('raw') while not self.context_stale and args: # process regex for regex in self.config['REGEX']: hook = regex['hook'] search = re.search(hook, raw) if not search: continue regex['context'] = dict(self.irc.context) regex['context']['regex_search'] = search self.plugin.enqueue_plugin(regex, hook, raw, regex=True) # process for a message if message.startswith(prefix): for plugin in self.config['PLUGINS']: plugin['context'] = dict(self.irc.context) hook = prefix + plugin['hook'] self.plugin.enqueue_plugin(plugin, hook, message) # process for a command if command and command.isupper(): for event in self.config['EVENTS']: event['context'] = dict(self.irc.context) hook = event['hook'] self.plugin.enqueue_plugin(event, hook, command) # irc context consumed; mark it as such self.irc.context['stale'] = True @property def context_stale(self): return self.irc.context.get('stale', True) def command(self, hook=None, **kwargs): '''This method provides a decorator that can be used to load a function into the global plugins list. If the `hook` parameter is provided the decorator will assign the hook key to the value of `hook`, update the `plugin` dict, and then return the wrapped function to the wrapper. Therein the plugin dictionary is updated with the `func` key whose value is set to the wrapped function. Otherwise if no `hook` parameter is passed the, `hook` is assumed to be the wrapped function and handled accordingly. ''' plugin = {} def wrapper(func): plugin.setdefault('hook', func.func_name) plugin['funcs'] = [func] self.plugin._update_plugin(plugin, 'PLUGINS') return func if kwargs or not inspect.isfunction(hook): if hook: plugin['hook'] = hook plugin.update(kwargs) return wrapper else: return wrapper(hook) def event(self, hook, **kwargs): '''This method provides a decorator that can be used to load a function into the global events list. It assumes one parameter, `hook`, i.e. the event you wish to bind this wrapped function to. For example, JOIN, which would call the function on all JOIN events. ''' plugin = {} def wrapper(func): plugin['funcs'] = [func] self.plugin._update_plugin(plugin, 'EVENTS') return func plugin['hook'] = hook plugin.update(kwargs) return wrapper def regex(self, hook, **kwargs): '''Takes a regular expression as a hook.''' plugin = {} def wrapper(func): plugin['funcs'] = [func] self.plugin._update_plugin(plugin, 'REGEX') return func plugin['hook'] = hook plugin.update(kwargs) return wrapper def add_command(self, hook, func): self.plugin._add_plugin(hook, func, command=True) def add_event(self, hook, func): self.plugin._add_plugin(hook, func, event=True) def add_regex(self, hook, func): self.plugin._add_plugin(hook, func, regex=True) def remove_command(self, hook, func): self.plugin._remove_plugin(hook, func, command=True) def remove_event(self, hook, func): self.plugin._remove_plugin(hook, func, event=True) def remove_regex(self, hook, func): self.plugin._remove_plugin(hook, func, regex=True) def reply(self, message, context, action=False, notice=False, recipient=None, line_limit=400): # conditionally set the recipient automatically if recipient is None: if context['sender'].startswith('#'): recipient = context['sender'] else: recipient = context['user'] def messages(message): message, extra = message[:line_limit], message[line_limit:] yield message if extra: for message in messages(extra): yield message for message in messages(message): self.irc.send_message(recipient, message, action, notice) def run(self, wait=0.1): # create connection self._create_connection() # connect self.connection.connect() # start the irc wrapper self.irc.run() # start the input parsing loop in a new thread thread.start_new_thread(self._parse_input, ()) while True: time.sleep(wait)
class IrcWrapperTestCase(unittest.TestCase): '''This test case is used to test the IRC wrapper methods.''' def setUp(self): self.conn = Queue.Queue() self.conn.out = '' self.wrapper = IrcWrapper(self.conn, 'test', 'tester', None, ['#test'], None) self.assertTrue(self.wrapper.nick == 'test') self.assertTrue(self.wrapper.realname == 'tester') self.assertTrue(self.wrapper.channels == ['#test']) def test_register(self): self.wrapper._register() nick = 'NICK test\r\n' user = '******' self.assertTrue((nick and user) in self.wrapper.out_buffer) self.assertEqual(nick, self.wrapper.out_buffer.split('\r\n')[0] + '\r\n') self.assertEqual(user, self.wrapper.out_buffer.split('\r\n')[1] + '\r\n') def test_send(self): pass def test_recv(self): pass def test_parse_line(self): line = 'PRIVMSG #testing :test message' prefix, command, args = self.wrapper._parse_line(line) self.assertEqual(prefix, '') self.assertEqual(command, 'PRIVMSG') self.assertEqual(args, ['#testing', 'test message']) line = ':server.example.net NOTICE Auth :*** Looking up your hostname...' prefix, command, args = self.wrapper._parse_line(line) self.assertEqual(prefix, 'server.example.net') self.assertEqual(command, 'NOTICE') self.assertEqual(args, ['Auth', '*** Looking up your hostname...']) def test_send_line(self): line = 'test' self.wrapper._send_line(line) self.assertEqual('test\r\n', self.wrapper.out_buffer) def test_send_lines(self): lines = ['foo', 'bar', 'baz'] expected_result = 'foo\r\nbar\r\nbaz\r\n' self.wrapper._send_lines(lines) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_run(self): pass def test_send_command(self): command = 'PRIVMSG' args = ['#test' + ' :' + 'test'] expected_result = 'PRIVMSG #test :test\r\n' self.wrapper.send_command(command, args) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_send_message(self): recipient = '#test' message = 'test' expected_result = 'PRIVMSG #test :test\r\n' self.wrapper.send_message(recipient, message) self.assertEqual(expected_result, self.wrapper.out_buffer) self.wrapper.out_buffer = '' recipient = '#test' message = 'dances' expected_result = 'PRIVMSG #test :\x01ACTION dances\x01\r\n' self.wrapper.send_message(recipient, message, action=True) self.assertEqual(expected_result, self.wrapper.out_buffer) self.wrapper.out_buffer = '' recipient = '#test' message = 'attention!' expected_result = 'NOTICE #test :attention!\r\n' self.wrapper.send_message(recipient, message, notice=True) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_send_notice(self): pass def test_send_action(self): pass
class IrcWrapperTestCase(unittest.TestCase): """This test case is used to test the IRC wrapper methods.""" def setUp(self): self.conn = Queue.Queue() self.conn.out = "" self.wrapper = IrcWrapper(self.conn, "test", "tester", ["#test"], None) self.assertTrue(self.wrapper.nick == "test") self.assertTrue(self.wrapper.realname == "tester") self.assertTrue(self.wrapper.channels == ["#test"]) def test_register(self): self.wrapper._register() nick = "NICK test\r\n" user = "******" self.assertTrue((nick and user) in self.wrapper.out_buffer) self.assertEqual(nick, self.wrapper.out_buffer.split("\r\n")[0] + "\r\n") self.assertEqual(user, self.wrapper.out_buffer.split("\r\n")[1] + "\r\n") def test_send(self): pass def test_recv(self): pass def test_parse_line(self): line = "PRIVMSG #testing :test message" prefix, command, args = self.wrapper._parse_line(line) self.assertEqual(prefix, "") self.assertEqual(command, "PRIVMSG") self.assertEqual(args, ["#testing", "test message"]) line = ":server.example.net NOTICE Auth :*** Looking up your hostname..." prefix, command, args = self.wrapper._parse_line(line) self.assertEqual(prefix, "server.example.net") self.assertEqual(command, "NOTICE") self.assertEqual(args, ["Auth", "*** Looking up your hostname..."]) def test_send_line(self): line = "test" self.wrapper._send_line(line) self.assertEqual("test\r\n", self.wrapper.out_buffer) def test_send_lines(self): lines = ["foo", "bar", "baz"] expected_result = "foo\r\nbar\r\nbaz\r\n" self.wrapper._send_lines(lines) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_run(self): pass def test_send_command(self): command = "PRIVMSG" args = ["#test" + " :" + "test"] expected_result = "PRIVMSG #test :test\r\n" self.wrapper.send_command(command, args) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_send_message(self): recipient = "#test" message = "test" expected_result = "PRIVMSG #test :test\r\n" self.wrapper.send_message(recipient, message) self.assertEqual(expected_result, self.wrapper.out_buffer) self.wrapper.out_buffer = "" recipient = "#test" message = "dances" expected_result = "PRIVMSG #test :\x01ACTION dances\x01\r\n" self.wrapper.send_message(recipient, message, action=True) self.assertEqual(expected_result, self.wrapper.out_buffer) self.wrapper.out_buffer = "" recipient = "#test" message = "attention!" expected_result = "NOTICE #test :attention!\r\n" self.wrapper.send_message(recipient, message, notice=True) self.assertEqual(expected_result, self.wrapper.out_buffer) def test_send_notice(self): pass def test_send_action(self): pass