@@ -11,9 +11,9 @@ class KwargParseException(Exception): | |||||
pass | pass | ||||
class Data(object): | class Data(object): | ||||
def __init__(self): | |||||
"""store data from an individual line received on IRC""" | |||||
self.line = str() | |||||
def __init__(self, line): | |||||
"""Store data from an individual line received on IRC.""" | |||||
self.line = line | |||||
self.chan = str() | self.chan = str() | ||||
self.nick = str() | self.nick = str() | ||||
self.ident = str() | self.ident = str() | ||||
@@ -5,29 +5,11 @@ | |||||
import os | import os | ||||
import traceback | import traceback | ||||
commands = [] | |||||
__all__ = ["load", "get_all", "check"] | |||||
def load_commands(connection): | |||||
"""load all valid command classes from irc/commmands/ into the commands variable""" | |||||
files = os.listdir(os.path.join("irc", "commands")) # get all files in irc/commands/ | |||||
files.sort() # alphabetically sort list of files | |||||
_commands = [] | |||||
for f in files: | |||||
if f.startswith("_") or not f.endswith(".py"): # ignore non-python files or files beginning with "_" | |||||
continue | |||||
module = f[:-3] # strip .py from end | |||||
try: | |||||
exec "from irc.commands import %s" % module | |||||
except: # importing the file failed for some reason... | |||||
print "Couldn't load file %s:" % f | |||||
traceback.print_exc() | |||||
continue | |||||
process_module(connection, eval(module)) # 'module' is a string, so get the actual object for processing by eval-ing it | |||||
pretty_cmnds = map(lambda c: c.__class__.__name__, commands) | |||||
print "Found %s command classes: %s." % (len(commands), ', '.join(pretty_cmnds)) | |||||
def process_module(connection, module): | |||||
def _process_module(connection, module): | |||||
"""go through all objects in a module and add valid command classes to the commands variable""" | """go through all objects in a module and add valid command classes to the commands variable""" | ||||
global commands | global commands | ||||
objects = dir(module) | objects = dir(module) | ||||
@@ -43,19 +25,41 @@ def process_module(connection, module): | |||||
for base in bases: | for base in bases: | ||||
if base.__name__ == "BaseCommand": # this inherits BaseCommand, so it must be a command class | if base.__name__ == "BaseCommand": # this inherits BaseCommand, so it must be a command class | ||||
command = obj(connection) # initialize a new command object | command = obj(connection) # initialize a new command object | ||||
commands.append(command) | |||||
_commands.append(command) | |||||
print "Added command class %s from %s..." % (this_obj, module.__name__) | print "Added command class %s from %s..." % (this_obj, module.__name__) | ||||
continue | continue | ||||
def get_commands(): | |||||
"""get our commands""" | |||||
return commands | |||||
def load(connection): | |||||
"""load all valid command classes from irc/commmands/ into the commands variable""" | |||||
files = os.listdir(os.path.join("irc", "commands")) # get all files in irc/commands/ | |||||
files.sort() # alphabetically sort list of files | |||||
for f in files: | |||||
if f.startswith("_") or not f.endswith(".py"): # ignore non-python files or files beginning with "_" | |||||
continue | |||||
module = f[:-3] # strip .py from end | |||||
try: | |||||
exec "from irc.commands import %s" % module | |||||
except: # importing the file failed for some reason... | |||||
print "Couldn't load file %s:" % f | |||||
traceback.print_exc() | |||||
continue | |||||
process_module(connection, eval(module)) # 'module' is a string, so get the actual object for processing by eval-ing it | |||||
pretty_cmnds = map(lambda c: c.__class__.__name__, commands) | |||||
print "Found %s command classes: %s." % (len(commands), ', '.join(pretty_cmnds)) | |||||
def get_all(): | |||||
"""Return our list of all commands.""" | |||||
return _commands | |||||
def check(hook, data): | def check(hook, data): | ||||
"""given an event on IRC, check if there's anything we can respond to by calling each command class""" | |||||
data.parse_args() # parse command arguments into data.command and data.args | |||||
"""Given an event on IRC, check if there's anything we can respond to by | |||||
calling each command class""" | |||||
# parse command arguments into data.command and data.args | |||||
data.parse_args() | |||||
for command in commands: | |||||
for command in _commands: | |||||
if hook in command.get_hooks(): | if hook in command.get_hooks(): | ||||
if command.check(data): | if command.check(data): | ||||
try: | try: | ||||
@@ -18,9 +18,9 @@ from within config's three global variables and one function: | |||||
""" | """ | ||||
import json | import json | ||||
from os import makedirs, path | |||||
from os import path | |||||
from lib import blowfish | |||||
import blowfish | |||||
script_dir = path.dirname(path.abspath(__file__)) | script_dir = path.dirname(path.abspath(__file__)) | ||||
root_dir = path.split(script_dir)[0] | root_dir = path.split(script_dir)[0] | ||||
@@ -149,7 +149,6 @@ def schedule(minute, hour, month_day, month, week_day): | |||||
def make_new_config(): | def make_new_config(): | ||||
"""Make a new config file based on the user's input.""" | """Make a new config file based on the user's input.""" | ||||
makedirs(config_dir) | |||||
encrypt = raw_input("Would you like to encrypt passwords stored in " + | encrypt = raw_input("Would you like to encrypt passwords stored in " + | ||||
"config.json? [y/n] ") | "config.json? [y/n] ") | ||||
@@ -1,7 +1,7 @@ | |||||
# -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
""" | """ | ||||
EarwigBot's IRC Front-end Component | |||||
EarwigBot's IRC Frontend Component | |||||
The IRC frontend runs on a normal IRC server and expects users to interact with | The IRC frontend runs on a normal IRC server and expects users to interact with | ||||
it and give it commands. Commands are stored as "command classes", subclasses | it and give it commands. Commands are stored as "command classes", subclasses | ||||
@@ -9,13 +9,16 @@ of BaseCommand in irc/base_command.py. All command classes are automatically | |||||
imported by irc/command_handler.py if they are in irc/commands. | imported by irc/command_handler.py if they are in irc/commands. | ||||
""" | """ | ||||
from re import findall | |||||
import re | |||||
from core import config | |||||
from irc import command_handler | |||||
from irc.classes import Connection, Data, BrokenSocketException | |||||
import config | |||||
import commands | |||||
from classes import Connection, Data, BrokenSocketException | |||||
__all__ = ["get_connection", "startup", "main"] | |||||
connection = None | connection = None | ||||
sender_regex = re.compile(":(.*?)!(.*?)@(.*?)\Z") | |||||
def get_connection(): | def get_connection(): | ||||
"""Return a new Connection() instance with information about our server | """Return a new Connection() instance with information about our server | ||||
@@ -31,16 +34,18 @@ def startup(conn): | |||||
command_handler, and then establish a connection with the IRC server.""" | command_handler, and then establish a connection with the IRC server.""" | ||||
global connection | global connection | ||||
connection = conn | connection = conn | ||||
command_handler.load_commands(connection) | |||||
commands.load(connection) | |||||
connection.connect() | connection.connect() | ||||
def main(): | def main(): | ||||
"""Main loop for the Frontend IRC Bot component. get_connection() and | |||||
startup() should have already been called.""" | |||||
"""Main loop for the frontend component. | |||||
get_connection() and startup() should have already been called before this. | |||||
""" | |||||
read_buffer = str() | read_buffer = str() | ||||
while 1: | while 1: | ||||
try: | |||||
try: | |||||
read_buffer = read_buffer + connection.get() | read_buffer = read_buffer + connection.get() | ||||
except BrokenSocketException: | except BrokenSocketException: | ||||
print "Socket has broken on front-end; restarting bot..." | print "Socket has broken on front-end; restarting bot..." | ||||
@@ -48,57 +53,60 @@ def main(): | |||||
lines = read_buffer.split("\n") | lines = read_buffer.split("\n") | ||||
read_buffer = lines.pop() | read_buffer = lines.pop() | ||||
for line in lines: # handle a single message from IRC | |||||
line = line.strip().split() | |||||
data = Data() # new Data() instance to store info about this line | |||||
data.line = line | |||||
if line[1] == "JOIN": | |||||
data.nick, data.ident, data.host = findall( | |||||
":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||||
data.chan = line[2][1:] | |||||
command_handler.check("join", data) # check for 'join' hooks in | |||||
# our commands | |||||
if line[1] == "PRIVMSG": | |||||
data.nick, data.ident, data.host = findall( | |||||
":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||||
data.msg = ' '.join(line[3:])[1:] | |||||
data.chan = line[2] | |||||
if data.chan == config.irc["frontend"]["nick"]: | |||||
# this is a privmsg to us, so set 'chan' as the nick of the | |||||
# sender, then check for private-only command hooks | |||||
data.chan = data.nick | |||||
command_handler.check("msg_private", data) | |||||
else: | |||||
# check for public-only command hooks | |||||
command_handler.check("msg_public", data) | |||||
# check for command hooks that apply to all messages | |||||
command_handler.check("msg", data) | |||||
# hardcode the !restart command (we can't restart from within | |||||
# an ordinary command) | |||||
if data.msg in ["!restart", ".restart"]: | |||||
if data.host in config.irc["permissions"]["owners"]: | |||||
print "Restarting bot per owner request..." | |||||
return | |||||
if line[0] == "PING": # if we are pinged, pong back to the server | |||||
connection.send("PONG %s" % line[1]) | |||||
if line[1] == "376": # we've successfully connected to the network | |||||
try: # if we're supposed to auth to nickserv, do that | |||||
ns_username = config.irc["frontend"]["nickservUsername"] | |||||
ns_password = config.irc["frontend"]["nickservPassword"] | |||||
except KeyError: | |||||
pass | |||||
else: | |||||
connection.say("NickServ", "IDENTIFY {0} {1}".format( | |||||
ns_username, ns_password)) | |||||
# join all of our startup channels | |||||
for chan in config.irc["frontend"]["channels"]: | |||||
connection.join(chan) | |||||
for line in lines: | |||||
_process_message(line) | |||||
def _process_message(line): | |||||
"""Process a single message from IRC.""" | |||||
line = line.strip().split() | |||||
data = Data(line) # new Data instance to store info about this line | |||||
if line[1] == "JOIN": | |||||
data.nick, data.ident, data.host = sender_regex.findall(line[0])[0] | |||||
data.chan = line[2][1:] | |||||
# Check for 'join' hooks in our commands: | |||||
commands.check("join", data) | |||||
elif line[1] == "PRIVMSG": | |||||
data.nick, data.ident, data.host = sender_regex.findall(line[0])[0] | |||||
data.msg = ' '.join(line[3:])[1:] | |||||
data.chan = line[2] | |||||
if data.chan == config.irc["frontend"]["nick"]: | |||||
# This is a privmsg to us, so set 'chan' as the nick of the, sender | |||||
# then check for private-only command hooks: | |||||
data.chan = data.nick | |||||
commands.check("msg_private", data) | |||||
else: | |||||
# Check for public-only command hooks: | |||||
commands.check("msg_public", data) | |||||
# Check for command hooks that apply to all messages: | |||||
commands.check("msg", data) | |||||
# Hardcode the !restart command (we can't restart from within an | |||||
# ordinary command): | |||||
if data.msg in ["!restart", ".restart"]: | |||||
if data.host in config.irc["permissions"]["owners"]: | |||||
print "Restarting bot per owner request..." | |||||
return | |||||
# If we are pinged, pong back to the server: | |||||
if line[0] == "PING": | |||||
connection.send("PONG %s" % line[1]) | |||||
# On successful connection to the server: | |||||
if line[1] == "376": | |||||
# If we're supposed to auth to NickServ, do that: | |||||
try: | |||||
username = config.irc["frontend"]["nickservUsername"] | |||||
password = config.irc["frontend"]["nickservPassword"] | |||||
except KeyError: | |||||
pass | |||||
else: | |||||
msg = " ".join(("IDENTIFY", username, password)) | |||||
connection.say("NickServ", msg) | |||||
# Join all of our startup channels: | |||||
for chan in config.irc["frontend"]["channels"]: | |||||
connection.join(chan) |
@@ -33,17 +33,11 @@ Else, the bot will stop, as no components are enabled. | |||||
import threading | import threading | ||||
import time | import time | ||||
import traceback | import traceback | ||||
import sys | |||||
import os | |||||
script_dir = os.path.dirname(os.path.abspath(__file__)) | |||||
root_dir = os.path.split(script_dir)[0] # the bot's "root" directory relative | |||||
# to its different components | |||||
sys.path.append(root_dir) # make sure we look in the root dir for modules | |||||
from core import config | |||||
from irc import frontend, watcher | |||||
from wiki import task_manager | |||||
import config | |||||
import frontend | |||||
import tasks | |||||
import watcher | |||||
f_conn = None | f_conn = None | ||||
w_conn = None | w_conn = None | ||||
@@ -70,7 +64,7 @@ def wiki_scheduler(): | |||||
time_start = time.time() | time_start = time.time() | ||||
now = time.gmtime(time_start) | now = time.gmtime(time_start) | ||||
task_manager.start_tasks(now) | |||||
tasks.schedule(now) | |||||
time_end = time.time() | time_end = time.time() | ||||
time_diff = time_start - time_end | time_diff = time_start - time_end | ||||
@@ -89,7 +83,7 @@ def irc_frontend(): | |||||
if "wiki_schedule" in config.components: | if "wiki_schedule" in config.components: | ||||
print "\nStarting wiki scheduler..." | print "\nStarting wiki scheduler..." | ||||
task_manager.load_tasks() | |||||
tasks.load() | |||||
t_scheduler = threading.Thread(target=wiki_scheduler) | t_scheduler = threading.Thread(target=wiki_scheduler) | ||||
t_scheduler.name = "wiki-scheduler" | t_scheduler.name = "wiki-scheduler" | ||||
t_scheduler.daemon = True | t_scheduler.daemon = True | ||||
@@ -123,7 +117,7 @@ def run(): | |||||
elif "wiki_schedule" in enabled: # run the scheduler on the main | elif "wiki_schedule" in enabled: # run the scheduler on the main | ||||
print "Starting wiki scheduler..." # thread, but also run the IRC | print "Starting wiki scheduler..." # thread, but also run the IRC | ||||
task_manager.load_tasks() # watcher on another thread iff it | |||||
tasks.load() # watcher on another thread iff it | |||||
if "irc_watcher" in enabled: # is enabled | if "irc_watcher" in enabled: # is enabled | ||||
print "\nStarting IRC watcher..." | print "\nStarting IRC watcher..." | ||||
t_watcher = threading.Thread(target=irc_watcher, args=()) | t_watcher = threading.Thread(target=irc_watcher, args=()) | ||||
@@ -1,9 +1,10 @@ | |||||
# -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
""" | """ | ||||
EarwigBot's Wiki Bot Task Manager | |||||
EarwigBot's Wiki Task Manager | |||||
This module provides some functions to run and load bot tasks from wiki/tasks/. | |||||
This package provides the wiki bot "tasks" EarwigBot runs. Here in __init__, | |||||
you can find some functions used to load and run these tasks. | |||||
""" | """ | ||||
import time | import time | ||||
@@ -11,28 +12,17 @@ import traceback | |||||
import threading | import threading | ||||
import os | import os | ||||
from core import config | |||||
import config | |||||
__all__ = ["load", "schedule", "start"] | |||||
# store loaded tasks as a dict where the key is the task name and the value is | # store loaded tasks as a dict where the key is the task name and the value is | ||||
# an instance of the task class (wiki.tasks.task_file.Task()) | # an instance of the task class (wiki.tasks.task_file.Task()) | ||||
task_list = dict() | |||||
_tasks = dict() | |||||
def load_tasks(): | |||||
"""Load all valid task classes from wiki/tasks/, and add them to the | |||||
task_list variable.""" | |||||
files = os.listdir(os.path.join("wiki", "tasks")) | |||||
files.sort() # alphabetically sort all files in wiki/tasks/ | |||||
for f in files: | |||||
if not os.path.isfile(os.path.join("wiki", "tasks", f)): | |||||
continue # ignore non-files | |||||
if f.startswith("_") or not f.endswith(".py"): | |||||
continue # ignore non-python files or files beginning with an _ | |||||
load_class_from_file(f) | |||||
print "Found %s tasks: %s." % (len(task_list), ', '.join(task_list.keys())) | |||||
def load_class_from_file(f): | |||||
def _load_class_from_file(f): | |||||
"""Look in a given file for the task class.""" | """Look in a given file for the task class.""" | ||||
global task_list | |||||
global _tasks | |||||
module = f[:-3] # strip .py from end | module = f[:-3] # strip .py from end | ||||
try: | try: | ||||
@@ -48,45 +38,58 @@ def load_class_from_file(f): | |||||
traceback.print_exc() | traceback.print_exc() | ||||
return | return | ||||
task_name = task_class.task_name | task_name = task_class.task_name | ||||
task_list[task_name] = task_class() | |||||
print "Added task %s from wiki/tasks/%s..." % (task_name, f) | |||||
_tasks[task_name] = task_class() | |||||
print "Added task %s from bot/tasks/%s..." % (task_name, f) | |||||
def _wrapper(task, **kwargs): | |||||
"""Wrapper for task classes: run the task and catch any errors.""" | |||||
try: | |||||
task.run(**kwargs) | |||||
except: | |||||
print "Task '{0}' raised an exception and had to stop:".format(task.task_name) | |||||
traceback.print_exc() | |||||
else: | |||||
print "Task '{0}' finished without error.".format(task.task_name) | |||||
def start_tasks(now=time.gmtime()): | |||||
def load(): | |||||
"""Load all valid task classes from bot/tasks/, and add them to the | |||||
_tasks variable.""" | |||||
files = os.listdir(os.path.join("bot", "tasks")) | |||||
files.sort() # alphabetically sort all files in wiki/tasks/ | |||||
for f in files: | |||||
if not os.path.isfile(os.path.join("bot", "tasks", f)): | |||||
continue # ignore non-files | |||||
if f.startswith("_") or not f.endswith(".py"): | |||||
continue # ignore non-python files or files beginning with an _ | |||||
load_class_from_file(f) | |||||
print "Found %s tasks: %s." % (len(_tasks), ', '.join(_tasks.keys())) | |||||
def schedule(now=time.gmtime()): | |||||
"""Start all tasks that are supposed to be run at a given time.""" | """Start all tasks that are supposed to be run at a given time.""" | ||||
tasks = config.schedule(now.tm_min, now.tm_hour, now.tm_mday, now.tm_mon, | tasks = config.schedule(now.tm_min, now.tm_hour, now.tm_mday, now.tm_mon, | ||||
now.tm_wday) # get list of tasks to run this turn | now.tm_wday) # get list of tasks to run this turn | ||||
for task in tasks: | for task in tasks: | ||||
if isinstance(task, list): # they've specified kwargs | |||||
start_task(task[0], **task[1]) # so pass those to start_task | |||||
if isinstance(task, list): # they've specified kwargs | |||||
start(task[0], **task[1]) # so pass those to start_task | |||||
else: # otherwise, just pass task_name | else: # otherwise, just pass task_name | ||||
start_task(task) | |||||
start(task) | |||||
def start_task(task_name, **kwargs): | |||||
def start(task_name, **kwargs): | |||||
"""Start a given task in a new thread. Pass args to the task's run() | """Start a given task in a new thread. Pass args to the task's run() | ||||
function.""" | function.""" | ||||
print "Starting task '{0}' in a new thread...".format(task_name) | print "Starting task '{0}' in a new thread...".format(task_name) | ||||
try: | try: | ||||
task = task_list[task_name] | |||||
task = _tasks[task_name] | |||||
except KeyError: | except KeyError: | ||||
print ("Couldn't find task '{0}': wiki/tasks/{0}.py does not exist.").format(task_name) | |||||
print ("Couldn't find task '{0}': bot/tasks/{0}.py does not exist.").format(task_name) | |||||
return | return | ||||
task_thread = threading.Thread(target=lambda: task_wrapper(task, **kwargs)) | |||||
task_thread = threading.Thread(target=lambda: _wrapper(task, **kwargs)) | |||||
task_thread.name = "{0} ({1})".format(task_name, time.strftime("%b %d %H:%M:%S")) | task_thread.name = "{0} ({1})".format(task_name, time.strftime("%b %d %H:%M:%S")) | ||||
# stop bot task threads automagically if the main bot stops | # stop bot task threads automagically if the main bot stops | ||||
task_thread.daemon = True | task_thread.daemon = True | ||||
task_thread.start() | task_thread.start() | ||||
def task_wrapper(task, **kwargs): | |||||
"""Wrapper for task classes: run the task and catch any errors.""" | |||||
try: | |||||
task.run(**kwargs) | |||||
except: | |||||
print "Task '{0}' raised an exception and had to stop:".format(task.task_name) | |||||
traceback.print_exc() | |||||
else: | |||||
print "Task '{0}' finished without error.".format(task.task_name) |
@@ -10,25 +10,30 @@ wiki bot tasks being started (listed in wiki/tasks/) or messages being sent to | |||||
channels in the IRC frontend. | channels in the IRC frontend. | ||||
""" | """ | ||||
from core import config | |||||
from irc.classes import Connection, RC, BrokenSocketException | |||||
from irc import watcher_logic | |||||
import config | |||||
from classes import Connection, RC, BrokenSocketException | |||||
import watcher_logic as logic | |||||
frontend_conn = None | frontend_conn = None | ||||
def get_connection(): | def get_connection(): | ||||
"""Return a new Connection() instance with information about our server | |||||
connection, but don't actually connect yet.""" | |||||
"""Return a new Connection() instance with connection information. | |||||
Don't actually connect yet. | |||||
""" | |||||
cf = config.irc["watcher"] | cf = config.irc["watcher"] | ||||
connection = Connection(cf["host"], cf["port"], cf["nick"], cf["ident"], | connection = Connection(cf["host"], cf["port"], cf["nick"], cf["ident"], | ||||
cf["realname"]) | cf["realname"]) | ||||
return connection | return connection | ||||
def main(connection, f_conn=None): | def main(connection, f_conn=None): | ||||
"""Main loop for the Watcher IRC Bot component. get_connection() should | |||||
have already been called and the connection should have been started with | |||||
connection.connect(). Accept the frontend connection as well as an optional | |||||
parameter in order to send messages directly to frontend IRC channels.""" | |||||
"""Main loop for the Watcher IRC Bot component. | |||||
get_connection() should have already been called and the connection should | |||||
have been started with connection.connect(). Accept the frontend connection | |||||
as well as an optional parameter in order to send messages directly to | |||||
frontend IRC channels. | |||||
""" | |||||
global frontend_conn | global frontend_conn | ||||
frontend_conn = f_conn | frontend_conn = f_conn | ||||
read_buffer = str() | read_buffer = str() | ||||
@@ -43,34 +48,42 @@ def main(connection, f_conn=None): | |||||
read_buffer = lines.pop() | read_buffer = lines.pop() | ||||
for line in lines: | for line in lines: | ||||
line = line.strip().split() | |||||
if line[1] == "PRIVMSG": | |||||
chan = line[2] | |||||
# ignore messages originating from channels not in our list, to | |||||
# prevent someone PMing us false data | |||||
if chan not in config.irc["watcher"]["channels"]: | |||||
continue | |||||
msg = ' '.join(line[3:])[1:] | |||||
rc = RC(msg) # new RC object to store this event's data | |||||
rc.parse() # parse a message into pagenames, usernames, etc. | |||||
process(rc) # report to frontend channels or start tasks | |||||
if line[0] == "PING": # if we are pinged, pong back to the server | |||||
connection.send("PONG %s" % line[1]) | |||||
# when we've finished starting up, join all watcher channels | |||||
if line[1] == "376": | |||||
for chan in config.irc["watcher"]["channels"]: | |||||
connection.join(chan) | |||||
def process(rc): | |||||
"""Process a message from IRC (technically, an RC object). The actual | |||||
processing is configurable, so we don't have that hard-coded here. We | |||||
simply call irc/watcher_logic.py's process() function and expect a list of | |||||
channels back, which we report the event data to.""" | |||||
_process_message(line) | |||||
def _process_message(line): | |||||
"""Process a single message from IRC.""" | |||||
line = line.strip().split() | |||||
if line[1] == "PRIVMSG": | |||||
chan = line[2] | |||||
# Ignore messages originating from channels not in our list, to prevent | |||||
# someone PMing us false data: | |||||
if chan not in config.irc["watcher"]["channels"]: | |||||
continue | |||||
msg = ' '.join(line[3:])[1:] | |||||
rc = RC(msg) # new RC object to store this event's data | |||||
rc.parse() # parse a message into pagenames, usernames, etc. | |||||
process_rc(rc) # report to frontend channels or start tasks | |||||
# If we are pinged, pong back to the server: | |||||
elif line[0] == "PING": | |||||
msg = " ".join(("PONG", line[1])) | |||||
connection.send(msg) | |||||
# When we've finished starting up, join all watcher channels: | |||||
elif line[1] == "376": | |||||
for chan in config.irc["watcher"]["channels"]: | |||||
connection.join(chan) | |||||
def process_rc(rc): | |||||
"""Process a recent change event from IRC (or, an RC object). | |||||
The actual processing is configurable, so we don't have that hard-coded | |||||
here. We simply call watcher_logic's process() function and expect a list | |||||
of channels back, which we report the event data to. | |||||
""" | |||||
chans = watcher_logic.process(rc) | chans = watcher_logic.process(rc) | ||||
if chans and frontend_conn: | if chans and frontend_conn: | ||||
pretty = rc.get_pretty() | pretty = rc.get_pretty() | ||||
@@ -12,7 +12,7 @@ sense for this sort of thing... so... | |||||
import re | import re | ||||
from wiki import task_manager as tasks | |||||
import tasks | |||||
afc_prefix = "wikipedia( talk)?:(wikiproject )?articles for creation" | afc_prefix = "wikipedia( talk)?:(wikiproject )?articles for creation" | ||||
@@ -39,8 +39,8 @@ def process(rc): | |||||
chans.update(("##earwigbot", "#wikipedia-en-afc")) | chans.update(("##earwigbot", "#wikipedia-en-afc")) | ||||
if r_page.search(page_name): | if r_page.search(page_name): | ||||
tasks.start_task("afc_statistics", action="process_edit", page=rc.page) | |||||
tasks.start_task("afc_copyvios", action="process_edit", page=rc.page) | |||||
tasks.start("afc_statistics", action="process_edit", page=rc.page) | |||||
tasks.start("afc_copyvios", action="process_edit", page=rc.page) | |||||
chans.add("#wikipedia-en-afc") | chans.add("#wikipedia-en-afc") | ||||
elif r_ffu.match(page_name): | elif r_ffu.match(page_name): | ||||
@@ -50,22 +50,22 @@ def process(rc): | |||||
chans.add("#wikipedia-en-afc") | chans.add("#wikipedia-en-afc") | ||||
elif rc.flags == "move" and (r_move1.match(comment) or | elif rc.flags == "move" and (r_move1.match(comment) or | ||||
r_move2.match(comment)): | |||||
r_move2.match(comment)): | |||||
p = r_moved_pages.findall(rc.comment)[0] | p = r_moved_pages.findall(rc.comment)[0] | ||||
tasks.start_task("afc_statistics", action="process_move", pages=p) | |||||
tasks.start_task("afc_copyvios", action="process_move", pages=p) | |||||
tasks.start("afc_statistics", action="process_move", pages=p) | |||||
tasks.start("afc_copyvios", action="process_move", pages=p) | |||||
chans.add("#wikipedia-en-afc") | chans.add("#wikipedia-en-afc") | ||||
elif rc.flags == "delete" and r_delete.match(comment): | elif rc.flags == "delete" and r_delete.match(comment): | ||||
p = r_deleted_page.findall(rc.comment)[0] | p = r_deleted_page.findall(rc.comment)[0] | ||||
tasks.start_task("afc_statistics", action="process_delete", page=p) | |||||
tasks.start_task("afc_copyvios", action="process_delete", page=p) | |||||
tasks.start("afc_statistics", action="process_delete", page=p) | |||||
tasks.start("afc_copyvios", action="process_delete", page=p) | |||||
chans.add("#wikipedia-en-afc") | chans.add("#wikipedia-en-afc") | ||||
elif rc.flags == "restore" and r_restore.match(comment): | elif rc.flags == "restore" and r_restore.match(comment): | ||||
p = r_restored_page.findall(rc.comment)[0] | p = r_restored_page.findall(rc.comment)[0] | ||||
tasks.start_task("afc_statistics", action="process_restore", page=p) | |||||
tasks.start_task("afc_copyvios", action="process_restore", page=p) | |||||
tasks.start("afc_statistics", action="process_restore", page=p) | |||||
tasks.start("afc_copyvios", action="process_restore", page=p) | |||||
chans.add("#wikipedia-en-afc") | chans.add("#wikipedia-en-afc") | ||||
elif rc.flags == "protect" and r_protect.match(comment): | elif rc.flags == "protect" and r_protect.match(comment): | ||||
@@ -20,7 +20,7 @@ from os import path | |||||
from sys import executable | from sys import executable | ||||
from time import sleep | from time import sleep | ||||
from core.config import verify_config | |||||
from bot import config | |||||
__author__ = "Ben Kurtovic" | __author__ = "Ben Kurtovic" | ||||
__copyright__ = "Copyright (C) 2009, 2010, 2011 by Ben Kurtovic" | __copyright__ = "Copyright (C) 2009, 2010, 2011 by Ben Kurtovic" | ||||
@@ -28,12 +28,12 @@ __license__ = "MIT License" | |||||
__version__ = "0.1-dev" | __version__ = "0.1-dev" | ||||
__email__ = "ben.kurtovic@verizon.net" | __email__ = "ben.kurtovic@verizon.net" | ||||
bot_script = path.join(path.dirname(path.abspath(__file__)), "core", "main.py") | |||||
bot_script = path.join(path.dirname(path.abspath(__file__)), "bot", "main.py") | |||||
def main(): | def main(): | ||||
print "EarwigBot v{0}\n".format(__version__) | print "EarwigBot v{0}\n".format(__version__) | ||||
is_encrypted = verify_config() | |||||
is_encrypted = config.verify_config() | |||||
if is_encrypted: # passwords in the config file are encrypted | if is_encrypted: # passwords in the config file are encrypted | ||||
key = getpass("Enter key to unencrypt bot passwords: ") | key = getpass("Enter key to unencrypt bot passwords: ") | ||||
else: | else: | ||||