Module_state done: global datas management

newnemubot replaces old one
This commit is contained in:
Némunaire 2012-05-30 11:58:27 +02:00
parent 684cecd137
commit 25b2634ea3
12 changed files with 453 additions and 414 deletions

View File

@ -1,152 +0,0 @@
# coding=utf-8
import re
import sys
from datetime import datetime
from datetime import date
from xml.dom.minidom import parse
from xml.dom.minidom import parseString
from xml.dom.minidom import getDOMImplementation
filename = ""
BIRTHDAYS = {}
def xmlparse(node):
"""Parse the given node and add birthdays to the global list."""
for item in node.getElementsByTagName("birthday"):
if (item.hasAttribute("year")):
year = int(item.getAttribute("year"))
else:
year = 0
if (item.hasAttribute("month")):
month = int(item.getAttribute("month"))
else:
month = 0
if (item.hasAttribute("day")):
day = int(item.getAttribute("day"))
else:
day = 0
if (item.hasAttribute("hour")):
hour = int(item.getAttribute("hour"))
else:
hour = 0
if (item.hasAttribute("minute")):
minute = int(item.getAttribute("minute"))
else:
minute = 0
second = 1
BIRTHDAYS[item.getAttribute("name")] = datetime(year, month, day, hour, minute, second)
def load_module(datas_path):
"""Load this module"""
global BIRTHDAYS, filename
BIRTHDAYS = {}
filename = datas_path + "/birthdays.xml"
sys.stdout.write ("Loading birthdays ... ")
dom = parse(filename)
xmlparse (dom.getElementsByTagName('birthdays')[0])
print ("done (%d loaded)" % len(BIRTHDAYS))
def save_module():
"""Save the dates"""
global filename
sys.stdout.write ("Saving birthdays ... ")
impl = getDOMImplementation()
newdoc = impl.createDocument(None, 'birthdays', None)
top = newdoc.documentElement
for name in BIRTHDAYS.keys():
day = BIRTHDAYS[name]
bonus=""
if day.hour != 0:
bonus += 'hour="%s" ' % day.hour
if day.minute != 0:
bonus += 'minute="%s" ' % day.minute
item = parseString ('<birthday name="%s" year="%d" month="%d" day="%d" %s />' % (name, day.year, day.month, day.day, bonus)).documentElement
top.appendChild(item);
with open(filename, "w") as f:
newdoc.writexml (f)
print ("done")
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "People birthdays and ages"
def help_full ():
return "!anniv /who/: gives the remaining time before the anniversary of /who/\n!age /who/: gives the age of /who/\nIf /who/ is not given, gives the remaining time before your anniversary.\n\n To set yout birthday, say it to nemubot :)"
def findName(msg):
if len(msg.cmd) < 2 or msg.cmd[1].lower() == "moi" or msg.cmd[1].lower() == "me":
name = msg.sender.lower()
else:
name = msg.cmd[1].lower()
matches = []
if name in BIRTHDAYS:
matches.append(name)
else:
for k in BIRTHDAYS.keys ():
if k.find (name) == 0:
matches.append (k)
return (matches, name)
def parseanswer(msg):
if msg.cmd[0] == "anniv":
(matches, name) = findName(msg)
if len(matches) == 1:
(n, d) = (matches[0], BIRTHDAYS[matches[0]])
tyd = d
tyd = datetime(date.today().year, tyd.month, tyd.day)
if tyd.day == datetime.today().day and tyd.month == datetime.today().month:
msg.send_chn (msg.countdown_format (d, "", "C'est aujourd'hui l'anniversaire de %s ! Il a%s. Joyeux anniversaire :)" % (n, "%s")))
else:
if tyd < datetime.today():
tyd = datetime(date.today().year + 1, tyd.month, tyd.day)
msg.send_chn (msg.countdown_format (tyd, "Il reste %s avant l'anniversaire de %s !" % ("%s", n), ""))
else:
msg.send_chn ("%s: désolé, je ne connais pas la date d'anniversaire de %s. Quand est-il né ?"%(msg.sender, name))
return True
elif msg.cmd[0] == "age":
(matches, name) = findName(msg)
if len(matches) == 1:
(n, d) = (matches[0], BIRTHDAYS[matches[0]])
msg.send_chn (msg.countdown_format (d, "", "%s a %s." % (n, "%s")))
else:
msg.send_chn ("%s: désolé, je ne connais pas l'âge de %s. Quand est-il né ?"%(msg.sender, name))
return True
else:
return False
def parseask(msg):
msgl = msg.content.lower ()
if re.match("^.*(date de naissance|birthday|geburtstag|née? |nee? le|born on).*$", msgl) is not None:
try:
extDate = msg.extractDate ()
if extDate is None:
msg.send_chn ("%s: ta date de naissance ne paraît pas valide..." % (msg.sender))
else:
BIRTHDAYS[msg.sender.lower()] = extDate
msg.send_chn ("%s: ok, c'est noté, ta date de naissance est le %s" % (msg.sender, extDate.strftime("%A %d %B %Y à %H:%M")))
save_module ()
except:
msg.send_chn ("%s: ta date de naissance ne paraît pas valide..." % (msg.sender))
return True
return False
def parselisten (msg):
return False

0
datas/datas Normal file
View File

View File

@ -1,97 +0,0 @@
# coding=utf-8
class ModuleException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class ModuleState:
def __init__(self, name):
self.name = name
self.attributes = dict()
self.childs = list()
def getName(self):
return self.name
def getAttribute(self, name):
if name in self.attributes:
return self.attributes[name]
else:
return None
def setAttribute(self, name, value):
self.attributes[name] = value
def getChilds(self):
return self.childs
def addChild(self, child):
self.childs.append(child)
class ModuleStateFile:
def __init__(self, filename):
self.filename = filename
if not os.access(self.filename, os.R_OK):
with open(self.filename) as f:
for line in f:
print line
class ModuleBase:
def __init__(self, datas_path):
self.datas_path = datas_path
if self.module_name is None:
raise ModuleException("module_name not defined")
if self.conf is not None:
self.conf = self.datas_path + self.conf
if not os.access(self.conf, os.R_OK):
def print(self, message):
print ("[%s] %s" % (self.module_name, message))
def load(self):
return True
def reload(self):
return self.save() and self.load()
def save(self):
return True
def launch(self, servers):
return True
def stop(self):
return True
def help_tiny(self):
return None
def help_full(self):
return None
def parseanswer(self, msg):
return False
def parseask(self, msg):
return False
def parselisten(self, msg):
return False
def parseadmin(self, msg):
return False

View File

@ -223,9 +223,14 @@ class Message:
#Try modules #Try modules
else: else:
for im in mods.keys(): for im in mods:
if mods[im].parseask(self): #try:
return if im.parseask(self):
return
#except AttributeError:
#print ("Warning: in module `%s', no function parseask defined." % im.name)
#im.parseask = lambda x: False
#continue
#Owner commands #Owner commands
elif self.content[0] == '`' and self.sender == self.srv.owner: elif self.content[0] == '`' and self.sender == self.srv.owner:

103
module_state.py Normal file
View File

@ -0,0 +1,103 @@
# coding=utf-8
import xml.sax
from datetime import datetime
from datetime import date
import time
class ModuleState:
def __init__(self, name):
self.name = name
self.attributes = dict()
self.childs = list()
self.index = dict()
self.index_fieldname = None
self.index_tagname = None
def getName(self):
return self.name
def __getitem__(self, i):
return self.getAttribute(i)
def __contains__(self, i):
return i in self.index
def getAttribute(self, name):
if name in self.attributes:
return self.attributes[name]
else:
return None
def getDate(self, name):
if name in self.attributes.keys():
if isinstance(self.attributes[name], datetime):
return self.attributes[name]
else:
return date.fromtimestamp(float(self.attributes[name]))
else:
return None
def getInt(self, name):
if name in self.attributes.keys():
return int(self.attributes[name])
else:
return None
def setIndex(self, fieldname = "name", tagname = None):
self.index_fieldname = fieldname
self.index_tagname = tagname
for child in self.childs:
if (tagname is None or tagname == child.name) and child.hasAttribute(fieldname):
self.index[child[fieldname]] = child
def hasAttribute(self, name):
return (name in self.attributes)
def setAttribute(self, name, value):
self.attributes[name] = value
def getChilds(self):
return self.childs
def getNode(self, tagname):
ret = None
for child in self.childs:
if tagname is None or tagname == child.name:
ret = child
return ret
def getNodes(self, tagname):
ret = list()
for child in self.childs:
if tagname is None or tagname == child.name:
ret.append(child)
return ret
def addChild(self, child):
self.childs.append(child)
if self.index_fieldname is not None:
self.setIndex(self.index_fieldname, self.index_tagname)
def save_node(self, gen):
attribs = {}
for att in self.attributes.keys():
if isinstance(self.attributes[att], datetime):
attribs[att] = str(time.mktime(self.attributes[att].timetuple()))
else:
attribs[att] = str(self.attributes[att])
attrs = xml.sax.xmlreader.AttributesImpl(attribs)
gen.startElement(self.name, attrs)
for child in self.childs:
child.save_node(gen)
gen.endElement(self.name)
def save(self, filename):
with open(filename,"w") as f:
gen = xml.sax.saxutils.XMLGenerator(f, "utf-8")
gen.startDocument()
self.save_node(gen)
gen.endDocument()

39
module_states_file.py Normal file
View File

@ -0,0 +1,39 @@
#!/usr/bin/python3
# coding=utf-8
import os
import xml.sax
from module_exception import ModuleException
from module_state import ModuleState
class ModuleStatesFile(xml.sax.ContentHandler):
def startDocument(self):
self.root = None
self.stack = list()
def startElement(self, name, attrs):
cur = ModuleState(name)
for name in attrs.keys():
cur.setAttribute(name, attrs.getValue(name))
self.stack.append(cur)
def endElement(self, name):
child = self.stack.pop()
size = len(self.stack)
if size > 0:
self.stack[size - 1].addChild(child)
else:
self.root = child
def parse_file(filename):
parser = xml.sax.make_parser()
mod = ModuleStatesFile()
parser.setContentHandler(mod)
try:
parser.parse(open(filename, "r"))
return mod.root
except:
return ModuleState("nemubotstate")

97
modules/birthday.py Normal file
View File

@ -0,0 +1,97 @@
# coding=utf-8
import re
import sys
from datetime import datetime
from datetime import date
from module_state import ModuleState
nemubotversion = 3.0
def load():
global DATAS
DATAS.setIndex("name", "birthday")
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "People birthdays and ages"
def help_full ():
return "!anniv /who/: gives the remaining time before the anniversary of /who/\n!age /who/: gives the age of /who/\nIf /who/ is not given, gives the remaining time before your anniversary.\n\n To set yout birthday, say it to nemubot :)"
def findName(msg):
if len(msg.cmd) < 2 or msg.cmd[1].lower() == "moi" or msg.cmd[1].lower() == "me":
name = msg.sender.lower()
else:
name = msg.cmd[1].lower()
matches = []
if name in DATAS.index:
matches.append(name)
else:
for k in DATAS.index.keys ():
if k.find (name) == 0:
matches.append (k)
return (matches, name)
def parseanswer(msg):
if msg.cmd[0] == "anniv":
(matches, name) = findName(msg)
if len(matches) == 1:
name = matches[0]
tyd = DATAS.index[name].getDate("born")
tyd = datetime(date.today().year, tyd.month, tyd.day)
if tyd.day == datetime.today().day and tyd.month == datetime.today().month:
msg.send_chn (msg.countdown_format (DATAS.index[name].getDate("born"), "", "C'est aujourd'hui l'anniversaire de %s ! Il a%s. Joyeux anniversaire :)" % (name, "%s")))
else:
if tyd < datetime.today():
tyd = datetime(date.today().year + 1, tyd.month, tyd.day)
msg.send_chn (msg.countdown_format (tyd, "Il reste %s avant l'anniversaire de %s !" % ("%s", name), ""))
else:
msg.send_chn ("%s: désolé, je ne connais pas la date d'anniversaire de %s. Quand est-il né ?"%(msg.sender, name))
return True
elif msg.cmd[0] == "age":
(matches, name) = findName(msg)
if len(matches) == 1:
name = matches[0]
d = DATAS.index[name].getDate("born")
msg.send_chn (msg.countdown_format (d, "", "%s a %s." % (n, "%s")))
else:
msg.send_chn ("%s: désolé, je ne connais pas l'âge de %s. Quand est-il né ?"%(msg.sender, name))
return True
else:
return False
def parseask(msg):
msgl = msg.content.lower ()
if re.match("^.*(date de naissance|birthday|geburtstag|née? |nee? le|born on).*$", msgl) is not None:
try:
extDate = msg.extractDate ()
if extDate is None:
msg.send_chn ("%s: ta date de naissance ne paraît pas valide..." % (msg.sender))
else:
if msg.sender.lower() in DATAS.index:
DATAS.index[msg.sender.lower()] = extDate
else:
ms = ModuleState("birthday")
ms.setAttribute("name", msg.sender.lower())
ms.setAttribute("born", extDate)
DATAS.addChild(ms)
msg.send_chn ("%s: ok, c'est noté, ta date de naissance est le %s" % (msg.sender, extDate.strftime("%A %d %B %Y à %H:%M")))
save()
except:
msg.send_chn ("%s: ta date de naissance ne paraît pas valide..." % (msg.sender))
return True
return False
def parselisten (msg):
return False

2
modules/birthday.xml Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" ?>
<nemubotmodule name="birthday" />

View File

@ -8,18 +8,60 @@ import threading
from datetime import timedelta from datetime import timedelta
from datetime import datetime from datetime import datetime
from datetime import date from datetime import date
from xml.dom.minidom import parse
from xml.dom.minidom import parseString
from xml.dom.minidom import getDOMImplementation
filename = "" from module_state import ModuleState
nemubotversion = 3.0
channels = "#nemutest #42sh #ykar #epitagueule" channels = "#nemutest #42sh #ykar #epitagueule"
MANCHE = None
QUESTIONS = list()
SCORES = dict ()
LASTSEEN = dict () LASTSEEN = dict ()
temps = dict () temps = dict ()
class Wrapper:
def __init__(self):
self.cache = dict()
def items(self):
global DATAS
ret = list()
for k in DATAS.index.keys():
ret.append((k, self[k]))
return ret
def __contains__(self, i):
global DATAS
return i in DATAS.index
def __getitem__(self, i):
global DATAS
if i in self.cache:
return self.cache[i]
else:
sc = Score()
sc.parse(DATAS.index[i])
self.cache[i] = sc
return sc
def __setitem__(self, i, j):
global DATAS
ms = ModuleState("player")
ms.setAttribute("name", i)
j.save(ms)
DATAS.addChild(ms)
DATAS.setIndex("name", "player")
def __delitem__(self, i):
global DATAS
del DATAS.index[i]
def save(self, i):
if i in self.cache:
self.cache[i].save(DATAS.index[i])
del self.cache[i]
SCORES = Wrapper()
class Score: class Score:
def __init__(self): def __init__(self):
#FourtyTwo #FourtyTwo
@ -37,15 +79,26 @@ class Score:
self.changed = False self.changed = False
def parse(self, item): def parse(self, item):
self.ftt = int(item.getAttribute("fourtytwo")) self.ftt = item.getInt("fourtytwo")
self.twt = int(item.getAttribute("twentythree")) self.twt = item.getInt("twentythree")
self.pi = int(item.getAttribute("pi")) self.pi = item.getInt("pi")
self.notfound = int(item.getAttribute("notfound")) self.notfound = item.getInt("notfound")
self.tententen = int(item.getAttribute("tententen")) self.tententen = item.getInt("tententen")
self.leet = int(item.getAttribute("leet")) self.leet = item.getInt("leet")
self.great = int(item.getAttribute("great")) self.great = item.getInt("great")
self.bad = int(item.getAttribute("bad")) self.bad = item.getInt("bad")
self.triche = int(item.getAttribute("triche")) self.triche = item.getInt("triche")
def save(self, state):
state.setAttribute("fourtytwo", self.ftt)
state.setAttribute("twentythree", self.twt)
state.setAttribute("pi", self.pi)
state.setAttribute("notfound", self.notfound)
state.setAttribute("tententen", self.tententen)
state.setAttribute("leet", self.leet)
state.setAttribute("great", self.great)
state.setAttribute("bad", self.bad)
state.setAttribute("triche", self.triche)
def merge(self, other): def merge(self, other):
self.ftt += other.ftt self.ftt += other.ftt
@ -100,6 +153,7 @@ class Score:
def playBad(self): def playBad(self):
if self.canPlay(): if self.canPlay():
self.bad += 1 self.bad += 1
self.great += 1
def playTriche(self): def playTriche(self):
self.triche += 1 self.triche += 1
def oupsTriche(self): def oupsTriche(self):
@ -130,58 +184,9 @@ class Score:
return "42: %d, 23: %d, leet: %d, pi: %d, 404: %d, 10: %d, great: %d, bad: %d, triche: %d = %d."%(self.ftt, self.twt, self.leet, self.pi, self.notfound, self.tententen, self.great, self.bad, self.triche, self.score()) return "42: %d, 23: %d, leet: %d, pi: %d, 404: %d, 10: %d, great: %d, bad: %d, triche: %d = %d."%(self.ftt, self.twt, self.leet, self.pi, self.notfound, self.tententen, self.great, self.bad, self.triche, self.score())
def xmlparse(node): def load():
"""Parse the given node and add scores to the global list.""" global DATAS
global SCORES, MANCHE DATAS.setIndex("name", "player")
for item in node.getElementsByTagName("score"):
SCORES[item.getAttribute("name")] = Score ()
SCORES[item.getAttribute("name")].parse(item)
for item in node.getElementsByTagName("question"):
QUESTIONS.append((item.getAttribute("question"),item.getAttribute("regexp"),item.getAttribute("great")))
manche = node.getElementsByTagName("manche")[0]
MANCHE = (int(manche.getAttribute("number")),
manche.getAttribute("winner"),
int(manche.getAttribute("winner_score")),
manche.getAttribute("who"),
# datetime.now ())
datetime.fromtimestamp (time.mktime (time.strptime (manche.getAttribute("date")[:19], "%Y-%m-%d %H:%M:%S"))))
def load_module(datas_path):
"""Load this module"""
global MANCHE, SCORES, filename
MANCHE = None
SCORES = dict ()
filename = datas_path + "/42.xml"
sys.stdout.write ("Loading 42scores ... ")
dom = parse(filename)
xmlparse (dom.documentElement)
print ("done (%d loaded, %d questions, currently in round %d)" % (len(SCORES), len(QUESTIONS), -42))
def save_module():
"""Save the scores"""
global filename
sys.stdout.write ("Saving 42scores ... ")
impl = getDOMImplementation()
newdoc = impl.createDocument(None, 'game', None)
top = newdoc.documentElement
for name in SCORES.keys():
scr = 'fourtytwo="%d" twentythree="%d" pi="%d" notfound="%d" tententen="%d" leet="%d" great="%d" bad="%d" triche="%d"'% SCORES[name].toTuple()
item = parseString ('<score name="%s" %s />' % (name, scr)).documentElement
top.appendChild(item);
top.appendChild(parseString ('<manche number="%d" winner="%s" winner_score="%d" who="%s" date="%s" />' % MANCHE).documentElement)
for q in QUESTIONS:
top.appendChild(parseString ('<question question="%s" regexp="%s" great="%s" />' % q).documentElement)
with open(filename, "w") as f:
newdoc.writexml (f)
print ("done")
def help_tiny (): def help_tiny ():
@ -198,7 +203,7 @@ def rev (tupl):
def parseanswer (msg): def parseanswer (msg):
if msg.cmd[0] == "42" or msg.cmd[0] == "score" or msg.cmd[0] == "scores": if msg.cmd[0] == "42" or msg.cmd[0] == "score" or msg.cmd[0] == "scores":
global SCORES, MANCHE global SCORES
if len(msg.cmd) > 2 and msg.is_owner and ((msg.cmd[1] == "merge" and len(msg.cmd) > 3) or msg.cmd[1] == "oupstriche"): if len(msg.cmd) > 2 and msg.is_owner and ((msg.cmd[1] == "merge" and len(msg.cmd) > 3) or msg.cmd[1] == "oupstriche"):
if msg.cmd[2] in SCORES and (len(msg.cmd) <= 3 or msg.cmd[3] in SCORES): if msg.cmd[2] in SCORES and (len(msg.cmd) <= 3 or msg.cmd[3] in SCORES):
if msg.cmd[1] == "merge": if msg.cmd[1] == "merge":
@ -215,7 +220,8 @@ def parseanswer (msg):
elif len(msg.cmd) > 1 and (msg.cmd[1] == "help" or msg.cmd[1] == "aide"): elif len(msg.cmd) > 1 and (msg.cmd[1] == "help" or msg.cmd[1] == "aide"):
msg.send_chn ("Formule : \"42\" * 2 + great * 5 + leet * 13.37 + (pi + 1) * 3.1415 * (not_found + 1) + tententen * 10 + \"23\" - (bad + 1) * 10 * (triche * 5 + 1) + 7") msg.send_chn ("Formule : \"42\" * 2 + great * 5 + leet * 13.37 + (pi + 1) * 3.1415 * (not_found + 1) + tententen * 10 + \"23\" - (bad + 1) * 10 * (triche * 5 + 1) + 7")
elif len(msg.cmd) > 1 and (msg.cmd[1] == "manche" or msg.cmd[1] == "round"): elif len(msg.cmd) > 1 and (msg.cmd[1] == "manche" or msg.cmd[1] == "round"):
msg.send_chn ("Nous sommes dans la %de manche, gagnée par %s avec %d points et commencée par %s le %s"%MANCHE) manche = DATAS.getNode("manche")
msg.send_chn ("Nous sommes dans la %de manche, gagnée par %s avec %d points et commencée par %s le %s." % (manche.getInt("number"), manche["winner"], manche.getInt("winner_score"), manche["who"], manche.getDate("date")))
#elif msg.channel == "#nemutest": #elif msg.channel == "#nemutest":
else: else:
phrase = "" phrase = ""
@ -241,15 +247,15 @@ def parseanswer (msg):
def win(msg): def win(msg):
global SCORES, MANCHE global SCORES
who = msg.sender who = msg.sender
(num_manche, winner, nb_points, whosef, dayte) = MANCHE manche = DATAS.getNode("manche")
maxi_scor = 0 maxi_scor = 0
maxi_name = None maxi_name = None
for player in SCORES.keys(): for player in DATAS.index.keys():
scr = SCORES[player].score() scr = SCORES[player].score()
if scr > maxi_scor: if scr > maxi_scor:
maxi_scor = scr maxi_scor = scr
@ -267,10 +273,14 @@ def win(msg):
else: else:
msg.send_chn ("Félicitations %s, tu remportes cette manche avec %d points !"%(maxi_name, maxi_scor)) msg.send_chn ("Félicitations %s, tu remportes cette manche avec %d points !"%(maxi_name, maxi_scor))
MANCHE = (num_manche + 1, maxi_name, maxi_scor, who, datetime.now ()) manche.setAttribute("number", manche.getInt("number") + 1)
manche.setAttribute("winner", maxi_name)
manche.setAttribute("winner_score", maxi_scor)
manche.setAttribute("who", who)
manche.setAttribute("date", datetime.now())
print ("Nouvelle manche :", MANCHE) print ("Nouvelle manche !")
save_module () save()
def parseask (msg): def parseask (msg):
@ -298,8 +308,8 @@ def parselisten (msg):
bfrseen = LASTSEEN[msg.realname] bfrseen = LASTSEEN[msg.realname]
LASTSEEN[msg.realname] = datetime.now() LASTSEEN[msg.realname] = datetime.now()
# if msg.channel == "#nemutest" and msg.sender not in DELAYED: if msg.channel == "#nemutest" and msg.sender not in DELAYED:
if msg.channel != "#nemutest" and msg.sender not in DELAYED: # if msg.channel != "#nemutest" and msg.sender not in DELAYED:
if re.match("^(42|quarante[- ]?deux).{,2}$", msg.content.strip().lower()): if re.match("^(42|quarante[- ]?deux).{,2}$", msg.content.strip().lower()):
if msg.time.minute == 10 and msg.time.second == 10 and msg.time.hour == 10: if msg.time.minute == 10 and msg.time.second == 10 and msg.time.hour == 10:
@ -389,9 +399,6 @@ class DelayedTuple:
else: else:
return False return False
#<question question=" ?" regexp="microprocesseur"/>
#<question question=" ?" regexp=""/>
def wait(self, timeout): def wait(self, timeout):
self.delayEvnt.wait(timeout) self.delayEvnt.wait(timeout)
@ -404,12 +411,17 @@ class GameUpdater(threading.Thread):
threading.Thread.__init__(self) threading.Thread.__init__(self)
def run(self): def run(self):
global DELAYED, QUESTIONS, LASTQUESTION global DELAYED, LASTQUESTION
seen = datetime.now() - self.bfrseen if self.bfrseen is not None:
seen = datetime.now() - self.bfrseen
rnd = random.randint(0, int(seen.seconds/90))
else:
rnd = 1
rnd = random.randint(0, seen.seconds/90)
if rnd != 0: if rnd != 0:
QUESTIONS = CONF.getNodes("question")
if self.msg.channel == "#nemutest": if self.msg.channel == "#nemutest":
quest = 9 quest = 9
else: else:
@ -419,7 +431,9 @@ class GameUpdater(threading.Thread):
quest = LASTQUESTION quest = LASTQUESTION
LASTQUESTION += 1 LASTQUESTION += 1
(question, regexp, great) = QUESTIONS[quest] question = QUESTIONS[quest]["question"]
regexp = QUESTIONS[quest]["regexp"]
great = QUESTIONS[quest]["great"]
self.msg.send_chn("%s: %s" % (self.msg.sender, question)) self.msg.send_chn("%s: %s" % (self.msg.sender, question))
DELAYED[self.msg.sender] = DelayedTuple(regexp, great) DELAYED[self.msg.sender] = DelayedTuple(regexp, great)
@ -436,4 +450,5 @@ class GameUpdater(threading.Thread):
else: else:
self.msg.send_chn("%s: J'accepte" % self.msg.sender) self.msg.send_chn("%s: J'accepte" % self.msg.sender)
del DELAYED[self.msg.sender] del DELAYED[self.msg.sender]
save_module () SCORES.save(self.msg.sender)
save()

View File

@ -2,72 +2,21 @@
# coding=utf-8 # coding=utf-8
import sys import sys
import signal
import os import os
import re
import imp import imp
from datetime import date import traceback
from datetime import datetime
from datetime import timedelta
from xml.dom.minidom import parse
if len(sys.argv) != 2 and len(sys.argv) != 3:
print ("This script takes exactly 1 arg: a XML config file")
sys.exit(1)
imports = ["birthday", "qd", "events", "youtube", "watchWebsite", "soutenance", "whereis", "alias"]
imports_launch = ["watchWebsite", "events"]
mods = {}
def onClose():
"""Call when the bot quit; saving all modules"""
for imp in mods.keys():
mods[imp].save_module ()
for imp in imports_launch:
mods[imp].stop ()
#Save banlist before quit
message.save_module ()
sys.exit (0)
def onSignal(signum, frame):
print ("\nSIGINT receive, saving states and close")
onClose()
signal.signal(signal.SIGINT, onSignal)
#Define working directory
if len(sys.argv) == 3:
basedir = sys.argv[2]
else:
basedir = "./"
#Load base modules
server = __import__ ("server")
message = __import__ ("message")
message.load (basedir + "/datas/")
#Read configuration XML file
dom = parse(sys.argv[1])
config = dom.getElementsByTagName('config')[0]
servers = dict ()
#Load modules
for imp in imports:
mod = __import__ (imp)
mods[imp] = mod
for serveur in config.getElementsByTagName('server'):
srv = server.Server(serveur, config.getAttribute('nick'), config.getAttribute('owner'), config.getAttribute('realname'))
srv.launch(mods, basedir + "/datas/")
servers[srv.id] = srv
servers = dict()
print ("Nemubot ready, my PID is %i!" % (os.getpid())) print ("Nemubot ready, my PID is %i!" % (os.getpid()))
prompt = __import__ ("prompt") prompt = __import__ ("prompt")
while prompt.launch(servers): while prompt.launch(servers):
imp.reload(prompt) try:
imp.reload(prompt)
except:
print ("Unable to reload the prompt due to errors. Fix them before trying to reload the prompt.")
exc_type, exc_value, exc_traceback = sys.exc_info()
sys.stdout.write (traceback.format_exception_only(exc_type, exc_value)[0])
onClose() print ("Bye")
sys.exit(0)

103
prompt.py
View File

@ -2,12 +2,17 @@ import sys
import shlex import shlex
import traceback import traceback
import imp import imp
from xml.dom.minidom import parse
server = __import__("server") server = __import__("server")
imp.reload(server) imp.reload(server)
xmlparser = __import__("module_states_file")
imp.reload(xmlparser)
selectedServer = None selectedServer = None
modules_path = "./modules/"
datas_path = "./datas/"
MODS = list() MODS = list()
def parsecmd(msg): def parsecmd(msg):
@ -39,13 +44,17 @@ def getPS1():
def launch(servers): def launch(servers):
"""Launch the prompt""" """Launch the prompt"""
for srv in servers:
servers[srv].update_mods(MODS)
ret = "" ret = ""
cmds = list() cmds = list()
while ret != "quit" and ret != "reset": while ret != "quit" and ret != "reset":
sys.stdout.write("\033[0;33m%s§\033[0m " % getPS1()) sys.stdout.write("\033[0;33m%s§\033[0m " % getPS1())
sys.stdout.flush() sys.stdout.flush()
for k in sys.stdin.readline().strip().split(";"):
try: try:
cmds = parsecmd(sys.stdin.readline().strip()) cmds = parsecmd(k)
except KeyboardInterrupt: except KeyboardInterrupt:
cmds = parsecmd("quit") cmds = parsecmd("quit")
except: except:
@ -66,23 +75,77 @@ def launch(servers):
# # # #
########################## ##########################
def load_module(config, servers):
global MODS
if config.hasAttribute("name"):
try:
#Import the module code
mod = imp.load_source(config["name"], modules_path + "/" + config["name"] + ".py")
try:
if mod.nemubotversion < 3.0:
print (" Module `%s' is not compatible with this version." % config["name"])
return
#Set module common functions and datas
mod.name = config["name"]
mod.print = lambda msg: print("[%s] %s"%(mod.name, msg))
mod.DATAS = xmlparser.parse_file(datas_path + "/" + config["name"] + ".xml")
mod.CONF = config
mod.save = lambda: mod.DATAS.save(datas_path + "/" + config["name"] + ".xml")
try:
mod.load()
print (" Module `%s' successfully loaded." % config["name"])
except AttributeError:
print (" Module `%s' successfully added." % config["name"])
MODS.append(mod)
except AttributeError:
print (" Module `%s' is not a nemubot module." % config["name"])
for srv in servers:
servers[srv].update_mods(MODS)
except IOError:
print (" Module `%s' not loaded: unable to find module implementation." % config["name"])
def load(cmds, servers): def load(cmds, servers):
"""Load an XML configuration file"""
if len(cmds) > 1: if len(cmds) > 1:
for f in cmds[1:]: for f in cmds[1:]:
dom = parse(f) config = xmlparser.parse_file(f)
config = dom.getElementsByTagName('config')[0] if config.getName() == "nemubotconfig" or config.getName() == "config":
for serveur in config.getElementsByTagName('server'): #Preset each server in this file
srv = server.Server(serveur, config.getAttribute('nick'), config.getAttribute('owner'), config.getAttribute('realname')) for serveur in config.getChilds():
if srv.id not in servers: srv = server.Server(serveur, config.getAttribute('nick'), config.getAttribute('owner'), config.getAttribute('realname'))
servers[srv.id] = srv if srv.id not in servers:
print (" Server `%s' successfully added." % srv.id) servers[srv.id] = srv
else: print (" Server `%s' successfully added." % srv.id)
print (" Server `%s' already added, skiped." % srv.id) else:
print (" Server `%s' already added, skiped." % srv.id)
elif config.getName() == "nemubotmodule":
load_module(config, servers)
else:
print (" Can't load `%s'; this is not a valid nemubot configuration file." % f)
else: else:
print ("Not enough arguments. `load' takes an filename.") print ("Not enough arguments. `load' takes an filename.")
return return
def unload(cmds, servers):
"""Unload a module"""
global MODS
if len(cmds) == 2 and cmds[1] == "all":
for mod in MODS:
try:
mod.unload()
except AttributeError:
continue
while len(MODS) > 0:
MODS.pop()
elif len(cmds) > 1:
print("Ok")
def close(cmds, servers): def close(cmds, servers):
"""Disconnect and forget (remove from the servers list) the server"""
global selectedServer global selectedServer
if len(cmds) > 1: if len(cmds) > 1:
for s in cmds[1:]: for s in cmds[1:]:
@ -98,6 +161,7 @@ def close(cmds, servers):
return return
def select(cmds, servers): def select(cmds, servers):
"""Select the current server"""
global selectedServer global selectedServer
if len(cmds) == 2 and cmds[1] != "None" and cmds[1] != "nemubot" and cmds[1] != "none": if len(cmds) == 2 and cmds[1] != "None" and cmds[1] != "nemubot" and cmds[1] != "none":
if cmds[1] in servers: if cmds[1] in servers:
@ -109,12 +173,16 @@ def select(cmds, servers):
return return
def liste(cmds, servers): def liste(cmds, servers):
"""Show some lists"""
if len(cmds) > 1: if len(cmds) > 1:
for l in cmds[1:]: for l in cmds[1:]:
l = l.lower() l = l.lower()
if l == "server" or l == "servers": if l == "server" or l == "servers":
for srv in servers.keys(): for srv in servers.keys():
print (" - %s ;" % srv) print (" - %s ;" % srv)
elif l == "mod" or l == "mods" or l == "module" or l == "modules":
for mod in MODS:
print (" - %s ;" % mod.name)
elif l == "chan" or l == "channel" or l == "channels": elif l == "chan" or l == "channel" or l == "channels":
if selectedServer is not None: if selectedServer is not None:
for chn in selectedServer.channels: for chn in selectedServer.channels:
@ -127,6 +195,7 @@ def liste(cmds, servers):
print (" Please give a list to show: servers, ...") print (" Please give a list to show: servers, ...")
def connect(cmds, servers): def connect(cmds, servers):
"""Make the connexion to a server"""
if len(cmds) > 1: if len(cmds) > 1:
for s in cmds[1:]: for s in cmds[1:]:
if s in servers: if s in servers:
@ -140,6 +209,7 @@ def connect(cmds, servers):
print (" Please SELECT a server or give its name in argument.") print (" Please SELECT a server or give its name in argument.")
def join(cmds, servers): def join(cmds, servers):
"""Join or leave a channel"""
rd = 1 rd = 1
if len(cmds) <= rd: if len(cmds) <= rd:
print ("%s: not enough arguments." % cmds[0]) print ("%s: not enough arguments." % cmds[0])
@ -164,6 +234,7 @@ def join(cmds, servers):
srv.leave(cmds[rd]) srv.leave(cmds[rd])
def send(cmds, servers): def send(cmds, servers):
"""Built-on that send a message on a channel"""
rd = 1 rd = 1
if len(cmds) <= rd: if len(cmds) <= rd:
print ("send: not enough arguments.") print ("send: not enough arguments.")
@ -202,6 +273,7 @@ def send(cmds, servers):
return "done" return "done"
def disconnect(cmds, servers): def disconnect(cmds, servers):
"""Close the connection to a server"""
if len(cmds) > 1: if len(cmds) > 1:
for s in cmds[1:]: for s in cmds[1:]:
if s in servers: if s in servers:
@ -216,6 +288,7 @@ def disconnect(cmds, servers):
print (" Please SELECT a server or give its name in argument.") print (" Please SELECT a server or give its name in argument.")
def zap(cmds, servers): def zap(cmds, servers):
"""Hard change connexion state"""
if len(cmds) > 1: if len(cmds) > 1:
for s in cmds[1:]: for s in cmds[1:]:
if s in servers: if s in servers:
@ -228,6 +301,7 @@ def zap(cmds, servers):
print (" Please SELECT a server or give its name in argument.") print (" Please SELECT a server or give its name in argument.")
def end(cmds, servers): def end(cmds, servers):
"""Quit the prompt for reload or exit"""
if cmds[0] == "reset": if cmds[0] == "reset":
return "reset" return "reset"
else: else:
@ -240,8 +314,9 @@ CAPS = {
'quit': end, #Disconnect all server and quit 'quit': end, #Disconnect all server and quit
'exit': end, #Alias for quit 'exit': end, #Alias for quit
'reset': end, #Reload the prompt 'reset': end, #Reload the prompt
'load': load, #Load a servers configuration file 'load': load, #Load a servers or module configuration file
'close': close, #Disconnect and remove a server from the list 'close': close, #Disconnect and remove a server from the list
'unload': unload, #Unload a module and remove it from the list
'select': select, #Select a server 'select': select, #Select a server
'list': liste, #Show lists 'list': liste, #Show lists
'connect': connect, #Connect to a server 'connect': connect, #Connect to a server

View File

@ -34,7 +34,7 @@ class Server(threading.Thread):
self.partner = "nbr23" self.partner = "nbr23"
self.channels = list() self.channels = list()
for channel in server.getElementsByTagName('channel'): for channel in server.getChilds():
self.channels.append(channel.getAttribute("name")) self.channels.append(channel.getAttribute("name"))
threading.Thread.__init__(self) threading.Thread.__init__(self)
@ -102,6 +102,9 @@ class Server(threading.Thread):
else: else:
return False return False
def update_mods(self, mods):
self.mods = mods
def launch(self, mods): def launch(self, mods):
if not self.connected: if not self.connected:
self.stop = False self.stop = False