diff --git a/modules/soutenance.xml b/modules/soutenance.xml index ed5da4d..957423b 100644 --- a/modules/soutenance.xml +++ b/modules/soutenance.xml @@ -1,4 +1,5 @@ - - \ No newline at end of file + + + diff --git a/modules/soutenance/SiteSoutenances.py b/modules/soutenance/SiteSoutenances.py index ffbc30e..63833b7 100644 --- a/modules/soutenance/SiteSoutenances.py +++ b/modules/soutenance/SiteSoutenances.py @@ -2,87 +2,178 @@ from datetime import datetime from datetime import timedelta +import http.client import re +import threading import time +from response import Response + from .Soutenance import Soutenance -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("", line) is not None: +class SiteSoutenances(threading.Thread): + def __init__(self, datas): + self.souts = list() + self.updated = datetime.now() + self.datas = datas + threading.Thread.__init__(self) + + def getPage(self): + conn = http.client.HTTPSConnection(CONF.getNode("server")["ip"], timeout=10) + try: + conn.request("GET", CONF.getNode("server")["url"]) + + res = conn.getresponse() + page = res.read() + except: + print ("[%s] impossible de récupérer la page %s."%(s, p)) + return "" + conn.close() + return page + + def parsePage(self, page): save = False - elif re.match("", line) is not None: - save = True - last = Soutenance() - self.souts.append(last) - elif save: - result = re.match("]+>(.*)", 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 + for line in page.split("\n"): + if re.match("", line) is not None: + save = False + elif re.match("", line) is not None: + save = True + last = Soutenance() + self.souts.append(last) + elif save: + result = re.match("]+>(.*)", 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 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 gen_response(self, req, msg): + """Generate a text response on right server and channel""" + return Response(req["sender"], msg, req["channel"], server=req["server"]) - 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 res_next(self, req): + soutenance = self.findLast() + if soutenance is None: + return self.gen_response(req, "Il ne semble pas y avoir de soutenance pour le moment.") + else: + if soutenance.start > soutenance.hour: + avre = "%s de *retard*"%msg.just_countdown(soutenance.start - soutenance.hour, 4) + else: + avre = "%s *d'avance*"%msg.just_countdown(soutenance.hour - soutenance.start, 4) + self.gen_response(req, "Actuellement à la soutenance numéro %d, commencée il y a %s avec %s."%(soutenance.rank, msg.just_countdown(datetime.now () - soutenance.start, 4), avre)) - def findAll(self, login): - ss = list() - for s in self.souts: - if s.login == login: - ss.append(s) - return ss + def res_assistants(self, req): + assistants = self.findAssistants() + if len(assistants) > 0: + return self.gen_response(req, "Les %d assistants faisant passer les soutenances sont : %s." % (len(assistants), ', '.join(assistants.keys()))) + else: + return self.gen_response(req, "Il ne semble pas y avoir de soutenance pour le moment.") - 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 res_soutenance(self, req): + name = req["user"] + + if name == "acu" or name == "yaka" or name == "acus" or name == "yakas" or name == "assistant" or name == "assistants": + return self.res_assistants(req) + elif name == "next": + return self.res_next(req) + + soutenance = self.findClose(name) + if soutenance is None: + return self.gen_response(req, "Pas d'horaire de soutenance pour %s."%name) + else: + if soutenance.state == "En cours": + return self.gen_response(req, "%s est actuellement en soutenance avec %s. Elle était prévue à %s, position %d."%(name, soutenance.assistant, soutenance.hour, soutenance.rank)) + elif soutenance.state == "Effectue": + return self.gen_response(req, "%s a passé sa soutenance avec %s. Elle a duré %s."%(name, soutenance.assistant, msg.just_countdown(soutenance.end - soutenance.start, 4))) + elif soutenance.state == "Retard": + return self.gen_response(req, "%s était en retard à sa soutenance de %s."%(name, soutenance.hour)) + else: + last = self.findLast() + if last is not None: + if soutenance.hour + (last.start - last.hour) > datetime.now (): + return self.gen_response(req, "Soutenance de %s : %s, position %d ; estimation du passage : dans %s."%(name, soutenance.hour, soutenance.rank, msg.just_countdown((soutenance.hour - datetime.now ()) + (last.start - last.hour)))) + else: + return self.gen_response(req, "Soutenance de %s : %s, position %d ; passage imminent."%(name, soutenance.hour, soutenance.rank)) + else: + return self.gen_response(req, "Soutenance de %s : %s, position %d."%(name, soutenance.hour, soutenance.rank)) + + def res_list(self, req): + name = req["user"] + + souts = self.findAll(name) + if souts is None: + self.gen_response(req, "Pas de soutenance prévues pour %s."%name) + else: + first = True + for s in souts: + if first: + self.gen_response(req, "Soutenance(s) de %s : - %s (position %d) ;"%(name, s.hour, s.rank)) + first = False + else: + self.gen_response(req, " %s - %s (position %d) ;"%(len(name)*' ', s.hour, s.rank)) + + def run(self): + self.parsePage(self.getPage().decode()) + res = list() + for u in self.datas.getNodes("request"): + res.append(self.res_soutenance(u)) + return res + + def needUpdate(self): + if self.findLast() is not None and datetime.now () - self.updated > timedelta(minutes=2): + return True + elif datetime.now () - self.updated < timedelta(hours=1): + return False + else: + return True + + def findAssistants(self): + h = dict() + 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 diff --git a/modules/soutenance/__init__.py b/modules/soutenance/__init__.py index 6ff8e10..28b981e 100644 --- a/modules/soutenance/__init__.py +++ b/modules/soutenance/__init__.py @@ -1,21 +1,15 @@ # coding=utf-8 -import http.client import time import re -import _thread import threading from datetime import date from datetime import datetime -from module_state import ModuleState - -from .SiteSoutenances import SiteSoutenances +from . import SiteSoutenances from .Delayed import Delayed -nemubotversion = 3.0 - -DELAYED = dict() +nemubotversion = 3.2 def help_tiny(): """Line inserted in the response to the command !help""" @@ -24,123 +18,32 @@ def help_tiny(): def help_full(): return "!soutenance: gives information about current defenses state\n!soutenance : gives the date of the next defense of /who/.\n!soutenances : gives all defense dates of /who/" -datas = None -THREAD = None -wait = list() +def load(context): + global CONF + SiteSoutenances.CONF = CONF -def parseanswer(msg): - global THREAD, wait - if msg.cmd[0] == "soutenance" or msg.cmd[0] == "soutenances": - if THREAD is None: - THREAD = _thread.start_new_thread (startSoutenance, (msg,)) +def ask_soutenance(msg): + req = ModuleState("request") + if len(msg.cmd) > 1: + req.setAttribute("user", msg.cmd[1]) else: - wait.append(msg) - return True - return False + req.setAttribute("user", "next") + req.setAttribute("server", msg.srv.id) + req.setAttribute("channel", msg.channel) + req.setAttribute("sender", msg.sender) + #An instance of this module is already running? + if not DATAS.hasAttribute("_running") or DATAS["_running"].needUpdate(): + DATAS.addChild(req) + site = SiteSoutenances.SiteSoutenances(DATAS) + DATAS.setAttribute("_running", site) -def parseask(msg): - if len(DELAYED) > 0 and msg.nick == 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 + res = site.run() + for n in DATAS.getNodes("request"): + DATAS.delChild(n) -def startSoutenance (msg): - global datas, THREAD, wait - - #Starts by updating datas - if datas is not None: - datas = datas.update () - if datas is None: - datas = SiteSoutenances(getPage().decode()) - - if len(msg.cmd) == 1 or msg.cmd[1] == "next": - soutenance = datas.findLast() - if soutenance is None: - msg.send_chn ("Il ne semble pas y avoir de soutenance pour le moment.") + return res else: - if soutenance.start > soutenance.hour: - avre = "%s de *retard*"%msg.just_countdown(soutenance.start - soutenance.hour, 4) - else: - avre = "%s *d'avance*"%msg.just_countdown(soutenance.hour - soutenance.start, 4) - msg.send_chn ("Actuellement à la soutenance numéro %d, commencée il y a %s avec %s."%(soutenance.rank, msg.just_countdown(datetime.now () - soutenance.start, 4), avre)) - - elif msg.cmd[1] == "assistants" or msg.cmd[1] == "assistant" or msg.cmd[1] == "yaka" or msg.cmd[1] == "yakas" or msg.cmd[1] == "acu" or msg.cmd[1] == "acus": - assistants = datas.findAssistants() - if len(assistants) > 0: - msg.send_chn ("Les %d assistants faisant passer les soutenances sont : %s." % (len(assistants), ', '.join(assistants.keys()))) - else: - msg.send_chn ("Il ne semble pas y avoir de soutenance pour le moment.") - else: - name = msg.cmd[1] - - if msg.cmd[0] == "soutenance": - soutenance = datas.findClose(name) - if soutenance is None: - global DELAYED - DELAYED[msg] = Delayed(name) - msg.srv.send_msg_prtn ("~whois %s" % name) - DELAYED[msg].wait(5) - if DELAYED[msg].res is not None: - name = DELAYED[msg].res - soutenance = datas.findClose(name) - - if soutenance is None: - msg.send_chn ("Pas d'horaire de soutenance pour %s."%name) - else: - if soutenance.state == "En cours": - msg.send_chn ("%s est actuellement en soutenance avec %s. Elle était prévue à %s, position %d."%(name, soutenance.assistant, soutenance.hour, soutenance.rank)) - elif soutenance.state == "Effectue": - msg.send_chn ("%s a passé sa soutenance avec %s. Elle a duré %s."%(name, soutenance.assistant, msg.just_countdown(soutenance.end - soutenance.start, 4))) - elif soutenance.state == "Retard": - msg.send_chn ("%s était en retard à sa soutenance de %s."%(name, soutenance.hour)) - else: - last = datas.findLast() - if last is not None: - if soutenance.hour + (last.start - last.hour) > datetime.now (): - msg.send_chn ("Soutenance de %s : %s, position %d ; estimation du passage : dans %s."%(name, soutenance.hour, soutenance.rank, msg.just_countdown((soutenance.hour - datetime.now ()) + (last.start - last.hour)))) - else: - msg.send_chn ("Soutenance de %s : %s, position %d ; passage imminent."%(name, soutenance.hour, soutenance.rank)) - else: - msg.send_chn ("Soutenance de %s : %s, position %d."%(name, soutenance.hour, soutenance.rank)) - - elif msg.cmd[0] == "soutenances": - souts = datas.findAll(name) - if souts is None: - msg.send_snd ("Pas de soutenance prévues pour %s."%name) - else: - first = True - for s in souts: - if first: - msg.send_snd ("Soutenance(s) de %s : - %s (position %d) ;"%(name, s.hour, s.rank)) - first = False - else: - msg.send_snd (" %s - %s (position %d) ;"%(len(name)*' ', s.hour, s.rank)) - THREAD = None - if len(wait) > 0: - startSoutenance(wait.pop()) - - -def getPage(): - conn = http.client.HTTPConnection(CONF.getNode("server")["ip"], timeout=10) - 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 + site = DATAS["_running"] + return site.res_soutenance(req)