@@ -1,23 +1,34 @@
#! /usr/bin/python
# -*- coding: utf-8 -*-
## EarwigBot's Core
## EarwigBot has three components that can run independently of each other: an
## IRC front-end, an IRC watcher, and a wiki scheduler.
## * The IRC front-end runs on a normal IRC server and expects users to
## interact with it/give it commands.
## * The IRC watcher runs on a wiki recent-changes server and listens for
## edits. Users cannot interact with this part of the bot.
## * The wiki scheduler runs wiki-editing bot tasks in separate threads at
## user-defined times through a cron-like interface.
## There is a "priority" system here:
## 1. If the IRC frontend is enabled, it will run on the main thread, and the
## IRC watcher and wiki scheduler (if enabled) will run on separate threads.
## 2. If the wiki scheduler is enabled, it will run on the main thread, and the
## IRC watcher (if enabled) will run on a separate thread.
## 3. If the IRC watcher is enabled, it will run on the main (and only) thread.
## Else, the bot will stop, as no components are enabled.
"""
EarwigBot's Core
This (should) not be run directly; the wrapper in "earwigbot.py" is preferred,
but it should work fine alone, as long as you enter the password-unlock key at
the initial hidden prompt.
The core is essentially responsible for starting the various bot components
(irc, scheduler, etc) and making sure they are all happy. An explanation of the
different components follows:
EarwigBot has three components that can run independently of each other: an IRC
front-end, an IRC watcher, and a wiki scheduler.
* The IRC front-end runs on a normal IRC server and expects users to interact
with it/give it commands.
* The IRC watcher runs on a wiki recent-changes server and listens for edits.
Users cannot interact with this part of the bot.
* The wiki scheduler runs wiki-editing bot tasks in separate threads at
user-defined times through a cron-like interface.
There is a "priority" system here:
1. If the IRC frontend is enabled, it will run on the main thread, and the IRC
watcher and wiki scheduler (if enabled) will run on separate threads.
2. If the wiki scheduler is enabled, it will run on the main thread, and the
IRC watcher (if enabled) will run on a separate thread.
3. If the IRC watcher is enabled, it will run on the main (and only) thread.
Else, the bot will stop, as no components are enabled.
"""
import threading
import time
@@ -25,12 +36,14 @@ import traceback
import sys
import os
parent_dir = os.path.split(sys.path[0])[0]
sys.path.append(parent_dir) # make sure we look in the parent directory for modules
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
# from irc import frontend, watcher
# from wiki import task_manager
f_conn = None
w_conn = None
@@ -39,16 +52,15 @@ def irc_watcher(f_conn):
"""Function to handle the IRC watcher as another thread (if frontend and/or
scheduler is enabled), otherwise run as the main thread."""
global w_conn
print "\nStarting IRC watcher..."
while 1: # restart the watcher component if (just) it breaks
while 1: # restart the watcher component if it breaks (and nothing else)
w_conn = watcher.get_connection()
w_conn.connect()
print # print a blank line her e to signify that the bot has finished starting up
print # blank lin e to signify that the bot has finished starting up
try:
watcher.main(w_conn, f_conn)
except:
traceback.print_exc()
time.sleep(5) # sleep a bit before restarting watcher
time.sleep(5) # sleep a bit before restarting watcher
print "\nWatcher has stopped; restarting component..."
def wiki_scheduler():
@@ -57,24 +69,24 @@ def wiki_scheduler():
while 1:
time_start = time.time()
now = time.gmtime(time_start)
task_manager.start_tasks(now)
time_end = time.time()
time_diff = time_start - time_end
if time_diff < 60: # sleep until the next minute
if time_diff < 60: # sleep until the next minute
time.sleep(60 - time_diff)
def irc_frontend():
def irc_frontend(components ):
"""If the IRC frontend is enabled, make it run on our primary thread, and
enable the wiki scheduler and IRC watcher on new threads if they are
enabled."""
global f_conn
print "\n Starting IRC frontend..."
print "Starting IRC frontend..."
f_conn = frontend.get_connection()
frontend.startup(f_conn)
if enable_wiki_schedule:
print "\nStarting wiki scheduler..."
task_manager.load_tasks()
@@ -82,8 +94,9 @@ def irc_frontend():
t_scheduler.name = "wiki-scheduler"
t_scheduler.daemon = True
t_scheduler.start()
if enable_irc_watcher:
print "\nStarting IRC watcher..."
t_watcher = threading.Thread(target=irc_watcher, args=(f_conn,))
t_watcher.name = "irc-watcher"
t_watcher.daemon = True
@@ -94,32 +107,41 @@ def irc_frontend():
if enable_irc_watcher:
w_conn.close()
f_conn.close()
def run():
config.load()
components = config.config["main"]
if components["enable_irc_frontend"]: # make the frontend run on our primary thread if enabled, and enable additional components through that function
irc_frontend()
elif components["enable_wiki_schedule"]: # the scheduler is enabled - run it on the main thread, but also run the IRC watcher on another thread if it is enabled
print "\nStarting wiki scheduler..."
task_manager.load_tasks()
if enable_irc_watcher:
try:
key = raw_input() # wait for our password unlock key from the bot's
except EOFError: # wrapper
key = None
config.parse_config(key) # load data from the config file and parse it
# using the unlock key
components = None
if components["irc_frontend"]: # make the frontend run on our primary
irc_frontend(components) # thread if enabled, and enable additional
# components through that function
elif components["wiki_schedule"]: # run the scheduler on the main
print "Starting wiki scheduler..." # thread, but also run the IRC
task_manager.load_tasks() # watcher on another thread iff it
if enable_irc_watcher: # is enabled
print "\nStarting IRC watcher..."
t_watcher = threading.Thread(target=irc_watcher, args=(f_conn,))
t_watcher.name = "irc-watcher"
t_watcher.daemon = True
t_watcher.start()
wiki_scheduler()
elif components["enable_irc_watcher"]: # the IRC watcher is our only enabled component, so run its function only and don't worry about anything else
irc_watcher()
elif components["irc_watcher"]: # the IRC watcher is our only enabled
print "Starting IRC watcher..." # component, so run its function only
irc_watcher() # and don't worry about anything else
else: # nothing is enabled!
exit("\nNo bot parts are enabled; stopping...")
print "No bot parts are enabled; stopping..."
if __name__ == "__main__":
try:
run()
except KeyboardInterrupt:
exit("\nKeyboardInterrupt: stopping main bot loop.")
print "\nKeyboardInterrupt: stopping main bot loop."
exit(1)