1
0
Fork 0

done moar stuff

This commit is contained in:
fanir 2014-03-01 01:25:12 +01:00
parent 9ca0509bb0
commit 69e20b40f5

221
main.py
View file

@ -26,13 +26,16 @@
# SETTINGS CAN BE FOUND AT THE BOTTOM OF THE FILE
import sys, time, string, socket, re, signal
import sys, time, string, socket, re, signal, struct
from select import poll, POLLIN, POLLPRI, POLLOUT,\
POLLERR, POLLHUP, POLLNVAL
from threading import Thread#, Event
from threading import Thread, Event
from APIcollection import Twitter
bot = None
class log():
DEBUG, INFO, WARNING, ERROR, FATAL, SILENT =\
0, 1, 2, 3, 4, 5
@ -44,6 +47,7 @@ class log():
raise ValueError("That's not a loglevel!")
class pircbot():
def encode(self, textstring):
for codec in self.encodings:
@ -59,68 +63,53 @@ class pircbot():
def __init__(self, nicknames, server, port=6667, ident="pircbot",
realname="pircbot", encodings=("utf-8", "latin-1"),
command_prefix=".", admins=""):
self.nicknames = nicknames
command_prefix=".", admins="", serverpasswd="", parser_wait_time=0.1):
self.server = server
self.port = port
self.serverpasswd = serverpasswd
self.encodings = encodings
self.nicknames = nicknames
self.ident = ident
self.realname = realname
self.encodings = encodings
self.admins = admins
self.cmdprefix = command_prefix
self.parser_wait_time=parser_wait_time
self.user = {}
self.socket = None
self.recvloop = None
self.recvbuffer = bytearray(1024)
self.run = False
self.ready = False
self.is_alive = False
self.need_nick = True
self.die_event = Event()
def recv(self):
def recv_loop(self):
"""
Loop for reciving data
"""
parser = Thread(target=self.parse, name="parser")
parser = Thread(target=self.parse_loop, name="parser")
p = poll()
p.register(self.socket.fileno(), POLLIN)
while self.run:
while not self.die_event.is_set():
ap = p.poll(1000)
if (self.socket.fileno(), POLLIN) in ap:
self.recvbuffer.extend(self.socket.recv(1024))
if not parser.is_alive():
parser = Thread(target=self.parse, name="parser")
parser = Thread(target=self.parse_loop, name="parser")
parser.start()
if parser.is_alive(): parser.join()
print("--- RECVLOOP EXITING ---")
def connect(self):
# connect
self.socket = socket.socket()
try:
self.socket.connect((self.server, self.port))
except socket.error as e:
log.show(log.FATAL, "Fehler: %s" % e)
return
self.run = True
# start getting data
self.recvloop = Thread(target=self.recv, name="recvloop")
self.recvloop.start()
# get a nick
self.socket.send(self.encode("NICK %s\r\n" % self.nicknames.pop(0)))
self.socket.send(self.encode("USER %s %s bla :%s\r\n" % (self.ident, self.server, self.realname)))
self.is_alive = True
def parse(self):
def parse_loop(self):
"""
Loop for parsing incoming data
"""
#line = ""
origin = {}
while self.run and self.recvbuffer != b"":
while not self.die_event.is_set():# and self.recvbuffer.endswith(b"\r\n"):# != b"":
if self.recvbuffer.endswith(b"\r\n"):
# get and decode line from buffer
rawline, _, self.recvbuffer = self.recvbuffer.partition(b"\r\n")
rawline = self.decode(rawline)
@ -129,9 +118,9 @@ class pircbot():
head = line[0].lstrip("\x00").split(" ")
larg = line[1] if len(line)>1 else ""
# parse prefix
origin = {}
if head[0].startswith(":"):
prefix = head.pop(0)[1:]
origin.clear()
if "@" in prefix:
origin["nick"], origin["ident"], origin["host"] = re.match(r"(\S+)!(\S+)@(\S+)", prefix).groups()
else:
@ -144,24 +133,60 @@ class pircbot():
params = head
params.append(larg)
log.show(log.DEBUG, ">> %s" % rawline)
log.show(log.DEBUG, " > %s" % rawline)
# PING
if command == "PING":
self.socket.send(self.encode("PONG %s\r\n" % params[0]))
self.send("PONG %s" % params[0])
# PRIVMSG
elif command == "PRIVMSG":
if params[1].startswith(self.cmdprefix):
args = params[1].lstrip(self.cmdprefix).split(" ")
sndline = self.on_command(prefix, origin, params[0], args[0], args[1:])
if sndline != None:
log.show(log.DEBUG, "<< %s" % sndline)
self.socket.send(self.encode(sndline))
self.send(sndline)
# 001 (RPL_WELCOME)
elif command == "001":
self.user["mask"] = re.search(r" (\S+!\S+@\S+)$", rawline.split(" :", 1)[1]).groups()[0]
self.user["nick"], self.user["ident"], self.user["host"] = re.match(r"(\S+)!(\S+)@(\S+)", self.user["mask"]).groups()
self.ready = True
# 433 (ERR_NICKNAMEINUSE)
elif command == "433":
self.socket.send(self.encode("NICK %s\r\n" % self.nicknames.pop(0)))
self.send("NICK %s" % self.nicknames.pop(0))
# KILL
elif command == "KILL":
print("Got killed: %s", rawline)
self.die()
log.show(log.WARNING, "Got killed by %s: %s" % (params[0], params[1:]))
self.quit(send=False)
else:
time.sleep(self.parser_wait_time)
print("--- PARSELOOP EXITING ---")
def send(self, data):
log.show(log.DEBUG, "< %s" % data)
try: self.socket.send(self.encode("".join((data, "\r\n"))))
except BrokenPipeError as e:
log.show(log.FATAL, e)
self.quit(send=False)
def connect(self):
# connect
self.socket = socket.socket()
try:
self.socket.connect((self.server, self.port))
except socket.error as e:
log.show(log.FATAL, "Fehler: %s" % e)
return
# start getting data
self.recvloop = Thread(target=self.recv_loop, name="recvloop")
self.recvloop.start()
# optionally send a server password
if self.serverpasswd != "": self.send("PASS %s" % self.serverpasswd)
# get a nick
self.send("NICK %s" % self.nicknames.pop(0))
# set user data
self.send("USER %s 0 * :%s" % (self.ident, self.realname))
def is_admin(self, user):
for admin in self.admins:
@ -169,24 +194,29 @@ class pircbot():
return True
return False
def die(self):
self.run = False
self.recvloop.join()
self.is_alive = False
sys.exit()
def quit(self, reason=""):
self.socket.send(self.encode("QUIT :%s\n" % reason))
self.run = False
self.recvloop.join()
self.is_alive = False
def quit(self, reason="", send=True):
if send:
try:
self.send("QUIT :%s" % reason)
except: pass
self.die_event.set()
print("--- SOCKET CLOSING ---")
try:
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
except: pass
def join(self, channel):
print(channel)
self.socket.send(self.encode("JOIN %s\n" % channel))
while not self.ready: time.sleep(1)
self.send("JOIN %s" % channel)
def part(self, channel):
self.socket.send(self.encode("PART %s\n" % channel))
while not self.ready: time.sleep(1)
self.send("PART %s" % channel)
def set_mode(self, modes):
while not self.ready: time.sleep(1)
self.send("MODE %s :%s" % (self.user["nick"], modes))
def on_command(self, prefix, origin, source, command, params):
"""
@ -199,19 +229,26 @@ class pircbot():
Command is the command for the bot.
Params contains a list of originally space separated parameters.
"""
print(params)
if command.startswith("hello"):
# hello
if command == "hello":
greeting = "".join(("Hi " + origin["nick"] +"!"))
if source[0] in {"#", "+", "!", "&"}:
return "PRIVMSG %s :%s\r\n" % (source, greeting)
return "PRIVMSG %s :%s" % (source, greeting)
else:
return "PRIVMSG %s :%s\r\n" % (origin["nick"], greeting)
elif command.startswith("join") and len(params)>0:
return "PRIVMSG %s :%s" % (origin["nick"], greeting)
# join <channel>
elif command == "join" and len(params)>0:
if self.is_admin(origin["nick"]): self.join(params[0])
else: return "PRIVMSG %s :You can't do that!\r\n" % origin["nick"]
elif command.startswith("part") and len(params)>0:
else: return "PRIVMSG %s :You can't do that!" % origin["nick"]
# part <channel>
elif command == "part" and len(params)>0:
if self.is_admin(origin["nick"]): self.part(params[0])
else: return "PRIVMSG %s :You can't do that!\r\n" % origin["nick"]
else: return "PRIVMSG %s :You can't do that!" % origin["nick"]
# die [<quitmsg>]
elif command == "die":
if self.is_admin(origin["nick"]):
self.quit("".join(params) if len(params)>0 else "".join((origin["nick"], " shot me, dying now... Bye...")))
def parseargs():
@ -222,31 +259,34 @@ def parseargs():
#p.add_argument("--daemon", "-d", type = bool, choices = [1, 0], default=1, help="Daemonize, Default: 1")
return p.parse_args()
def KeyboardInterruptHandler(signum, frame):
global bot
print("Got Ctrl-C, dying now...")
bot.quit("")
sys.exit()
def main():
global bot
signal.signal(signal.SIGINT, KeyboardInterruptHandler)
args = parseargs()
if args.action == "start":
bot = pircbot(nicknames=NICKNAMES, ident=IDENT, realname=REALNAME,
server=SERVER, port=PORT, encodings=ENCODINGS, command_prefix=COMMAND_PREFIX, admins=ADMINS)
server=SERVER, port=PORT, encodings=ENCODINGS, command_prefix=COMMAND_PREFIX,
admins=ADMINS, serverpasswd=SERVERPASSWD, parser_wait_time=PARSER_WAIT_TIME)
try:
bot.connect()
while bot.ready == False: time.sleep(1)
for channel in CHANNELS:
bot.join(channel)
while 1:
if bot.is_alive == False: print("X")
time.sleep(10)
except SystemExit:
print("exiting...")
# wait for the bot to become ready
while bot.ready and not bot.die_event.is_set() == False:
time.sleep(1)
if not bot.die_event.is_set():
# set modes and join channels
bot.set_mode(MODES)
for channel in CHANNELS:
bot.join(channel)
# while bot is active, do nothing
while not bot.die_event.is_set():
time.sleep(1)
except KeyboardInterrupt:
log.show(log.INFO, "Got Ctrl-C, dying now...")
bot.quit()
elif args.action == "stop": print("nope!")
print("--- MAIN EXITING ---")
return 0
@ -287,6 +327,8 @@ if __name__ == '__main__':
# supported. Maybe in a future, far far away...
PORT = 6667
SERVERPASSWD = ""
# A comma-seperated list of channels to join, enclosed by braces.
CHANNELS = ["#bots", "#main"]
@ -303,6 +345,13 @@ if __name__ == '__main__':
COMMAND_PREFIX = "."
# The time the parser for incoming data should wait between each attempt to read new data in seconds.
# High values will certainly make the bot reply slowly while very low values increads cpu load and therefore will perform badly on slow machines.
# You should keep it between 1 and 0.001 seconds.
# For gods sake, don't set it to 0!
PARSER_WAIT_TIME = 0.05
#######################
### END OF SETTINGS ###
#######################