From 061e73722fae958b634c78e920dccf4121891877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 30 Jun 2012 04:06:59 +0200 Subject: [PATCH] Oups, add a lot of missing files --- modules/events/Manager.py | 48 ++++++++++ modules/qcm/Course.py | 31 ++++++ modules/qcm/Question.py | 93 ++++++++++++++++++ modules/qcm/QuestionFile.py | 16 ++++ modules/qcm/Session.py | 68 ++++++++++++++ modules/qcm/User.py | 27 ++++++ modules/qd/DelayedTuple.py | 26 ++++++ modules/qd/GameUpdater.py | 59 ++++++++++++ modules/qd/QDWrapper.py | 20 ++++ modules/qd/Score.py | 126 +++++++++++++++++++++++++ modules/qd/__init__.py | 3 +- modules/soutenance/Delayed.py | 13 +++ modules/soutenance/SiteSoutenances.py | 88 +++++++++++++++++ modules/soutenance/Soutenance.py | 11 +++ modules/watchWebsite/Site.py | 130 ++++++++++++++++++++++++++ modules/watchWebsite/Watcher.py | 46 +++++++++ modules/whereis/Delayed.py | 5 + modules/whereis/UpdatedStorage.py | 57 +++++++++++ modules/whereis/User.py | 35 +++++++ modules/ycc/Tinyfier.py | 35 +++++++ prompt.py | 2 +- 21 files changed, 937 insertions(+), 2 deletions(-) create mode 100644 modules/events/Manager.py create mode 100644 modules/qcm/Course.py create mode 100644 modules/qcm/Question.py create mode 100644 modules/qcm/QuestionFile.py create mode 100644 modules/qcm/Session.py create mode 100644 modules/qcm/User.py create mode 100644 modules/qd/DelayedTuple.py create mode 100644 modules/qd/GameUpdater.py create mode 100644 modules/qd/QDWrapper.py create mode 100644 modules/qd/Score.py create mode 100644 modules/soutenance/Delayed.py create mode 100644 modules/soutenance/SiteSoutenances.py create mode 100644 modules/soutenance/Soutenance.py create mode 100644 modules/watchWebsite/Site.py create mode 100644 modules/watchWebsite/Watcher.py create mode 100644 modules/whereis/Delayed.py create mode 100644 modules/whereis/UpdatedStorage.py create mode 100644 modules/whereis/User.py create mode 100644 modules/ycc/Tinyfier.py diff --git a/modules/events/Manager.py b/modules/events/Manager.py new file mode 100644 index 0000000..d638d70 --- /dev/null +++ b/modules/events/Manager.py @@ -0,0 +1,48 @@ +# coding=utf-8 + +from datetime import datetime +import threading + +newStrendEvt = threading.Event() + +class Manager(threading.Thread): + def __init__(self, datas, srvs): + self.stop = False + self.DATAS = datas + self.SRVS = srvs + threading.Thread.__init__(self) + + def alertEnd(self, evt): + global newStrendEvt + #Send the message on each matched servers + for server in self.SRVS.keys(): + if not evt.hasAttribute("server") or server == evt["server"]: + if evt["channel"] == self.SRVS[server].nick: + self.SRVS[server].send_msg_usr(evt["proprio"], "%s: %s arrivé à échéance." % (evt["proprio"], evt["name"])) + else: + self.SRVS[server].send_msg(evt["channel"], "%s: %s arrivé à échéance." % (evt["proprio"], evt["name"])) + self.DATAS.delChild(self.DATAS.index[evt["name"]]) + save() + newStrendEvt.set() + + def run(self): + global newStrendEvt + while not self.stop: + newStrendEvt.clear() + closer = None + #Gets the closer event + for evt in self.DATAS.index.keys(): + if self.DATAS.index[evt].hasAttribute("end") and (closer is None or self.DATAS.index[evt].getDate("end") < closer.getDate("end")) and self.DATAS.index[evt].getDate("end") > datetime.now(): + closer = self.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 diff --git a/modules/qcm/Course.py b/modules/qcm/Course.py new file mode 100644 index 0000000..9cddf1a --- /dev/null +++ b/modules/qcm/Course.py @@ -0,0 +1,31 @@ +# coding=utf-8 + +COURSES = 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 diff --git a/modules/qcm/Question.py b/modules/qcm/Question.py new file mode 100644 index 0000000..8e4c389 --- /dev/null +++ b/modules/qcm/Question.py @@ -0,0 +1,93 @@ +# coding=utf-8 + +from datetime import datetime +import hashlib +import http.client +import socket +from urllib.parse import quote + +from .Course import Course +from .User import User + +QUESTIONS = None + +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 diff --git a/modules/qcm/QuestionFile.py b/modules/qcm/QuestionFile.py new file mode 100644 index 0000000..48ed23f --- /dev/null +++ b/modules/qcm/QuestionFile.py @@ -0,0 +1,16 @@ +# coding=utf-8 + +import module_states_file as xmlparser + +from .Question import Question + +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 diff --git a/modules/qcm/Session.py b/modules/qcm/Session.py new file mode 100644 index 0000000..54898d0 --- /dev/null +++ b/modules/qcm/Session.py @@ -0,0 +1,68 @@ +# coding=utf-8 + +import threading + +SESSIONS = dict() + +from . import Question + +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): + return Question.Question(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 == self.server.nick: + 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 == self.server.nick: + 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() + diff --git a/modules/qcm/User.py b/modules/qcm/User.py new file mode 100644 index 0000000..5f18831 --- /dev/null +++ b/modules/qcm/User.py @@ -0,0 +1,27 @@ +# coding=utf-8 + +USERS = None + +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 diff --git a/modules/qd/DelayedTuple.py b/modules/qd/DelayedTuple.py new file mode 100644 index 0000000..becd363 --- /dev/null +++ b/modules/qd/DelayedTuple.py @@ -0,0 +1,26 @@ +# coding=utf-8 + +import re +import threading + +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) diff --git a/modules/qd/GameUpdater.py b/modules/qd/GameUpdater.py new file mode 100644 index 0000000..12c4e9c --- /dev/null +++ b/modules/qd/GameUpdater.py @@ -0,0 +1,59 @@ +# coding=utf-8 + +from datetime import datetime +import random +import threading +from .DelayedTuple import DelayedTuple + +DELAYED = dict() + +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() diff --git a/modules/qd/QDWrapper.py b/modules/qd/QDWrapper.py new file mode 100644 index 0000000..d3516d8 --- /dev/null +++ b/modules/qd/QDWrapper.py @@ -0,0 +1,20 @@ +# coding=utf-8 + +from wrapper import Wrapper +from .Score import Score + +class QDWrapper(Wrapper): + def __init__(self, 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 diff --git a/modules/qd/Score.py b/modules/qd/Score.py new file mode 100644 index 0000000..52c5692 --- /dev/null +++ b/modules/qd/Score.py @@ -0,0 +1,126 @@ +# coding=utf-8 + +from datetime import datetime + +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): + now = datetime.now() + ret = self.last == None or self.last.minute != now.minute or self.last.hour != now.hour or self.last.day != 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()) diff --git a/modules/qd/__init__.py b/modules/qd/__init__.py index 7550013..0b6dacf 100644 --- a/modules/qd/__init__.py +++ b/modules/qd/__init__.py @@ -6,6 +6,7 @@ from datetime import datetime nemubotversion = 3.0 from . import GameUpdater +from .QDWrapper import QDWrapper channels = "#nemutest #42sh #ykar #epitagueule" LASTSEEN = dict () @@ -210,7 +211,7 @@ def parselisten (msg): win(msg) return True elif getUser(msg.sender).hasChanged(): - gu = GameUpdater(msg, bfrseen) + gu = GameUpdater.GameUpdater(msg, bfrseen) gu.start() return True return False diff --git a/modules/soutenance/Delayed.py b/modules/soutenance/Delayed.py new file mode 100644 index 0000000..8cf47c5 --- /dev/null +++ b/modules/soutenance/Delayed.py @@ -0,0 +1,13 @@ +# coding=utf-8 + +import threading + +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) diff --git a/modules/soutenance/SiteSoutenances.py b/modules/soutenance/SiteSoutenances.py new file mode 100644 index 0000000..ffbc30e --- /dev/null +++ b/modules/soutenance/SiteSoutenances.py @@ -0,0 +1,88 @@ +# coding=utf-8 + +from datetime import datetime +from datetime import timedelta +import re +import time + +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: + 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 + + 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 diff --git a/modules/soutenance/Soutenance.py b/modules/soutenance/Soutenance.py new file mode 100644 index 0000000..e2a0882 --- /dev/null +++ b/modules/soutenance/Soutenance.py @@ -0,0 +1,11 @@ +# coding=utf-8 + +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 diff --git a/modules/watchWebsite/Site.py b/modules/watchWebsite/Site.py new file mode 100644 index 0000000..85e4c87 --- /dev/null +++ b/modules/watchWebsite/Site.py @@ -0,0 +1,130 @@ +# coding=utf-8 + +from datetime import datetime +from datetime import timedelta +import http.client +import hashlib +import socket +import sys +import traceback +from urllib.parse import unquote + +from .atom import Atom + +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(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: + print ("[%s] impossible de récupérer la page %s."%(s, p)) + return (None, None) + + conn.close() + return (res.status, data) diff --git a/modules/watchWebsite/Watcher.py b/modules/watchWebsite/Watcher.py new file mode 100644 index 0000000..bc77192 --- /dev/null +++ b/modules/watchWebsite/Watcher.py @@ -0,0 +1,46 @@ +# coding=utf-8 + +from datetime import datetime +import threading + +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() diff --git a/modules/whereis/Delayed.py b/modules/whereis/Delayed.py new file mode 100644 index 0000000..45826f4 --- /dev/null +++ b/modules/whereis/Delayed.py @@ -0,0 +1,5 @@ +# coding=utf-8 + +class Delayed: + def __init__(self): + self.names = dict() diff --git a/modules/whereis/UpdatedStorage.py b/modules/whereis/UpdatedStorage.py new file mode 100644 index 0000000..de09848 --- /dev/null +++ b/modules/whereis/UpdatedStorage.py @@ -0,0 +1,57 @@ +# coding=utf-8 + +import socket +from datetime import datetime +from datetime import timedelta + +from .User import User + +class UpdatedStorage: + def __init__(self, url, port): + sock = connect_to_ns(url, 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 + + +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 diff --git a/modules/whereis/User.py b/modules/whereis/User.py new file mode 100644 index 0000000..d4b48b4 --- /dev/null +++ b/modules/whereis/User.py @@ -0,0 +1,35 @@ +# coding=utf-8 + +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) diff --git a/modules/ycc/Tinyfier.py b/modules/ycc/Tinyfier.py new file mode 100644 index 0000000..dad382a --- /dev/null +++ b/modules/ycc/Tinyfier.py @@ -0,0 +1,35 @@ +# coding=utf-8 + +import threading + +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 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) diff --git a/prompt.py b/prompt.py index b29d01a..546588a 100644 --- a/prompt.py +++ b/prompt.py @@ -99,7 +99,7 @@ def mod_save(mod, datas_path): def mod_has_access(mod, config, msg): if config is not None and config.hasNode("channel"): - for chan in config.getChilds("channel"): + for chan in config.getNodes("channel"): if (chan["server"] is None or chan["server"] == msg.srv.id) and (chan["channel"] is None or chan["channel"] == msg.channel): return True return False