bitbot-3.11-fork/IRCBot.py

151 lines
5.9 KiB
Python
Raw Normal View History

2016-03-29 11:56:58 +00:00
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.events.on("timer").on("reconnect").hook(self.reconnect)
self.events.on("boot").on("done").hook(self.setup_timers)
2016-03-29 11:56:58 +00:00
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.events.on("new").on("server").call(server=new_server)
2016-03-29 11:56:58 +00:00
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
2016-03-30 18:32:14 +00:00
self.poll.register(server.fileno(), select.EPOLLOUT)
2016-03-29 11:56:58 +00:00
return True
def connect_all(self):
for server in self.servers.values():
2016-03-30 18:32:14 +00:00
self.connect(server)
2016-03-29 11:56:58 +00:00
def setup_timers(self, event):
for setting, value in self.find_settings("timer-%"):
id = setting.split("timer-", 1)[1]
self.add_timer(value["event-name"], value["delay"], value[
"next-due"], id, **value["kwargs"])
def timer_setting(self, timer):
self.set_setting("timer-%s" % timer.id, {
"event-name": timer.event_name, "delay": timer.delay,
"next-due": timer.next_due, "kwargs": timer.kwargs})
def timer_setting_remove(self, timer):
self.timers.remove(timer)
self.del_setting("timer-%s" % timer.id)
def add_timer(self, event_name, delay, next_due=None, id=None, **kwargs):
timer = Timer.Timer(self, event_name, delay, next_due, **kwargs)
if id:
timer.id = id
else:
self.timer_setting(timer)
2016-03-29 11:56:58 +00:00
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.timer_setting_remove(timer)
else:
self.timer_setting(timer)
2016-03-29 11:56:58 +00:00
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 None if not server.last_read else time.time(
)-server.last_read
2016-03-29 11:56:58 +00:00
2016-03-30 18:32:14 +00:00
def disconnect(self, server):
self.poll.unregister(server.fileno())
del self.servers[server.fileno()]
def reconnect(self, event):
server = event["server"]
IRCServer.Server.__init__(server, server.id, server.target_hostname,
server.port, server.password, server.ipv4, server.tls,
server.original_nickname, server.original_username,
server.original_realname, self)
2016-03-30 18:32:14 +00:00
if self.connect(server):
self.servers[server.fileno()] = server
else:
event["timer"].redo()
def set_setting(self, setting, value):
self.database.set_bot_setting(setting, value)
def get_setting(self, setting, default=None):
return self.database.get_bot_setting(setting, default)
def find_settings(self, pattern, default=[]):
return self.database.find_bot_settings(pattern, default)
def del_setting(self, setting):
self.database.del_bot_setting(setting)
2016-03-29 11:56:58 +00:00
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")
server.disconnect()
2016-03-29 11:56:58 +00:00
for server in list(self.servers.values()):
since_last_read = self.since_last_read(server)
if since_last_read:
if since_last_read > 120:
2016-03-29 11:56:58 +00:00
print("pingout from %s" % str(server))
server.disconnect()
elif since_last_read > 30 and not server.ping_sent:
server.send_ping()
server.ping_sent = True
2016-03-29 11:56:58 +00:00
if not server.connected:
2016-03-30 18:32:14 +00:00
self.disconnect(server)
reconnect_delay = self.config.get("reconnect-delay", 10)
self.add_timer("reconnect", reconnect_delay, server=server)
2016-03-30 18:32:14 +00:00
print("disconnected from %s, reconnecting in %d seconds" % (
str(server), reconnect_delay))
2016-03-29 11:56:58 +00:00
elif server.waiting_send():
self.register_both(server)
self.lock.release()