]> gitweb.pimeys.fr Git - bots/hung.git/blob - hung.py
Fail float/int + compter le bonus qu'on annonce, c'est mieux
[bots/hung.git] / hung.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 le 23/04/12
5
6 # Un bot IRC qui joue au pendu
7
8 import threading
9 import random
10 import time
11 import socket, ssl, json
12 import pickle
13 import re
14 import os
15 import signal
16 import sys
17 from commands import getstatusoutput as ex
18
19 # Oui, j'ai recodé ma version d'irclib pour pouvoir rattrapper les SIGHUP
20 sys.path.insert(0, "/home/vincent/scripts/python-myirclib")
21 import irclib
22 import ircbot
23
24 import sys
25
26 # Fichier de conf
27 import config
28
29 def get_config_logfile(serveur):
30 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans","localhost":"localhost"}
31 return config.logfile_template%(serveurs[serveur])
32
33 def log(serveur,channel,auteur=None,message=None):
34 f=open(get_config_logfile(serveur),"a")
35 if auteur == message == None:
36 # alors c'est que c'est pas un channel mais juste une ligne de log
37 chain="%s %s"%(time.strftime("%F %T"),channel)
38 else:
39 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
40 f.write(chain+"\n")
41 if config.debug_stdout:
42 print chain
43 f.close()
44
45 def ignore_event(serv, ev):
46 """Retourne ``True`` si il faut ignorer cet évènement."""
47 for (blackmask, exceptmask) in config.blacklisted_masks:
48 usermask = ev.source()
49 if exceptmask is None:
50 exceptit = False
51 else:
52 exceptit = bool(irclib.mask_matches(usermask, exceptmask))
53 blackit = bool(irclib.mask_matches(usermask, blackmask))
54 if blackit and not exceptit:
55 return True
56
57 class UnicodeBotError(Exception):
58 pass
59 def bot_unicode(chain):
60 try:
61 unicode(chain,"utf8")
62 except UnicodeDecodeError as exc:
63 raise UnicodeBotError
64
65 def remplace_accents(chaine):
66 chaine=chaine.lower()
67 remplacements = {u"á":u"a",u"à":u"a",u"â":u"a",u"ä":u"a",u"é":u"e",u"è":u"e",u"ê":u"e",u"ë":u"e",u"í":u"i",u"ì":u"i",u"î":u"i",u"ï":u"i",u"ó":u"o", u"ò":u"o",u"ô":u"o",u"ö":u"o",u"ú":u"u",u"ù":u"u",u"û":u"u",u"ü":u"u",u"ý":u"y",u"ỳ":u"y",u"ŷ":u"y",u"ÿ":u"y",u"œ":u"oe",u"æ":u"ae"}
68 for avant,apres in remplacements.items():
69 chaine=chaine.replace(avant,apres)
70 return chaine
71
72 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
73 if case_sensitive:
74 chain=unicode(chain,"utf8")
75 else:
76 chain=unicode(chain,"utf8").lower()
77 allmatches="("+"|".join(matches)+")"
78 reg=(avant+allmatches+apres).lower()
79 o=re.match(reg,chain)
80 return o
81
82 def is_tag(chain):
83 return is_something(chain,config.tag_triggers)
84
85 def is_mot(mot,liste):
86 real_word = "".join([lettre[0] for lettre in liste])
87 real_word = real_word.decode("utf8").lower()
88 mot=remplace_accents(mot.decode("utf8"))
89 return mot.startswith(real_word)
90
91 class Hung(ircbot.SingleServerIRCBot):
92 def __init__(self,serveur,debug=False):
93 temporary_pseudo=config.irc_pseudo+str(random.randrange(10000,100000))
94 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
95 temporary_pseudo,"Bot irc pour jouer au pendu", 10)
96 self.debug=debug
97 self.serveur=serveur
98 self.overops=config.overops
99 self.ops=self.overops+config.ops
100 self.report_bugs_to=config.report_bugs_to
101 self.chanlist=config.chanlist
102 self.stay_channels=config.stay_channels
103 self.play_channels=config.play_channels
104 self.play_status={i:[None,None,None] for i in self.play_channels}
105 self.lives={}
106 self.tried_letters={}
107 self.quiet_channels=config.quiet_channels
108
109
110 def give_me_my_pseudo(self,serv):
111 serv.privmsg("NickServ","RECOVER %s %s"%(config.irc_pseudo,config.irc_password))
112 serv.privmsg("NickServ","RELEASE %s %s"%(config.irc_pseudo,config.irc_password))
113 time.sleep(0.3)
114 serv.nick(config.irc_pseudo)
115
116 def on_welcome(self, serv, ev):
117 self.serv=serv # ça serv ira :)
118 self.give_me_my_pseudo(serv)
119 serv.privmsg("NickServ","IDENTIFY %s"%(config.irc_password))
120 log(self.serveur,"Connected")
121 if self.debug:
122 self.chanlist=["#bot"]
123 self.play_channels=["#bot"]
124 for c in self.chanlist:
125 log(self.serveur,"JOIN %s"%(c))
126 serv.join(c)
127
128 def pourmoi(self, serv, message):
129 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
130 pseudo=serv.get_nickname()
131 size=len(pseudo)
132 if message[:size]==pseudo and len(message)>size and message[size]==":":
133 return (True,message[size+1:].lstrip(" "))
134 else:
135 return (False,message)
136
137 def on_privmsg(self, serv, ev):
138 if ignore_event(serv, ev):
139 return
140 message=ev.arguments()[0]
141 auteur = irclib.nm_to_n(ev.source())
142 try:
143 test=bot_unicode(message)
144 except UnicodeBotError:
145 if config.utf8_trigger:
146 serv.privmsg(auteur, random.choice(config.utf8_fail_answers).encode("utf8"))
147 return
148 message=message.split()
149 cmd=message[0].lower()
150 notunderstood=False
151 if cmd=="help":
152 helpmsg_default="""Liste des commandes :
153 HELP Affiche ce message d'aide
154 SCORE Affiche ton score
155 SCORES Affiche les scores"""
156 helpmsg_ops="""
157 JOIN Faire rejoindre un channel (sans paramètres, donne la liste des chans actuels)
158 LEAVE Faire quitter un channel
159 PLAY Passe un channel en mode "jouer"
160 NOPLAY Passe un channel en mode "ne pas jouer"
161 QUIET Se taire sur un channel
162 NOQUIET Opposé de QUIET
163 RELOAD Recharge la config"""
164 helpmsg_overops="""
165 SAY Fais envoyer un message sur un chan ou à une personne
166 DO Me fait faire une action sur un chan
167 STAY Ignorera les prochains LEAVE pour un chan
168 NOSTAY Opposé de STAY
169 STATUS Montre l'état courant
170 DIE Mourir"""
171 helpmsg=helpmsg_default
172 if auteur in self.ops:
173 helpmsg+=helpmsg_ops
174 if auteur in self.overops:
175 helpmsg+=helpmsg_overops
176 for ligne in helpmsg.split("\n"):
177 serv.privmsg(auteur,ligne)
178 elif cmd=="join":
179 if auteur in self.ops:
180 if len(message)>1:
181 if message[1] in self.chanlist:
182 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
183 else:
184 serv.join(message[1])
185 self.chanlist.append(message[1])
186 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
187 log(self.serveur,"priv",auteur," ".join(message))
188 else:
189 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
190 else:
191 notunderstood=True
192 elif cmd=="leave":
193 if auteur in self.ops and len(message)>1:
194 if message[1] in self.chanlist:
195 if not (message[1] in self.stay_channels) or auteur in self.overops:
196 self.quitter(message[1]," ".join(message[2:]))
197 self.chanlist.remove(message[1])
198 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
199 else:
200 serv.privmsg(auteur,"Non, je reste !")
201 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
202 else:
203 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
204 else:
205 notunderstood=True
206 elif cmd=="play":
207 if auteur in self.ops:
208 if len(message)>1:
209 if message[1] in self.play_channels:
210 if len(message) > 2:
211 self.start_partie(serv, message[1], " ".join(message[2:]))
212 else:
213 serv.privmsg(auteur,"Je play déjà sur %s."%(message[1]))
214 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
215 else:
216 self.play_channels.append(message[1])
217 self.play_status[message[1]]=[None,None,None]
218 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
219 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
220 else:
221 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
222 else:
223 notunderstood=True
224 elif cmd=="noplay":
225 if auteur in self.ops:
226 if len(message)>1:
227 if message[1] in self.play_channels:
228 self.play_channels.remove(message[1])
229 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
230 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
231 else:
232 serv.privmsg(auteur,"Je ne play pas sur %s."%(message[1]))
233 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
234 else:
235 notunderstood=True
236 elif cmd=="stay":
237 if auteur in self.overops:
238 if len(message)>1:
239 if message[1] in self.stay_channels:
240 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
241 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
242 else:
243 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
244 self.stay_channels.append(message[1])
245 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
246 else:
247 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
248 else:
249 notunderstood=True
250 elif cmd=="nostay":
251 if auteur in self.overops:
252 if len(message)>1:
253 if message[1] in self.stay_channels:
254 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
255 self.stay_channels.remove(message[1])
256 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
257 else:
258 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
259 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
260
261 else:
262 notunderstood=True
263 elif cmd in ["states","status"]:
264 if auteur in self.overops:
265 for k in self.play_status.keys():
266 if self.play_status[k]==[None,None,None]:
267 serv.privmsg(auteur,"None")
268 else:
269 serv.privmsg(auteur,"%s : %s (%s) [%s]"%(k,"".join([str(i[0]) for i in self.play_status[k][0]])
270 ,self.play_status[k][1], self.play_status[k][2]))
271 elif cmd=="die":
272 if auteur in self.overops:
273 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
274 self.mourir()
275 else:
276 notunderstood=True
277 elif cmd=="quiet":
278 if auteur in self.ops:
279 if len(message)>1:
280 if message[1] in self.quiet_channels:
281 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
282 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
283 else:
284 self.quiet_channels.append(message[1])
285 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
286 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
287 else:
288 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
289 else:
290 notunderstood=True
291 elif cmd=="noquiet":
292 if auteur in self.ops:
293 if len(message)>1:
294 if message[1] in self.quiet_channels:
295 self.quiet_channels.remove(message[1])
296 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
297 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
298 else:
299 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
300 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
301 else:
302 notunderstood=True
303 elif cmd=="reload":
304 if auteur in self.ops:
305 self.reload(auteur)
306 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
307 else:
308 notunderstood=True
309 elif cmd=="say":
310 if auteur in self.overops and len(message)>2:
311 serv.privmsg(message[1]," ".join(message[2:]))
312 log(self.serveur,"priv",auteur," ".join(message))
313 elif len(message)<=2:
314 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
315 else:
316 notunderstood=True
317 elif cmd=="do":
318 if auteur in self.overops and len(message)>2:
319 serv.action(message[1]," ".join(message[2:]))
320 log(self.serveur,"priv",auteur," ".join(message))
321 elif len(message)<=2:
322 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
323 else:
324 notunderstood=True
325 elif cmd in ["score","scores"]:
326 self.send_scores(serv,auteur)
327 else:
328 notunderstood=True
329 if notunderstood:
330 serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
331
332 def affiche_mot(self, serv, canal, begin="Mot courant"):
333 if self.play_status.has_key(canal):
334 mot = self.play_status[canal][0]
335 obfuskated=" ".join([lettre[0] if lettre[1] else "_" for lettre in mot])
336 serv.privmsg(canal,"%s : %s"%(begin,obfuskated))
337
338 def start_partie(self, serv, canal, mot=None):
339 if mot is None:
340 mots=[mot.strip() for mot in open(config.dico_mots).readlines()]
341 defs=[defi.strip() for defi in open(config.dico_defs).readlines()]
342 indice = random.randrange(0,len(mots))
343 mot,definition=mots[indice],defs[indice]
344 else:
345 definition = "(custom word)"
346 # ' et - sont considérés comme déjà devinés
347 mot = mot.upper()
348 mot = [(lettre,lettre in config.non_guess_chars) for lettre in list(mot)]
349 self.play_status[canal]=[mot,definition,{}]
350 self.tried_letters[canal] = set ()
351 self.lives[canal] = config.lives
352 self.affiche_mot(serv, canal, begin="Devinez")
353
354 def on_pubmsg(self, serv, ev):
355 if ignore_event(serv, ev):
356 return
357 auteur = irclib.nm_to_n(ev.source())
358 canal = ev.target()
359 message = ev.arguments()[0]
360 try:
361 test=bot_unicode(message)
362 except UnicodeBotError:
363 if config.utf8_trigger and not canal in self.quiet_channels:
364 serv.privmsg(canal, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
365 return
366 pour_moi,message=self.pourmoi(serv,message)
367 if pour_moi and message.split()!=[]:
368 cmd=message.split()[0].lower()
369 try:
370 args=" ".join(message.split()[1:])
371 except:
372 args=""
373 if cmd in ["meurs","die","crève"]:
374 if auteur in self.overops:
375 log(self.serveur,canal,auteur,message+"[successful]")
376 self.mourir()
377 else:
378 serv.privmsg(canal,"%s: crève !"%(auteur))
379 log(self.serveur,canal,auteur,message+"[failed]")
380 elif cmd == "reload":
381 if auteur in self.ops:
382 log(self.serveur, canal, auteur, message+"[successful]")
383 self.reload(canal)
384 elif cmd in ["part","leave","dégage"]:
385 if auteur in self.ops and (not (canal in self.stay_channels)
386 or auteur in self.overops):
387 self.quitter(canal)
388 log(self.serveur,canal,auteur,message+"[successful]")
389 if canal in self.chanlist:
390 self.chanlist.remove(canal)
391 else:
392 serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
393 log(self.serveur,canal,auteur,message+"[failed]")
394 elif cmd in ["play","jeu","encore","again","partie","pendu","game","mot","go","allez"]:
395 if not canal in self.quiet_channels and canal in self.play_channels:
396 if self.play_status.has_key(canal):
397 if self.play_status[canal]==[None,None,None]:
398 self.start_partie(serv, canal)
399 else:
400 self.affiche_mot(serv, canal, begin="%s: Rappel"%(auteur))
401 else:
402 self.play_status[canal]=[None,None,None]
403 self.start_partie(serv, canal)
404 elif not canal in self.play_channels:
405 serv.privmsg(canal,"%s: pas ici…"%(auteur))
406 elif cmd in ["score","scores","!score","!scores"]:
407 self.send_scores(serv,auteur)
408 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
409 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
410 if is_tag(message) and not canal in self.quiet_channels:
411 if auteur in self.ops:
412 action=random.choice(config.tag_actions)
413 serv.action(canal,action.encode("utf8"))
414 self.quiet_channels.append(canal)
415 else:
416 answer=random.choice(config.tag_answers)
417 for ligne in answer.split("\n"):
418 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
419 # on essaye de voir si le mot fourni matche la partie en cours
420 mot = message
421 if canal in self.play_channels and self.play_status[canal][0]!=None and is_mot(mot, self.play_status[canal][0]):
422 # on a trouvé le mot
423 # on regarde combien de lettre il manquait
424 manquait = sum([not lettre[1] for lettre in self.play_status[canal][0]])
425 self.add_score({auteur: manquait})
426 if self.play_status[canal][2].has_key(auteur):
427 self.play_status[canal][2][auteur]+=manquait
428 else:
429 self.play_status[canal][2][auteur]=manquait
430 self.gagne(serv, canal, bonus=auteur, bonusvalue=manquait)
431 return
432 elif (cmd in list("azertyuiopqsdfghjklmwxcvbn") and canal in self.play_channels
433 and self.play_status.has_key(canal) and self.play_status[canal]!=[None,None,None]):
434 giv_let=cmd.upper()
435 liste=self.play_status[canal][0]
436 listeapres=[(lettre[0],lettre[1] or lettre[0]==giv_let) for lettre in liste]
437 if liste!=listeapres:
438 nbtrouvees=(sum([lettre[1] for lettre in listeapres if not lettre[0] in "'-()"])
439 - sum([lettre[1] for lettre in liste if not lettre[0] in "'-()"]))
440 if self.play_status[canal][2].has_key(auteur):
441 self.play_status[canal][2][auteur]+= nbtrouvees
442 else:
443 self.play_status[canal][2][auteur] = nbtrouvees
444 self.play_status[canal][0]=listeapres
445 self.affiche_mot(serv, canal, begin="%s placé"%(giv_let))
446 else:
447 if not giv_let in self.tried_letters[canal]:
448 # On perd une chance
449 self.lives[canal] -= 1
450 if self.lives[canal] > 0:
451 serv.privmsg(canal, "Pas de %s. Plus que %s chance%s…" % (giv_let, self.lives[canal], "s" * (self.lives[canal] > 1)))
452 if self.lives[canal] == 0:
453 serv.privmsg(canal, "Pas de %s." % (giv_let))
454 self.perd(serv, canal)
455 return
456 self.tried_letters[canal].add(giv_let)
457 if all([lettre[1] for lettre in listeapres]):
458 self.gagne(serv, canal)
459
460 else:
461 pass
462
463
464 def on_action(self, serv, ev):
465 if ignore_event(serv, ev):
466 return
467 action = ev.arguments()[0]
468 auteur = irclib.nm_to_n(ev.source())
469 channel = ev.target()
470
471
472 def on_kick(self,serv,ev):
473 auteur = irclib.nm_to_n(ev.source())
474 channel = ev.target()
475 victime = ev.arguments()[0]
476 raison = ev.arguments()[1]
477 if victime==self.nick:
478 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
479 time.sleep(5)
480 serv.join(channel)
481 # on ne dit rien au rejoin
482 #l1,l2=config.kick_answers,config.kick_actions
483 #n1,n2=len(l1),len(l2)
484 #i=random.randrange(n1+n2)
485 #if i>=n1:
486 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
487 #else:
488 # serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
489
490 def _getnick(self):
491 return self.serv.get_nickname()
492 nick = property(_getnick)
493
494 def quitter(self,chan,leave_message=None):
495 if leave_message==None:
496 leave_message=random.choice(config.leave_messages)
497 self.serv.part(chan,message=leave_message.encode("utf8"))
498
499 def mourir(self):
500 quit_message=random.choice(config.quit_messages)
501 self.die(msg=quit_message.encode("utf8"))
502
503 def get_scores(self):
504 f=open(config.scores_file)
505 scores=pickle.load(f)
506 f.close()
507 return scores
508 def save_scores(self,scores):
509 f=open(config.scores_file,'w')
510 pickle.dump(scores,f)
511 f.close()
512 def add_score(self,dico):
513 scores=self.get_scores()
514 for k,v in dico.items():
515 if scores.has_key(k):
516 scores[k]+=v
517 else:
518 scores[k]=v
519 self.save_scores(scores)
520 def send_scores(self, serv, destinataire):
521 scores=self.get_scores()
522 scores=scores.items()
523 scores.sort(lambda x,y:cmp(x[1],y[1]))
524 scores.reverse()
525 serv.privmsg(destinataire,"Scores by score : "+" ; ".join(["%s %s"%(k,v) for (k,v) in scores]) )
526 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
527 serv.privmsg(destinataire,"Scores by pseudo : "+" ; ".join(["%s %s"%(k,v) for (k,v) in scores]) )
528
529 def gagne(self, serv, canal, bonus=None, bonusvalue=2):
530 serv.privmsg(canal,"Bravo !")
531 realword = self.reveal_word(serv, canal)
532 nlettre=float(len([l for l in realword if not l in config.non_guess_chars]))
533 contribs=["%s:%s%%%s"%(pseudo,str(int(100*contrib/nlettre)),("+bonus(%s)"%(bonusvalue))*(bonus==pseudo)) for pseudo,contrib in self.play_status[canal][2].items()]
534 contribs_score={pseudo:int(10.0*contrib/nlettre)+(bonusvalue*(bonus==pseudo)) for pseudo,contrib in self.play_status[canal][2].items()}
535 self.add_score(contribs_score)
536 serv.privmsg(canal,"Contributions : %s"%(" ".join(contribs)) )
537 self.play_status[canal]=[None,None,None]
538
539 def reveal_word(self, serv, canal):
540 realword="".join([lettre[0] for lettre in self.play_status[canal][0]])
541 serv.privmsg(canal, "C'était %s." % (realword))
542 definition = self.play_status[canal][1]
543 serv.privmsg(canal,definition)
544 return realword
545
546 def perd(self, serv, canal):
547 serv.privmsg(canal,"Pendu !")
548 self.reveal_word(serv, canal)
549 self.play_status[canal]=[None,None,None]
550
551 def reload(self, auteur=None):
552 reload(config)
553 if auteur in [None, "SIGHUP"]:
554 towrite = "Config reloaded" + " (SIGHUP received)"*(auteur == "SIGHUP")
555 for to in config.report_bugs_to:
556 self.serv.privmsg(to, towrite)
557 log(self.serveur, towrite)
558 else:
559 self.serv.privmsg(auteur,"Config reloaded")
560
561 def start_as_daemon(self, outfile):
562 sys.stderr = Logger(outfile)
563 self.start()
564
565
566 class Logger(object):
567 """Pour écrire ailleurs que sur stdout"""
568 def __init__(self, filename="hung.full.log"):
569 self.filename = filename
570
571 def write(self, message):
572 f = open(self.filename, "a")
573 f.write(message)
574 f.close()
575
576
577 if __name__=="__main__":
578 import sys
579 if len(sys.argv)==1:
580 print "Usage : hung.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
581 print " --outfile sans --no-output ni --daemon n'a aucun effet"
582 exit(1)
583 serveur=sys.argv[1]
584 if "--daemon" in sys.argv:
585 thisfile = os.path.realpath(__file__)
586 thisdirectory = thisfile.rsplit("/", 1)[0]
587 os.chdir(thisdirectory)
588 daemon = True
589 else:
590 daemon = False
591 if "debug" in sys.argv or "--debug" in sys.argv:
592 debug=True
593 else:
594 debug=False
595 if "--no-output" in sys.argv or "--daemon" in sys.argv:
596 outfile = "/var/log/bots/hung.full.log"
597 for arg in sys.argv:
598 arg = arg.split("=")
599 if arg[0].strip('-') in ["out", "outfile", "logfile"]:
600 outfile = arg[1]
601 sys.stdout = Logger(outfile)
602 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
603 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org",
604 "localhost":"localhost"}
605 try:
606 serveur=serveurs[serveur]
607 except KeyError:
608 print "Server Unknown : %s"%(serveur)
609 exit(404)
610 hung=Hung(serveur,debug)
611 # Si on reçoit un SIGHUP, on reload la config
612 def sighup_handler(signum, frame):
613 hung.reload("SIGHUP")
614 signal.signal(signal.SIGHUP, sighup_handler)
615 if daemon:
616 child_pid = os.fork()
617 if child_pid == 0:
618 os.setsid()
619 hung.start_as_daemon(outfile)
620 else:
621 # on enregistre le pid de hung
622 pidfile = "/var/run/bots/hung.pid"
623 for arg in sys.argv:
624 arg = arg.split("=")
625 if arg[0].strip('-') in ["pidfile"]:
626 pidfile = arg[1]
627 f = open(pidfile, "w")
628 f.write("%s\n" % child_pid)
629 f.close()
630 else:
631 hung.start()
632