Changes most of nemubot modules to packages

This commit is contained in:
Némunaire 2012-06-29 19:20:29 +02:00
parent 7b7bbd99e5
commit 316e6878ba
13 changed files with 420 additions and 1247 deletions

View File

@ -3,7 +3,6 @@
import re
import sys
from datetime import timedelta
from datetime import datetime
from datetime import date
import time
import threading
@ -12,6 +11,8 @@ from module_state import ModuleState
nemubotversion = 3.0
from . import Manager
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "events manager"
@ -19,63 +20,23 @@ def help_tiny ():
def help_full ():
return "This module store a lot of events: ny, we, vacs, " + (", ".join(DATAS.index.keys())) + "\n!eventslist: gets list of timer\n!start /something/: launch a timer"
class Manager(threading.Thread):
def __init__(self):
self.stop = False
threading.Thread.__init__(self)
def alertEnd(self, evt):
global newStrendEvt, SRVS, DATAS
#Send the message on each matched servers
for server in SRVS.keys():
if not evt.hasAttribute("server") or server == evt["server"]:
if evt["channel"] == SRVS[server].nick:
SRVS[server].send_msg_usr(evt["proprio"], "%s: %s arrivé à échéance." % (evt["proprio"], evt["name"]))
else:
SRVS[server].send_msg(evt["channel"], "%s: %s arrivé à échéance." % (evt["proprio"], evt["name"]))
DATAS.delChild(DATAS.index[evt["name"]])
save()
newStrendEvt.set()
def run(self):
global DATAS
while not self.stop:
newStrendEvt.clear()
closer = None
#Gets the closer event
for evt in DATAS.index.keys():
if DATAS.index[evt].hasAttribute("end") and (closer is None or DATAS.index[evt].getDate("end") < closer.getDate("end")) and DATAS.index[evt].getDate("end") > datetime.now():
closer = DATAS.index[evt]
if closer is not None and closer.hasAttribute("end"):
#print ("Closer: %s à %s"%(closer.name, closer["end"]))
timeleft = (closer.getDate("end") - datetime.now()).seconds
timer = threading.Timer(timeleft, self.alertEnd, (closer,))
timer.start()
#print ("Start timer (%ds)"%timeleft)
newStrendEvt.wait()
if closer is not None and closer.hasAttribute("end") and closer.getDate("end") > datetime.now():
timer.cancel()
self.threadManager = None
threadManager = None
newStrendEvt = threading.Event()
def load():
global DATAS, threadManager
global DATAS, SRVS, threadManager
#Define the index
DATAS.setIndex("name")
#Load the manager
threadManager = Manager()
Manager.save = save
threadManager = Manager(DATAS, SRVS)
threadManager.start()
def close():
global threadManager
if threadManager is not None:
threadManager.stop = True
newStrendEvt.set()
Manager.newStrendEvt.set()
def parseanswer(msg):
@ -122,7 +83,7 @@ def parseanswer(msg):
strnd["end"] = datetime.now() + timedelta(days=int(result.group(1)))
else:
strnd["end"] = datetime.now() + timedelta(seconds=int(result.group(1)))
newStrendEvt.set()
Manager.newStrendEvt.set()
msg.send_snd ("%s commencé le %s et se terminera le %s."% (msg.cmd[1], datetime.now(), strnd.getDate("end")))
except:
msg.send_snd ("Impossible de définir la fin de %s."% (msg.cmd[1]))
@ -139,7 +100,7 @@ def parseanswer(msg):
msg.send_chn ("%s a duré %s." % (msg.cmd[1], msg.just_countdown(datetime.now () - DATAS.index[msg.cmd[1]].getDate("start"))))
if DATAS.index[msg.cmd[1]]["proprio"] == msg.sender or (msg.cmd[0] == "forceend" and msg.sender == msg.srv.owner):
DATAS.delChild(DATAS.index[msg.cmd[1]])
newStrendEvt.set()
Manager.newStrendEvt.set()
save()
else:
msg.send_snd ("Vous ne pouvez pas terminer le compteur %s, créé par %s."% (msg.cmd[1], DATAS.index[msg.cmd[1]]["proprio"]))

View File

@ -1,418 +0,0 @@
# coding=utf-8
from datetime import datetime
import http.client
import hashlib
import re
import random
import socket
import sys
import threading
import time
from urllib.parse import quote
from module_state import ModuleState
import module_states_file as xmlparser
nemubotversion = 3.0
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "MCQ module, working with http://bot.nemunai.re/"
def help_full ():
return "!qcm [/nbQuest/] [/theme/]"
class QuestionFile:
def __init__(self, filename):
self.questions = xmlparser.parse_file(filename)
self.questions.setIndex("xml:id")
def getQuestion(self, ident):
if ident in self.questions.index:
return Question(self.questions.index[ident])
else:
return None
class Course:
def __init__(self, iden):
global COURSES
if iden in COURSES.index:
self.node = COURSES.index[iden]
else:
self.node = { "code":"N/A", "name":"N/A", "branch":"N/A" }
@property
def id(self):
return self.node["xml:id"]
@property
def code(self):
return self.node["code"]
@property
def name(self):
return self.node["name"]
@property
def branch(self):
return self.node["branch"]
@property
def validated(self):
return int(self.node["validated"]) > 0
class User:
def __init__(self, iden):
global USERS
if iden in USERS.index:
self.node = USERS.index[iden]
else:
self.node = { "username":"N/A", "email":"N/A" }
@property
def id(self):
return self.node["xml:id"]
@property
def username(self):
return self.node["username"]
@property
def email(self):
return self.node["email"]
@property
def validated(self):
return int(self.node["validated"]) > 0
class Question:
def __init__(self, node):
self.node = node
@property
def ident(self):
return self.node["xml:id"]
@property
def id(self):
return self.node["xml:id"]
@property
def question(self):
return self.node["question"]
@property
def course(self):
return Course(self.node["course"])
@property
def answers(self):
return self.node.getNodes("answer")
@property
def validator(self):
return User(self.node["validator"])
@property
def writer(self):
return User(self.node["writer"])
@property
def validated(self):
return self.node["validated"]
@property
def addedtime(self):
return datetime.fromtimestamp(float(self.node["addedtime"]))
@property
def author(self):
return User(self.node["writer"])
def report(self, raison="Sans raison"):
conn = http.client.HTTPConnection(CONF.getNode("server")["url"])
try:
conn.request("GET", "report.php?id=" + hashlib.md5(self.id.encode()).hexdigest() + "&raison=" + quote(raison))
except socket.gaierror:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return False
res = conn.getresponse()
conn.close()
return (res.status == http.client.OK)
@property
def tupleInfo(self):
return (self.author.username, self.validator.username, self.addedtime)
@property
def bestAnswer(self):
best = self.answers[0]
for answer in self.answers:
if best.getInt("score") < answer.getInt("score"):
best = answer
return best["answer"]
def isCorrect(self, msg):
msg = msg.lower().replace(" ", "")
for answer in self.answers:
if msg == answer["answer"].lower().replace(" ", ""):
return True
return False
def getScore(self, msg):
msg = msg.lower().replace(" ", "")
for answer in self.answers:
if msg == answer["answer"].lower().replace(" ", ""):
return answer.getInt("score")
return 0
class Session:
def __init__(self, srv, chan, sender):
self.questions = list()
self.current = -1
self.score = 0
self.good = 0
self.bad = 0
self.trys = 0
self.timer = None
self.server = srv
self.channel = chan
self.sender = sender
def addQuestion(self, ident):
if ident not in self.questions:
self.questions.append(ident)
return True
return False
def next_question(self):
self.trys = 0
self.current += 1
return self.question
@property
def question(self):
if self.current >= 0 and self.current < len(self.questions):
global QUESTIONS
return Question(QUESTIONS.index[self.questions[self.current]])
else:
return None
def askNext(self, bfr = ""):
global SESSIONS
self.timer = None
nextQ = self.next_question()
if nextQ is not None:
if self.channel == "nemubot":
self.server.send_msg_final(self.sender, "%s%s" % (bfr, nextQ.question))
elif self.sender != self.channel:
self.server.send_msg_final(self.channel, "%s: %s%s" % (self.sender, bfr, nextQ.question))
else:
self.server.send_msg_final(self.channel, "%s%s" % (bfr, nextQ.question))
else:
if self.good > 1:
goodS = "s"
else:
goodS = ""
if self.channel == "nemubot":
self.server.send_msg_final(self.sender, "%sFini, tu as donné %d bonne%s réponse%s sur %d questions." % (self.sender, bfr, self.good, goodS, goodS, len(self.questions)))
elif self.sender != self.channel:
self.server.send_msg_final(self.channel, "%s: %sFini, tu as donné %d bonne%s réponse%s sur %d questions." % (self.sender, bfr, self.good, goodS, goodS, len(self.questions)))
else:
self.server.send_msg_final(self.channel, "%sFini, vous avez donné %d bonne%s réponse%s sur %d questions." % (bfr, self.good, goodS, goodS, len(self.questions)))
del SESSIONS[self.sender]
def prepareNext(self, lag = 3):
if self.timer is None:
self.timer = threading.Timer(lag, self.askNext)
self.timer.start()
QUESTIONS = None
COURSES = None
USERS = None
SESSIONS = dict()
def load():
CONF.setIndex("name", "file")
def buildSession(msg, categ = None, nbQuest = 10, channel = False):
global QUESTIONS, COURSES, USERS
if QUESTIONS is None:
QUESTIONS = xmlparser.parse_file(CONF.index["main"]["url"])
QUESTIONS.setIndex("xml:id")
COURSES = xmlparser.parse_file(CONF.index["courses"]["url"])
COURSES.setIndex("xml:id")
USERS = xmlparser.parse_file(CONF.index["users"]["url"])
USERS.setIndex("xml:id")
#Remove no validated questions
keys = list()
for k in QUESTIONS.index.keys():
keys.append(k)
for ques in keys:
if QUESTIONS.index[ques]["validated"] != "1" or QUESTIONS.index[ques]["reported"] == "1":
del QUESTIONS.index[ques]
#Apply filter
QS = list()
if categ is not None and len(categ) > 0:
#Find course id corresponding to categ
courses = list()
for c in COURSES.childs:
if c["code"] in categ:
courses.append(c["xml:id"])
#Keep only questions matching course or branch
for q in QUESTIONS.index.keys():
if (QUESTIONS.index[q]["branch"] is not None and QUESTIONS.index[q]["branch"].find(categ)) or QUESTIONS.index[q]["course"] in courses:
QS.append(q)
else:
for q in QUESTIONS.index.keys():
QS.append(q)
nbQuest = min(nbQuest, len(QS))
if channel:
sess = Session(msg.srv, msg.channel, msg.channel)
else:
sess = Session(msg.srv, msg.channel, msg.sender)
maxQuest = len(QS) - 1
for i in range(0, nbQuest):
while True:
q = QS[random.randint(0, maxQuest)]
if sess.addQuestion(q):
break
if channel:
SESSIONS[msg.channel] = sess
else:
SESSIONS[msg.sender] = sess
def askQuestion(msg, bfr = ""):
SESSIONS[msg.sender].askNext(bfr)
def parseanswer(msg):
global DATAS, SESSIONS, COURSES, QUESTIONS, USERS
if msg.cmd[0] == "qcm" or msg.cmd[0] == "qcmchan" or msg.cmd[0] == "simulateqcm":
if msg.sender in SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = SESSIONS[msg.sender]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("%s: Fini, tu as donné %d bonne%s réponse%s sur %d questions." % (msg.sender, sess.good, goodS, goodS, sess.current))
del SESSIONS[msg.sender]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
askQuestion(msg)
return True
msg.send_chn("%s: tu as déjà une session de QCM en cours, finis-la avant d'en commencer une nouvelle." % msg.sender)
elif msg.channel in SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = SESSIONS[msg.channel]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("Fini, vous avez donné %d bonne%s réponse%s sur %d questions." % (sess.good, goodS, goodS, sess.current))
del SESSIONS[msg.channel]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
SESSIONS[msg.channel].prepareNext(1)
return True
else:
nbQuest = 10
filtre = list()
if len(msg.cmd) > 1:
for cmd in msg.cmd[1:]:
try:
tmp = int(cmd)
nbQuest = tmp
except ValueError:
filtre.append(cmd.upper())
if len(filtre) == 0:
filtre = None
if msg.channel in SESSIONS:
msg.send_snd("Il y a deja une session de QCM sur ce chan.")
else:
buildSession(msg, filtre, nbQuest, msg.cmd[0] == "qcmchan")
if msg.cmd[0] == "qcm":
askQuestion(msg)
elif msg.cmd[0] == "qcmchan":
SESSIONS[msg.channel].askNext()
else:
msg.send_chn("QCM de %d questions" % len(SESSIONS[msg.sender].questions))
del SESSIONS[msg.sender]
return True
elif msg.sender in SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % SESSIONS[msg.sender].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif SESSIONS[msg.sender].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
SESSIONS[msg.sender].askNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
elif msg.channel in SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % SESSIONS[msg.channel].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif SESSIONS[msg.channel].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
SESSIONS[msg.channel].prepareNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
else:
if msg.cmd[0] == "listecours":
if COURSES is None:
msg.send_chn("La liste de cours n'est pas encore construite, lancez un QCM pour la construire.")
else:
lst = ""
for cours in COURSES.getNodes("course"):
lst += cours["code"] + " (" + cours["name"] + "), "
msg.send_chn("Liste des cours existants : " + lst[:len(lst)-2])
elif msg.cmd[0] == "refreshqcm":
QUESTIONS = None
COURSES = None
USERS = None
return False
def parseask(msg):
if msg.sender in SESSIONS:
dest = msg.sender
if SESSIONS[dest].question.isCorrect(msg.content):
SESSIONS[dest].good += 1
SESSIONS[dest].score += SESSIONS[dest].question.getScore(msg.content)
askQuestion(msg, "correct ; ")
else:
SESSIONS[dest].bad += 1
if SESSIONS[dest].trys == 0:
SESSIONS[dest].trys = 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
else:
askQuestion(msg, "non, la bonne reponse était : %s ; " % SESSIONS[dest].question.bestAnswer)
return True
elif msg.channel in SESSIONS:
dest = msg.channel
if SESSIONS[dest].question.isCorrect(msg.content):
SESSIONS[dest].good += 1
SESSIONS[dest].score += SESSIONS[dest].question.getScore(msg.content)
msg.send_chn("%s: correct :)" % msg.sender)
SESSIONS[dest].prepareNext()
else:
SESSIONS[dest].bad += 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
return True
return False

202
modules/qcm/__init__.py Normal file
View File

@ -0,0 +1,202 @@
# coding=utf-8
from datetime import datetime
import http.client
import re
import random
import sys
import time
nemubotversion = 3.0
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "MCQ module, working with http://bot.nemunai.re/"
def help_full ():
return "!qcm [<nbQuest>] [<theme>]"
from . import Question
from . import Course
from . import Session
def load():
CONF.setIndex("name", "file")
def buildSession(msg, categ = None, nbQuest = 10, channel = False):
if Question.QUESTIONS is None:
Question.QUESTIONS = xmlparser.parse_file(CONF.index["main"]["url"])
Question.QUESTIONS.setIndex("xml:id")
Course.COURSES = xmlparser.parse_file(CONF.index["courses"]["url"])
Course.COURSES.setIndex("xml:id")
User.USERS = xmlparser.parse_file(CONF.index["users"]["url"])
User.USERS.setIndex("xml:id")
#Remove no validated questions
keys = list()
for k in Question.QUESTIONS.index.keys():
keys.append(k)
for ques in keys:
if Question.QUESTIONS.index[ques]["validated"] != "1" or Question.QUESTIONS.index[ques]["reported"] == "1":
del Question.QUESTIONS.index[ques]
#Apply filter
QS = list()
if categ is not None and len(categ) > 0:
#Find course id corresponding to categ
courses = list()
for c in Course.COURSES.childs:
if c["code"] in categ:
courses.append(c["xml:id"])
#Keep only questions matching course or branch
for q in Question.QUESTIONS.index.keys():
if (Question.QUESTIONS.index[q]["branch"] is not None and Question.QUESTIONS.index[q]["branch"].find(categ)) or Question.QUESTIONS.index[q]["course"] in courses:
QS.append(q)
else:
for q in Question.QUESTIONS.index.keys():
QS.append(q)
nbQuest = min(nbQuest, len(QS))
if channel:
sess = Session.Session(msg.srv, msg.channel, msg.channel)
else:
sess = Session.Session(msg.srv, msg.channel, msg.sender)
maxQuest = len(QS) - 1
for i in range(0, nbQuest):
while True:
q = QS[random.randint(0, maxQuest)]
if sess.addQuestion(q):
break
if channel:
Session.SESSIONS[msg.channel] = sess
else:
Session.SESSIONS[msg.sender] = sess
def askQuestion(msg, bfr = ""):
Session.SESSIONS[msg.sender].askNext(bfr)
def parseanswer(msg):
global DATAS
if msg.cmd[0] == "qcm" or msg.cmd[0] == "qcmchan" or msg.cmd[0] == "simulateqcm":
if msg.sender in Session.SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = Session.SESSIONS[msg.sender]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("%s: Fini, tu as donné %d bonne%s réponse%s sur %d questions." % (msg.sender, sess.good, goodS, goodS, sess.current))
del Session.SESSIONS[msg.sender]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
askQuestion(msg)
return True
msg.send_chn("%s: tu as déjà une session de QCM en cours, finis-la avant d'en commencer une nouvelle." % msg.sender)
elif msg.channel in Session.SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = Session.SESSIONS[msg.channel]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("Fini, vous avez donné %d bonne%s réponse%s sur %d questions." % (sess.good, goodS, goodS, sess.current))
del Session.SESSIONS[msg.channel]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
Session.SESSIONS[msg.channel].prepareNext(1)
return True
else:
nbQuest = 10
filtre = list()
if len(msg.cmd) > 1:
for cmd in msg.cmd[1:]:
try:
tmp = int(cmd)
nbQuest = tmp
except ValueError:
filtre.append(cmd.upper())
if len(filtre) == 0:
filtre = None
if msg.channel in Session.SESSIONS:
msg.send_snd("Il y a deja une session de QCM sur ce chan.")
else:
buildSession(msg, filtre, nbQuest, msg.cmd[0] == "qcmchan")
if msg.cmd[0] == "qcm":
askQuestion(msg)
elif msg.cmd[0] == "qcmchan":
Session.SESSIONS[msg.channel].askNext()
else:
msg.send_chn("QCM de %d questions" % len(Session.SESSIONS[msg.sender].questions))
del Session.SESSIONS[msg.sender]
return True
elif msg.sender in Session.SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % Session.SESSIONS[msg.sender].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif Session.SESSIONS[msg.sender].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
Session.SESSIONS[msg.sender].askNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
elif msg.channel in Session.SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % Session.SESSIONS[msg.channel].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif Session.SESSIONS[msg.channel].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
Session.SESSIONS[msg.channel].prepareNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
else:
if msg.cmd[0] == "listecours":
if Course.COURSES is None:
msg.send_chn("La liste de cours n'est pas encore construite, lancez un QCM pour la construire.")
else:
lst = ""
for cours in Course.COURSES.getNodes("course"):
lst += cours["code"] + " (" + cours["name"] + "), "
msg.send_chn("Liste des cours existants : " + lst[:len(lst)-2])
elif msg.cmd[0] == "refreshqcm":
Question.QUESTIONS = None
Course.COURSES = None
User.USERS = None
return False
def parseask(msg):
if msg.sender in Session.SESSIONS:
dest = msg.sender
if Session.SESSIONS[dest].question.isCorrect(msg.content):
Session.SESSIONS[dest].good += 1
Session.SESSIONS[dest].score += Session.SESSIONS[dest].question.getScore(msg.content)
askQuestion(msg, "correct ; ")
else:
Session.SESSIONS[dest].bad += 1
if Session.SESSIONS[dest].trys == 0:
Session.SESSIONS[dest].trys = 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
else:
askQuestion(msg, "non, la bonne reponse était : %s ; " % Session.SESSIONS[dest].question.bestAnswer)
return True
elif msg.channel in Session.SESSIONS:
dest = msg.channel
if Session.SESSIONS[dest].question.isCorrect(msg.content):
Session.SESSIONS[dest].good += 1
Session.SESSIONS[dest].score += Session.SESSIONS[dest].question.getScore(msg.content)
msg.send_chn("%s: correct :)" % msg.sender)
Session.SESSIONS[dest].prepareNext()
else:
Session.SESSIONS[dest].bad += 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
return True
return False

View File

@ -1,19 +1,12 @@
# coding=utf-8
import re
import time
import random
import sys
import threading
from datetime import timedelta
from datetime import datetime
from datetime import date
from module_state import ModuleState
from wrapper import Wrapper
nemubotversion = 3.0
from . import GameUpdater
channels = "#nemutest #42sh #ykar #epitagueule"
LASTSEEN = dict ()
temps = dict ()
@ -21,9 +14,14 @@ temps = dict ()
SCORES = None
def load():
global DATAS, SCORES
global DATAS, SCORES, CONF
DATAS.setIndex("name", "player")
SCORES = QDWrapper()
SCORES = QDWrapper(DATAS)
GameUpdater.SCORES = SCORES
GameUpdater.CONF = CONF
GameUpdater.save = save
GameUpdater.getUser = getUser
def help_tiny ():
"""Line inserted in the response to the command !help"""
@ -33,150 +31,6 @@ def help_full ():
return "!42: display scores\n!42 help: display the performed calculate\n!42 manche: display information about current round\n!42 /who/: show the /who/'s scores"
class QDWrapper(Wrapper):
def __init__(self):
global DATAS
Wrapper.__init__(self)
self.DATAS = DATAS
self.stateName = "player"
self.attName = "name"
def __getitem__(self, i):
if i in self.cache:
return self.cache[i]
else:
sc = Score()
sc.parse(Wrapper.__getitem__(self, i))
self.cache[i] = sc
return sc
class Score:
"""Manage the user's scores"""
def __init__(self):
#FourtyTwo
self.ftt = 0
#TwentyThree
self.twt = 0
self.pi = 0
self.notfound = 0
self.tententen = 0
self.leet = 0
self.great = 0
self.bad = 0
self.triche = 0
self.last = None
self.changed = False
def parse(self, item):
self.ftt = item.getInt("fourtytwo")
self.twt = item.getInt("twentythree")
self.pi = item.getInt("pi")
self.notfound = item.getInt("notfound")
self.tententen = item.getInt("tententen")
self.leet = item.getInt("leet")
self.great = item.getInt("great")
self.bad = item.getInt("bad")
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):
self.ftt += other.ftt
self.twt += other.twt
self.pi += other.pi
self.notfound += other.notfound
self.tententen += other.tententen
self.leet += other.leet
self.great += other.great
self.bad += other.bad
self.triche += other.triche
def newWinner(self):
self.ftt = 0
self.twt = 0
self.pi = 1
self.notfound = 1
self.tententen = 0
self.leet = 1
self.great = -1
self.bad = -4
self.triche = 0
def isWinner(self):
return self.great >= 42
def playFtt(self):
if self.canPlay():
self.ftt += 1
def playTwt(self):
if self.canPlay():
self.twt += 1
def playSuite(self):
self.canPlay()
self.twt += 1
self.great += 1
def playPi(self):
if self.canPlay():
self.pi += 1
def playNotfound(self):
if self.canPlay():
self.notfound += 1
def playTen(self):
if self.canPlay():
self.tententen += 1
def playLeet(self):
if self.canPlay():
self.leet += 1
def playGreat(self):
if self.canPlay():
self.great += 1
def playBad(self):
if self.canPlay():
self.bad += 1
self.great += 1
def playTriche(self):
self.triche += 1
def oupsTriche(self):
self.triche -= 1
def bonusQuestion(self):
return
def toTuple(self):
return (self.ftt, self.twt, self.pi, self.notfound, self.tententen, self.leet, self.great, self.bad, self.triche)
def canPlay(self):
ret = self.last == None or self.last.minute != datetime.now().minute or self.last.hour != datetime.now().hour or self.last.day != datetime.now().day
self.changed = self.changed or ret
return ret
def hasChanged(self):
if self.changed:
self.changed = False
self.last = datetime.now()
return True
else:
return False
def score(self):
return (self.ftt * 2 + self.great * 5 + self.leet * 13.37 + (self.pi + 1) * 3.1415 * (self.notfound + 1) + self.tententen * 10 + self.twt - (self.bad + 1) * 10 * (self.triche * 5 + 1) + 7)
def details(self):
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 rev (tupl):
(k, v) = tupl
return (v.score(), k)
def parseanswer (msg):
if msg.cmd[0] == "42" or msg.cmd[0] == "score" or msg.cmd[0] == "scores":
global SCORES
@ -261,14 +115,20 @@ def win(msg):
def parseask (msg):
if len(DELAYED) > 0:
if msg.sender in DELAYED:
DELAYED[msg.sender].msg = msg.content
DELAYED[msg.sender].delayEvnt.set()
if len(GameUpdater.DELAYED) > 0:
if msg.sender in GameUpdater.DELAYED:
GameUpdater.DELAYED[msg.sender].msg = msg.content
GameUpdater.DELAYED[msg.sender].delayEvnt.set()
return True
return False
def rev (tupl):
(k, v) = tupl
return (v.score(), k)
def getUser(name):
global SCORES
if name not in SCORES:
@ -277,7 +137,7 @@ def getUser(name):
def parselisten (msg):
if len(DELAYED) > 0 and msg.sender in DELAYED and DELAYED[msg.sender].good(msg.content):
if len(GameUpdater.DELAYED) > 0 and msg.sender in GameUpdater.DELAYED and GameUpdater.DELAYED[msg.sender].good(msg.content):
msg.send_chn("%s: n'oublie pas le nemubot: devant ta réponse pour qu'elle soit prise en compte !" % msg.sender)
bfrseen = None
@ -285,8 +145,8 @@ def parselisten (msg):
bfrseen = LASTSEEN[msg.realname]
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 GameUpdater.DELAYED:
if msg.channel != "#nemutest" and msg.sender not in GameUpdater.DELAYED:
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:
@ -355,77 +215,3 @@ def parselisten (msg):
return True
return False
DELAYED = dict()
class DelayedTuple:
def __init__(self, regexp, great):
self.delayEvnt = threading.Event()
self.msg = None
self.regexp = regexp
self.great = great
def triche(self, res):
if res is not None:
return re.match(".*" + self.regexp + ".*", res.lower() + " ") is None
else:
return True
def perfect(self, res):
if res is not None:
return re.match(".*" + self.great + ".*", res.lower() + " ") is not None
else:
return False
def wait(self, timeout):
self.delayEvnt.wait(timeout)
LASTQUESTION = 99999
class GameUpdater(threading.Thread):
def __init__(self, msg, bfrseen):
self.msg = msg
self.bfrseen = bfrseen
threading.Thread.__init__(self)
def run(self):
global DELAYED, LASTQUESTION
if self.bfrseen is not None:
seen = datetime.now() - self.bfrseen
rnd = random.randint(0, int(seen.seconds/90))
else:
rnd = 1
if rnd != 0:
QUESTIONS = CONF.getNodes("question")
if self.msg.channel == "#nemutest":
quest = 9
else:
if LASTQUESTION >= len(QUESTIONS):
random.shuffle(QUESTIONS)
LASTQUESTION = 0
quest = LASTQUESTION
LASTQUESTION += 1
question = QUESTIONS[quest]["question"]
regexp = QUESTIONS[quest]["regexp"]
great = QUESTIONS[quest]["great"]
self.msg.send_chn("%s: %s" % (self.msg.sender, question))
DELAYED[self.msg.sender] = DelayedTuple(regexp, great)
DELAYED[self.msg.sender].wait(20)
if DELAYED[self.msg.sender].triche(DELAYED[self.msg.sender].msg):
getUser(self.msg.sender).playTriche()
self.msg.send_chn("%s: Tricheur !" % self.msg.sender)
elif DELAYED[self.msg.sender].perfect(DELAYED[self.msg.sender].msg):
if random.randint(0, 10) == 1:
getUser(self.msg.sender).bonusQuestion()
self.msg.send_chn("%s: Correct !" % self.msg.sender)
else:
self.msg.send_chn("%s: J'accepte" % self.msg.sender)
del DELAYED[self.msg.sender]
SCORES.save(self.msg.sender)
save()

View File

@ -7,137 +7,28 @@ import _thread
import threading
from datetime import date
from datetime import datetime
from datetime import timedelta
from module_state import ModuleState
from .SiteSoutenances import SiteSoutenances
from .Delayed import Delayed
nemubotversion = 3.0
def getPage ():
conn = http.client.HTTPSConnection(CONF.getNode("server")["ip"])
conn.request("GET", CONF.getNode("server")["url"])
res = conn.getresponse()
data = res.read()
conn.close()
return data
class Soutenance:
def __init__(self):
self.hour = None
self.rank = 0
self.login = None
self.state = None
self.assistant = None
self.start = None
self.end = None
DELAYED = dict()
class Delayed:
def __init__(self, name):
self.name = name
self.res = None
self.evt = threading.Event()
def wait(self, timeout):
self.evt.clear()
self.evt.wait(timeout)
class SiteSoutenances:
def __init__(self, page):
save = False
self.souts = list()
self.updated = datetime.now ()
last = None
for line in page.split("\n"):
if re.match("</tr>", line) is not None:
save = False
elif re.match("<tr.*>", line) is not None:
save = True
last = Soutenance()
self.souts.append(last)
elif save:
result = re.match("<td[^>]+>(.*)</td>", line)
if last.hour is None:
try:
last.hour = datetime.fromtimestamp (time.mktime (time.strptime (result.group(1), "%Y-%m-%d %H:%M")))
except ValueError:
continue
elif last.rank == 0:
last.rank = int (result.group(1))
elif last.login == None:
last.login = result.group(1)
elif last.state == None:
last.state = result.group(1)
elif last.assistant == None:
last.assistant = result.group(1)
elif last.start == None:
try:
last.start = datetime.fromtimestamp (time.mktime (time.strptime (result.group(1), "%Y-%m-%d %H:%M")))
except ValueError:
last.start = None
elif last.end == None:
try:
last.end = datetime.fromtimestamp (time.mktime (time.strptime (result.group(1), "%Y-%m-%d %H:%M")))
except ValueError:
last.end = None
def update(self):
if self.findLast() is not None and datetime.now () - self.updated > timedelta(minutes=2):
return None
elif datetime.now () - self.updated < timedelta(hours=1):
return self
else:
return None
def findAssistants(self):
h = {}
for s in self.souts:
if s.assistant is not None and s.assistant != "":
h[s.assistant] = (s.start, s.end)
return h
def findLast(self):
close = None
for s in self.souts:
if (s.state != "En attente" and s.start is not None and (close is None or close.rank < s.rank or close.hour.day > s.hour.day)) and (close is None or s.hour - close.hour < timedelta(seconds=2499)):
close = s
return close
def findAll(self, login):
ss = list()
for s in self.souts:
if s.login == login:
ss.append(s)
return ss
def findClose(self, login):
ss = self.findAll(login)
close = None
for s in ss:
if close is not None:
print (close.hour)
print (s.hour)
if close is None or (close.hour < s.hour and close.hour.day >= datetime.datetime().day):
close = s
return close
def help_tiny ():
def help_tiny():
"""Line inserted in the response to the command !help"""
return "EPITA ING1 defenses module"
def help_full ():
return "!soutenance: gives information about current defenses state\n!soutenance /who/: gives the date of the next defense of /who/.\n!soutenances /who/: gives all defense dates of /who/"
def help_full():
return "!soutenance: gives information about current defenses state\n!soutenance <who>: gives the date of the next defense of /who/.\n!soutenances <who>: gives all defense dates of /who/"
datas = None
THREAD = None
wait = list()
def parseanswer (msg):
def parseanswer(msg):
global THREAD, wait
if msg.cmd[0] == "soutenance" or msg.cmd[0] == "soutenances":
if THREAD is None:
@ -148,6 +39,22 @@ def parseanswer (msg):
return False
def parseask(msg):
if len(DELAYED) > 0 and msg.sender == msg.srv.partner:
treat = False
for part in msg.content.split(';'):
if part is None:
continue
for d in DELAYED.keys():
if DELAYED[d].res is None and part.find(DELAYED[d].name) >= 0:
result = re.match(".* est (.*[^.])\.?", part)
if result is not None:
DELAYED[d].res = result.group(1)
DELAYED[d].evt.set()
return treat
return False
def startSoutenance (msg):
global datas, THREAD, wait
@ -224,17 +131,16 @@ def startSoutenance (msg):
startSoutenance(wait.pop())
def parseask (msg):
if len(DELAYED) > 0 and msg.sender == msg.srv.partner:
treat = False
for part in msg.content.split(';'):
if part is None:
continue
for d in DELAYED.keys():
if DELAYED[d].res is None and part.find(DELAYED[d].name) >= 0:
result = re.match(".* est (.*[^.])\.?", part)
if result is not None:
DELAYED[d].res = result.group(1)
DELAYED[d].evt.set()
return treat
return False
def getPage():
conn = http.client.HTTPConnection(CONF.getNode("server")["ip"])
try:
conn.request("GET", CONF.getNode("server")["url"])
res = conn.getresponse()
data = res.read()
except:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return ""
conn.close()
return data

View File

@ -1,206 +0,0 @@
# coding=utf-8
from datetime import timedelta
from datetime import datetime
from datetime import date
import http.client
import hashlib
import sys
import traceback
import socket
import time
import base64
import threading
from urllib.parse import unquote
from module_state import ModuleState
nemubotversion = 3.0
import atom
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "Alert on changes on websites"
def help_full ():
return "This module is autonomous you can't interract with it."
WATCHER = None
def load():
global WATCHER, DATAS
#Load the watcher
WATCHER = Watcher()
for site in DATAS.getNodes("watch"):
s = Site(site)
WATCHER.addServer(s)
WATCHER.start()
def close():
global WATCHER
if WATCHER is not None:
WATCHER.stop = True
WATCHER.newSrv.set()
class Watcher(threading.Thread):
def __init__(self):
self.servers = list()
self.stop = False
self.newSrv = threading.Event()
threading.Thread.__init__(self)
def addServer(self, server):
self.servers.append(server)
self.newSrv.set()
def check(self, closer):
closer.check()
self.newSrv.set()
def run(self):
while not self.stop:
self.newSrv.clear()
closer = None
#Gets the closer server update
for server in self.servers:
if server.update < datetime.now():
#print ("Closer now: %s à %s"%(server.url, server.update))
self.check(server)
elif closer is None or server.update < closer.update:
closer = server
if closer is not None:
#print ("Closer: %s à %s"%(closer.url, closer.update))
timeleft = (closer.update - datetime.now()).seconds
timer = threading.Timer(timeleft, self.check, (closer,))
timer.start()
#print ("Start timer (%ds)"%timeleft)
self.newSrv.wait()
if closer is not None and closer.update is not None and closer.update > datetime.now():
timer.cancel()
def stop(self):
self.stop = True
self.newSrv.set()
class Site:
def __init__(self, item):
self.server = item.getAttribute("server")
self.page = item.getAttribute("page")
if len(self.page) <= 0 or self.page[0] != "/":
self.page = "/" + self.page
if item.hasAttribute("type"):
self.type = item.getAttribute("type")
else:
self.type = "hash"
self.message = item.getAttribute("message")
if item.hasAttribute("time"):
self.updateTime = item.getInt("time")
else:
self.updateTime = 60
self.lastChange = datetime.now()
self.lastpage = None
self.channels = list()
for channel in item.getNodes('channel'):
self.channels.append(channel.getAttribute("name"))
self.categories = dict()
for category in item.getNodes('category'):
self.categories[category.getAttribute("term")] = category.getAttribute("part")
@property
def update(self):
if self.lastpage is None:
return self.lastChange
else:
return self.lastChange + timedelta(seconds=self.updateTime)
@property
def url(self):
return self.server + self.page
def send_message (self, msg):
global SRVS
if len(self.channels) > 0:
for server in SRVS.keys():
for chan in self.channels:
SRVS[server].send_msg (chan, msg)
else:
for server in SRVS.keys():
SRVS[server].send_global (msg)
def treat_atom (self, content):
change=False
f = atom.Atom (content)
if self.lastpage is not None:
diff = self.lastpage.diff (f)
if len(diff) > 0:
print ("[%s] Page differ!"%self.server)
diff.reverse()
for d in diff:
if self.message.count("%s") == 2 and len(self.categories) > 0:
if d.category is None or d.category not in self.categories:
messageI = self.message % (self.categories[""], "%s")
else:
messageI = self.message % (self.categories[d.category], "%s")
self.send_message (messageI % unquote (d.link))
elif self.message.count("%s") == 2:
if f.id == youtube.idAtom:
youtube.send_global (d.link2, self.message % (d.title, unquote (d.link)))
else:
self.send_message (self.message % (d.title, unquote (d.link)))
elif self.message.count("%s") == 1:
self.send_message(self.message % unquote (d.title))
else:
self.send_message(self.message)
change=True
return (f, change)
def check (self):
try:
#print ("Check %s"%(self.url))
(status, content) = getPage(self.server, self.page)
if content is None:
return
if self.type == "atom":
(self.lastpage, change) = self.treat_atom (content)
else:
hash = hashlib.sha224(content).hexdigest()
if hash != self.lastpage:
if self.lastpage is not None:
self.send_message (self.message)
self.lastpage = hash
self.lastChange = datetime.now()
# if self.updateTime < 10:
# self.updateTime = 10
# if self.updateTime > 400:
# self.updateTime = 400
except:
print ("Une erreur est survenue lors de la récupération de la page " + self.server + "/" + self.page)
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
self.updateTime *= 2
def getPage(s, p):
conn = http.client.HTTPConnection(s)
try:
conn.request("GET", p)
res = conn.getresponse()
data = res.read()
except socket.gaierror:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return (None, None)
conn.close()
return (res.status, data)

View File

@ -0,0 +1,32 @@
# coding=utf-8
nemubotversion = 3.0
from .Watcher import Watcher
from .Site import Site
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "Alert on changes on websites"
def help_full ():
return "This module is autonomous you can't interract with it."
WATCHER = None
def load():
global WATCHER, DATAS
#Load the watcher
WATCHER = Watcher()
for site in DATAS.getNodes("watch"):
s = Site(site)
WATCHER.addServer(s)
WATCHER.start()
def close():
global WATCHER
if WATCHER is not None:
WATCHER.stop = True
WATCHER.newSrv.set()

View File

@ -13,102 +13,25 @@ from urllib.parse import unquote
from module_state import ModuleState
from . import User
from .UpdatedStorage import UpdatedStorage
from .Delayed import Delayed
nemubotversion = 3.0
THREAD = None
search = list()
class UpdatedStorage:
def __init__(self):
sock = connect_to_ns(CONF.getNode("server")["url"],
CONF.getNode("server").getInt("port"))
self.users = dict()
if sock != None:
users = list_users(sock)
if users is not None:
for l in users:
u = User(l)
if u.login not in self.users:
self.users[u.login] = list()
self.users[u.login].append(u)
self.lastUpdate = datetime.now ()
else:
self.users = None
sock.close()
else:
self.users = None
def update(self):
if datetime.now () - self.lastUpdate < timedelta(minutes=10):
return self
else:
return None
class User(object):
def __init__(self, line):
fields = line.split()
self.login = fields[1]
self.ip = fields[2]
self.location = fields[8]
self.promo = fields[9]
@property
def sm(self):
for sm in CONF.getNodes("sm"):
if self.ip.startswith(sm["ip"]):
return sm["name"]
return None
@property
def poste(self):
if self.sm is None:
if self.ip.startswith('10.'):
return 'quelque part sur le PIE (%s)'%self.ip
else:
return "chez lui"
else:
if self.ip.startswith('10.247') or self.ip.startswith('10.248') or self.ip.startswith('10.249') or self.ip.startswith('10.250'):
return "en " + self.sm + " rangée " + self.ip.split('.')[2] + " poste " + self.ip.split('.')[3]
else:
return "en " + self.sm
def __cmp__(self, other):
return cmp(self.login, other.login)
def __hash__(self):
return hash(self.login)
def connect_to_ns(server, port):
try:
s = socket.socket()
s.settimeout(3)
s.connect((server, port))
except socket.error:
return None
s.recv(8192)
return s
def list_users(sock):
try:
sock.send('list_users\n'.encode())
buf = ''
while True:
tmp = sock.recv(8192).decode()
buf += tmp
if '\nrep 002' in tmp or tmp == '':
break
return buf.split('\n')[:-2]
except socket.error:
return None
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "Find a user on the PIE"
def help_full ():
return "!whereis /who/: gives the position of /who/.\n!whereare /who/ [/other who/ ...]: gives the position of /who/."
return "!whereis <who>: gives the position of /who/.\n!whereare <who> [<other who> ...]: gives the position of these <who>.\n!peoplein <sm>: gives the number of people in this /sm/.\n!ip <who>: gets the IP adress of /who/.\n!whoison <location>: gives the name or the number (if > 15) of people at this /location/.\n!whoisin <sm>: gives the name or the number of people in this /sm/"
def load():
global CONF
User.CONF = CONF
datas = None
@ -117,7 +40,7 @@ def startWhereis(msg):
if datas is not None:
datas = datas.update ()
if datas is None:
datas = UpdatedStorage()
datas = UpdatedStorage(CONF.getNode("server")["url"], CONF.getNode("server").getInt("port"))
if datas is None or datas.users is None:
msg.send_chn("Hmm c'est embarassant, serait-ce la fin du monde ou juste netsoul qui est mort ?")
return
@ -178,10 +101,6 @@ def whoison(msg):
DELAYED = dict()
delayEvnt = threading.Event()
class Delayed:
def __init__(self):
self.names = dict()
def whereis_msg(msg):
names = list()
for name in msg.cmd:

View File

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

View File

@ -3,7 +3,8 @@
import http.client
import re
import sys
import threading
from .Tinyfier import Tinyfier
nemubotversion = 3.0
@ -15,24 +16,6 @@ def help_full ():
return "TODO"
class Tinyfier(threading.Thread):
def __init__(self, url, msg):
self.url = url
self.msg = msg
threading.Thread.__init__(self)
def run(self):
(status, page) = getPage("ycc.fr", "/redirection/create/" + self.url)
if status == http.client.OK and len(page) < 100:
srv = re.match(".*((ht|f)tps?://|www.)([^/ ]+).*", self.url)
if srv is None:
self.msg.send_chn("Mauvaise URL : %s" % (self.url))
else:
self.msg.send_chn("URL pour %s : %s" % (srv.group(3), page.decode()))
else:
print ("ERROR: ycc.fr seem down?")
self.msg.send_chn("La situation est embarassante, il semblerait que YCC soit down :(")
def parseanswer(msg):
global LAST_URLS
if msg.cmd[0] == "ycc":
@ -42,7 +25,7 @@ def parseanswer(msg):
t = Tinyfier(url, msg)
t.start()
else:
msg.send_chn("%s: je n'ai pas d'autre URL a reduire" % msg.sender)
msg.send_chn("%s: je n'ai pas d'autre URL reduire" % msg.sender)
else:
if len(msg.cmd) < 6:
for url in msg.cmd[1:]:
@ -66,17 +49,3 @@ def parselisten (msg):
LAST_URLS[msg.channel] = list(res.group(1))
return True
return False
def getPage(s, p):
conn = http.client.HTTPConnection(s)
try:
conn.request("GET", p)
except socket.gaierror:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return None
res = conn.getresponse()
data = res.read()
conn.close()
return (res.status, data)

View File

@ -10,9 +10,19 @@ servers = dict()
prompt = __import__ ("prompt")
#Add modules dir path
if os.path.isdir("./modules/"):
modules_path = os.path.realpath(os.path.abspath("./modules/"))
if modules_path not in sys.path:
sys.path.insert(0, modules_path)
#Load given files
if len(sys.argv) >= 2:
for arg in sys.argv[1:]:
prompt.load_file(arg, servers)
if os.path.isfile(arg):
prompt.load_file(arg, servers)
elif os.path.isdir(arg):
sys.path.insert(1, arg)
print ("Nemubot ready, my PID is %i!" % (os.getpid()))
while prompt.launch(servers):

178
prompt.py
View File

@ -1,4 +1,5 @@
import imp
import os
import shlex
import sys
import traceback
@ -92,12 +93,12 @@ def launch(servers):
# #
##########################
def mod_save(mod, datas_path, config):
mod.DATAS.save(datas_path + "/" + config["name"] + ".xml")
def mod_save(mod, datas_path):
mod.DATAS.save(datas_path + "/" + mod.name + ".xml")
mod.print ("Saving!")
def mod_has_access(mod, config, msg):
if config.hasNode("channel"):
if config is not None and config.hasNode("channel"):
for chan in config.getChilds("channel"):
if (chan["server"] is None or chan["server"] == msg.srv.id) and (chan["channel"] is None or chan["channel"] == msg.channel):
return True
@ -111,93 +112,106 @@ def mod_has_access(mod, config, msg):
# #
##########################
def load_module_from_name(name, servers, config=None):
try:
#Import the module code
mod = __import__(name)
try:
if mod.nemubotversion < 3.0:
print (" Module `%s' is not compatible with this version." % name)
return
#Set module common functions and datas
mod.name = name
mod.print = lambda msg: print("[%s] %s"%(mod.name, msg))
mod.DATAS = xmlparser.parse_file(datas_path + "/" + name + ".xml")
mod.CONF = config
mod.SRVS = servers
mod.has_access = lambda msg: mod_has_access(mod, config, msg)
mod.save = lambda: mod_save(mod, datas_path)
#Load dependancies
if mod.CONF is not None and mod.CONF.hasNode("dependson"):
mod.MODS = dict()
for depend in mod.CONF.getNodes("dependson"):
for md in MODS:
if md.name == depend["name"]:
mod.MODS[md.name] = md
break
if depend["name"] not in mod.MODS:
print ("\033[1;31mERROR:\033[0m in module `%s', module `%s' require by this module but is not loaded." % (mod.name,depend["name"]))
return
try:
test = mod.parseask
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseask defined." % mod.name)
mod.parseask = lambda x: False
try:
test = mod.parseanswer
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseanswer defined." % mod.name)
mod.parseanswer = lambda x: False
try:
test = mod.parselisten
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parselisten defined." % mod.name)
mod.parselisten = lambda x: False
try:
mod.load()
print (" Module `%s' successfully loaded." % name)
except AttributeError:
print (" Module `%s' successfully added." % name)
#TODO: don't append already running modules
MODS.append(mod)
except AttributeError:
print (" Module `%s' is not a nemubot module." % name)
for srv in servers:
servers[srv].update_mods(MODS)
except IOError:
print (" Module `%s' not loaded: unable to find module implementation." % name)
except ImportError:
print ("\033[1;31mERROR:\033[0m Module attached to the file `%s' not loaded. Is this file existing?" % name)
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
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.SRVS = servers
mod.has_access = lambda msg: mod_has_access(mod, config, msg)
mod.save = lambda: mod_save(mod, datas_path, config)
#Load dependancies
if mod.CONF.hasNode("dependson"):
mod.MODS = dict()
for depend in mod.CONF.getNodes("dependson"):
for md in MODS:
if md.name == depend["name"]:
mod.MODS[md.name] = md
break
if depend["name"] not in mod.MODS:
print ("\033[1;35mERROR:\033[0m in module `%s', module `%s' require by this module but is not loaded." % (mod.name,depend["name"]))
return
try:
test = mod.parseask
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseask defined." % mod.name)
mod.parseask = lambda x: False
try:
test = mod.parseanswer
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseanswer defined." % mod.name)
mod.parseanswer = lambda x: False
try:
test = mod.parselisten
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parselisten defined." % mod.name)
mod.parselisten = lambda x: False
try:
mod.load()
print (" Module `%s' successfully loaded." % config["name"])
except AttributeError:
print (" Module `%s' successfully added." % config["name"])
#TODO: don't append already running modules
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"])
load_module_from_name(config["name"], servers, config)
def load_file(filename, servers):
"""Realy load a file"""
global MODS
config = xmlparser.parse_file(filename)
if config.getName() == "nemubotconfig" or config.getName() == "config":
#Preset each server in this file
for serveur in config.getNodes("server"):
srv = server.Server(serveur, config["nick"], config["owner"], config["realname"])
if srv.id not in servers:
servers[srv.id] = srv
print (" Server `%s' successfully added." % srv.id)
else:
print (" Server `%s' already added, skiped." % srv.id)
if srv.autoconnect:
srv.launch(MODS)
#Load files asked by the configuration file
for load in config.getNodes("load"):
load_file(load["path"], servers)
elif config.getName() == "nemubotmodule":
load_module(config, servers)
if os.path.isfile(filename):
config = xmlparser.parse_file(filename)
if config.getName() == "nemubotconfig" or config.getName() == "config":
#Preset each server in this file
for serveur in config.getNodes("server"):
srv = server.Server(serveur, config["nick"], config["owner"], config["realname"])
if srv.id not in servers:
servers[srv.id] = srv
print (" Server `%s' successfully added." % srv.id)
else:
print (" Server `%s' already added, skiped." % srv.id)
if srv.autoconnect:
srv.launch(MODS)
#Load files asked by the configuration file
for load in config.getNodes("load"):
load_file(load["path"], servers)
elif config.getName() == "nemubotmodule":
load_module(config, servers)
else:
print (" Can't load `%s'; this is not a valid nemubot configuration file." % filename)
elif os.path.isfile(filename + ".xml"):
load_file(filename + ".xml", servers)
elif os.path.isfile("./modules/" + filename + ".xml"):
load_file("./modules/" + filename + ".xml", servers)
else:
print (" Can't load `%s'; this is not a valid nemubot configuration file." % filename)
load_module_from_name(filename, servers)
def load(cmds, servers):