aboutsummaryrefslogtreecommitdiff
path: root/IRCBot.py
diff options
context:
space:
mode:
Diffstat (limited to 'IRCBot.py')
-rw-r--r--IRCBot.py101
1 files changed, 101 insertions, 0 deletions
diff --git a/IRCBot.py b/IRCBot.py
new file mode 100644
index 00000000..578f7a69
--- /dev/null
+++ b/IRCBot.py
@@ -0,0 +1,101 @@
+import os, select, sys, threading, time, traceback
+import EventManager, IRCServer, ModuleManager, Timer
+
+class Bot(object):
+ def __init__(self):
+ self.lock = threading.Lock()
+ self.database = None
+ self.config = None
+ self.bot_directory = os.path.dirname(os.path.realpath(__file__))
+ self.servers = {}
+ self.running = True
+ self.poll = select.epoll()
+ self.modules = ModuleManager.ModuleManager(self)
+ self.events = EventManager.EventHook(self)
+ self.timers = []
+ self.last_ping = None
+
+ def add_server(self, id, hostname, port, password, ipv4, tls,
+ nickname, username, realname, connect=False):
+ new_server = IRCServer.Server(id, hostname, port, password,
+ ipv4, tls, nickname, username, realname, self)
+ self.servers[new_server.fileno()] = new_server
+ if connect:
+ self.connect(new_server)
+ def connect(self, server):
+ try:
+ server.connect()
+ except:
+ sys.stderr.write("Failed to connect to %s\n" % str(server))
+ traceback.print_exc()
+ return False
+ return True
+ def connect_all(self):
+ for server in self.servers.values():
+ if self.connect(server):
+ self.poll.register(server.fileno(), select.EPOLLOUT)
+
+ def add_timer(self, function, delay, *args, **kwargs):
+ timer = Timer.Timer(function, delay, *args, **kwargs)
+ timer.set_started_time()
+ self.timers.append(timer)
+ def next_timer(self):
+ next = None
+ for timer in self.timers:
+ time_left = timer.time_left()
+ if not next or time_left < next:
+ next = time_left
+ return next or 30
+ def call_timers(self):
+ for timer in self.timers[:]:
+ if timer.due():
+ timer.call()
+ if timer.done():
+ self.timers.remove(timer)
+
+ def register_read(self, server):
+ self.poll.modify(server.fileno(), select.EPOLLIN)
+ def register_write(self, server):
+ self.poll.modify(server.fileno(), select.EPOLLOUT)
+ def register_both(self, server):
+ self.poll.modify(server.fileno(),
+ select.EPOLLIN|select.EPOLLOUT)
+
+ def since_last_read(self, server):
+ return time.time()-server.last_read
+
+ def run(self):
+ while self.running:
+ self.lock.acquire()
+ events = self.poll.poll(self.next_timer())
+ self.call_timers()
+ for fd, event in events:
+ if fd in self.servers:
+ server = self.servers[fd]
+ if event & select.EPOLLIN:
+ lines = server.read()
+ for line in lines:
+ print(line)
+ server.parse_line(line)
+ elif event & select.EPOLLOUT:
+ server._send()
+ self.register_read(server)
+ elif event & select.EPULLHUP:
+ print("hangup")
+ if not self.last_ping or time.time()-self.last_ping >= 60:
+ for server in self.servers.values():
+ server.send_ping()
+ self.last_ping = time.time()
+ for server in list(self.servers.values()):
+ if server.last_read and self.since_last_read(server
+ ) > 160:
+ print("pingout from %s" % str(server))
+ server.disconnect()
+ if not server.connected:
+ self.poll.unregister(server.fileno())
+ del self.servers[server.fileno()]
+ # add reconnect here
+ print("disconnected from %s" % str(server))
+ elif server.waiting_send():
+ self.register_both(server)
+ self.lock.release()