From 5336a4b79530dca50d29060a9dfe07f44d5e58a4 Mon Sep 17 00:00:00 2001 From: jcao219 Date: Sun, 17 Jul 2011 20:30:26 -0500 Subject: [PATCH] full threading for the reaper function --- decorators.py | 1 - oyoyo/client.py | 51 +++++++------- oyoyo/ircevents.py | 4 +- oyoyo/parse.py | 2 +- var.py | 4 +- wolfgame.py | 168 ++++++++++++++++++++++----------------------- 6 files changed, 113 insertions(+), 117 deletions(-) diff --git a/decorators.py b/decorators.py index 87b5cc2..08a8130 100644 --- a/decorators.py +++ b/decorators.py @@ -35,7 +35,6 @@ def generate(fdict, **kwargs): if (fn.owner_only != owner_only or fn.admin_only != admin_only): raise Exception("Command: "+x+" has non-matching protection levels!") - fdict[x].append(innerf) innerf.owner_only = owner_only innerf.raw_nick = raw_nick diff --git a/oyoyo/client.py b/oyoyo/client.py index f34cb78..2d7545c 100644 --- a/oyoyo/client.py +++ b/oyoyo/client.py @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Duncan Fordyce +# Copyright (c) 2011 Duncan Fordyce, Jimmy Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights @@ -18,11 +18,11 @@ import logging import socket import time +import threading +import traceback from oyoyo.parse import parse_raw_irc_command -class IRCClientError(Exception): - pass # Adapted from http://code.activestate.com/recipes/511490-implementation-of-the-token-bucket-algorithm/ @@ -107,6 +107,7 @@ class IRCClient(object): self.port = None self.connect_cb = None self.blocking = True + self.lock = threading.RLock() self.tokenbucket = TokenBucket(3, 1.63) self.__dict__.update(kwargs) @@ -128,25 +129,26 @@ class IRCClient(object): str they will be converted to bytes with the encoding specified by the 'encoding' keyword argument (default 'utf8'). """ - # Convert all args to bytes if not already - encoding = kwargs.get('encoding') or 'utf_8' - bargs = [] - for i,arg in enumerate(args): - if isinstance(arg, str): - bargs.append(bytes(arg, encoding)) - elif isinstance(arg, bytes): - bargs.append(arg) - elif arg is None: - continue - else: - raise Exception(('Refusing to send arg at index {1} of the args from '+ - 'provided: {0}').format(repr([(type(arg), arg) - for arg in args]), i)) - - msg = bytes(" ", "utf_8").join(bargs) - logging.info('---> send "{0}"'.format(msg)) - - self.socket.send(msg + bytes("\r\n", "utf_8")) + with self.lock: + # Convert all args to bytes if not already + encoding = kwargs.get('encoding') or 'utf_8' + bargs = [] + for i,arg in enumerate(args): + if isinstance(arg, str): + bargs.append(bytes(arg, encoding)) + elif isinstance(arg, bytes): + bargs.append(arg) + elif arg is None: + continue + else: + raise Exception(('Refusing to send arg at index {1} of the args from '+ + 'provided: {0}').format(repr([(type(arg), arg) + for arg in args]), i)) + + msg = bytes(" ", "utf_8").join(bargs) + logging.info('---> send "{0}"'.format(msg)) + + self.socket.send(msg + bytes("\r\n", "utf_8")) def connect(self): """ initiates the connection to the server set in self.host:self.port @@ -214,9 +216,8 @@ class IRCClient(object): self.command_handler[command](self, prefix,*largs) elif "" in self.command_handler: self.command_handler[""](self, prefix, command, *largs) - finally: - # error will of already been logged by the handler - pass + except Exception as e: + traceback.print_exc() yield True finally: diff --git a/oyoyo/ircevents.py b/oyoyo/ircevents.py index 3faecf5..8bacbef 100644 --- a/oyoyo/ircevents.py +++ b/oyoyo/ircevents.py @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Duncan Fordyce +# Copyright (c) 2011 Duncan Fordyce, Jimmy Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights @@ -15,8 +15,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -# taken from python irclib.. who took it from... -# Numeric table mostly stolen from the Perl IRC module (Net::IRC). numeric_events = { b"001": "welcome", b"002": "yourhost", diff --git a/oyoyo/parse.py b/oyoyo/parse.py index 2121e19..57cd13a 100644 --- a/oyoyo/parse.py +++ b/oyoyo/parse.py @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Duncan Fordyce +# Copyright (c) 2011 Duncan Fordyce, Jimmy Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights diff --git a/var.py b/var.py index 5e16b5f..8e7c4db 100644 --- a/var.py +++ b/var.py @@ -8,8 +8,8 @@ DRUNK_SHOTS_MULTIPLIER = 3 NIGHT_TIME_LIMIT = 90 DAY_TIME_LIMIT = 333 START_WITH_DAY = False -KILL_IDLE_TIME = 0 #300 -WARN_IDLE_TIME = 0 #180 +KILL_IDLE_TIME = 300 +WARN_IDLE_TIME = 180 GAME_COMMAND_ADMIN_ONLY = True # HIT MISS SUICIDE diff --git a/wolfgame.py b/wolfgame.py index 3b8c8ed..3865167 100644 --- a/wolfgame.py +++ b/wolfgame.py @@ -69,8 +69,7 @@ def connect_callback(cli): var.LAST_SAID_TIME = {} var.GAME_START_TIME = datetime.now() # for idle checker only - var.GRAVEYARD = [] - var.GRAVEYARD_LOCK = threading.Lock() + var.GRAVEYARD_LOCK = threading.RLock() prepare_stuff() @@ -111,6 +110,7 @@ def reset(cli): if var.TIMERS[1]: var.TIMERS[1].cancel() var.TIMERS[1] = None + var.GAME_ID = 0 cli.mode(chan, "-m") cmodes = [] @@ -565,110 +565,107 @@ def del_player(cli, nick, forced_death = False): Returns: False if one side won. arg: forced_death = True when lynched. """ - - cmode = [] - cmode.append(("-v", nick)) - var.del_player(nick) - ret = True - if var.PHASE == "join": - # Died during the joining process as a person - mass_mode(cli, cmode) - return not chk_win(cli) - if var.PHASE != "join" and ret: - # Died during the game, so quiet! - if not is_fake_nick(nick): - cmode.append(("+q", nick)) - mass_mode(cli, cmode) - var.DEAD.append(nick) - ret = not chk_win(cli) - if var.PHASE in ("night", "day") and ret: - # remove him from variables if he is in there - if var.VICTIM == nick: - var.VICTIM = "" - for x in (var.OBSERVED, var.HVISITED, var.GUARDED): - keys = list(x.keys()) - for k in keys: - if k == nick: - del x[k] - elif x[k] == nick: - del x[k] - if nick in var.GUNNERS.keys(): - del var.GUNNERS[nick] - if nick in var.CURSED: - var.CURSED.remove(nick) - if var.PHASE == "day" and not forced_death and ret: # didn't die from lynching - if nick in var.VOTES.keys(): - del var.VOTES[nick] # Delete his votes - for k in var.VOTES.keys(): - if nick in var.VOTES[k]: - var.VOTES[k].remove(nick) - chk_decision(cli) - return ret + t = timetime() # time + with var.GRAVEYARD_LOCK: + if not var.GAME_ID or var.GAME_ID > t: + # either game ended, or a new game has started. + return False + cmode = [] + cmode.append(("-v", nick)) + var.del_player(nick) + ret = True + if var.PHASE == "join": + # Died during the joining process as a person + mass_mode(cli, cmode) + return not chk_win(cli) + if var.PHASE != "join" and ret: + # Died during the game, so quiet! + if not is_fake_nick(nick): + cmode.append(("+q", nick)) + mass_mode(cli, cmode) + var.DEAD.append(nick) + ret = not chk_win(cli) + if var.PHASE in ("night", "day") and ret: + # remove him from variables if he is in there + if var.VICTIM == nick: + var.VICTIM = "" + for x in (var.OBSERVED, var.HVISITED, var.GUARDED): + keys = list(x.keys()) + for k in keys: + if k == nick: + del x[k] + elif x[k] == nick: + del x[k] + if nick in var.GUNNERS.keys(): + del var.GUNNERS[nick] + if nick in var.CURSED: + var.CURSED.remove(nick) + if var.PHASE == "day" and not forced_death and ret: # didn't die from lynching + if nick in var.VOTES.keys(): + del var.VOTES[nick] # Delete his votes + for k in var.VOTES.keys(): + if nick in var.VOTES[k]: + var.VOTES[k].remove(nick) + chk_decision(cli) + return ret @hook("ping") def on_ping(cli, prefix, server): - cli.send('PONG', server) - check_graveyard(cli) + cli.send('PONG', server) + -def reaper(cli): +def reaper(cli, gameid): # check to see if idlers need to be killed. - var.IDLE_KILLED = [] var.IDLE_WARNED = [] if not var.WARN_IDLE_TIME or not var.KILL_IDLE_TIME: return - while var.PHASE != "none": - to_warn = [] - for nick in var.list_players(): - lst = var.LAST_SAID_TIME.get(nick, var.GAME_START_TIME) - tdiff = datetime.now() - lst - if (tdiff > timedelta(seconds=var.WARN_IDLE_TIME) and - nick not in var.IDLE_WARNED): - to_warn.append(nick) - var.IDLE_WARNED.append(nick) - var.LAST_SAID_TIME[nick] = (datetime.now() - - timedelta(seconds=var.KILL_IDLE_TIME)) # Give him a chance - elif (tdiff > timedelta(seconds=var.KILL_IDLE_TIME) and - nick not in var.IDLE_KILLED): - with var.GRAVEYARD_LOCK: - var.GRAVEYARD.append(("kill",nick)) - var.IDLE_KILLED.append(nick) - if to_warn: - with var.GRAVEYARD_LOCK: - var.GRAVEYARD.append(("warn", to_warn)) - sleep(10) - - - -def check_graveyard(cli): - if not var.GRAVEYARD: return - chan = botconfig.CHANNEL - with var.GRAVEYARD_LOCK: - for action, x in var.GRAVEYARD: - if action=="kill": - if x not in var.list_players(): + while gameid == var.GAME_ID: + with var.GRAVEYARD_LOCK: + to_warn = [] + to_kill = [] + for nick in var.list_players(): + lst = var.LAST_SAID_TIME.get(nick, var.GAME_START_TIME) + tdiff = datetime.now() - lst + if (tdiff > timedelta(seconds=var.WARN_IDLE_TIME) and + nick not in var.IDLE_WARNED): + to_warn.append(nick) + var.IDLE_WARNED.append(nick) + var.LAST_SAID_TIME[nick] = (datetime.now() - + timedelta(seconds=var.WARN_IDLE_TIME)) # Give him a chance + elif (tdiff > timedelta(seconds=var.KILL_IDLE_TIME) and + nick in var.IDLE_WARNED): + to_kill.append(nick) + print("WILL KILL "+nick) + elif (tdiff < timedelta(seconds=var.WARN_IDLE_TIME) and + nick in var.IDLE_WARNED): + var.IDLE_WARNED.remove(nick) # he saved himself from death + chan = botconfig.CHANNEL + for nck in to_kill: + if nck not in var.list_players(): continue cli.msg(chan, ("\u0002{0}\u0002 didn't get out of bed "+ "for a very long time. S/He is declared dead. Appears "+ - "(s)he was a \u0002{1}\u0002").format(x, var.get_role(x))) - del_player(cli, x) - elif action=="warn": - pl = var.list_players() - x = [a for a in x if a in pl] + "(s)he was a \u0002{1}\u0002").format(nck, var.get_role(nck))) + if not del_player(cli, nck): + return + pl = var.list_players() + x = [a for a in to_warn if a in pl] + if x: cli.msg(chan, ("{0}: \u0002You have been idling for a while. "+ - "Please remember to say something soon or you "+ - "might be declared dead.\u0002").format(", ".join(x))) - var.GRAVEYARD = [] + "Please remember to say something soon or you "+ + "might be declared dead.\u0002").format(", ".join(x))) + sleep(10) + @cmd("") # update last said def update_last_said(cli, nick, *rest): if var.PHASE not in ("join", "none"): var.LAST_SAID_TIME[nick] = datetime.now() - check_graveyard(cli) @@ -1647,7 +1644,8 @@ def start(cli, nick, chan, rest): transition_day(cli) # DEATH TO IDLERS! - reapertimer = threading.Thread(None, reaper, args=(cli,)) + var.GAME_ID = timetime() + reapertimer = threading.Thread(None, reaper, args=(cli,var.GAME_ID)) reapertimer.daemon = True reapertimer.start()