diff --git a/modules/coins.py b/modules/coins.py index 86c334e2..4e0f966e 100644 --- a/modules/coins.py +++ b/modules/coins.py @@ -101,6 +101,9 @@ class Module(object): all_coins[nickname])) for nickname in top_10) event["stdout"].write("Richest users: %s" % top_10) + def _redeem_cache(self, server, user): + return "redeem|%s|%s@%s" % (server.id, user.username, user.hostname) + @Utils.hook("received.command.redeemcoins") def redeem_coins(self, event): """ @@ -109,21 +112,20 @@ class Module(object): user_coins = decimal.Decimal(event["user"].get_setting( "coins", "0.0")) if user_coins == DECIMAL_ZERO: - last_redeem = event["user"].get_setting("last-redeem", None) - redeem_delay = event["server"].get_setting("redeem-delay", - DEFAULT_REDEEM_DELAY) - - if last_redeem == None or (time.time()-last_redeem - ) >= redeem_delay: + cache = self._redeem_cache(event["server"], event["user"]) + if not self.bot.cache.has_item(cache): redeem_amount = decimal.Decimal(event["server" ].get_setting("redeem-amount", DEFAULT_REDEEM_AMOUNT)) event["user"].set_setting("coins", str( user_coins+redeem_amount)) event["stdout"].write("Redeemed %s coins" % "{0:.2f}".format( redeem_amount)) - event["user"].set_setting("last-redeem", time.time()) + + redeem_delay = event["server"].get_setting("redeem-delay", + DEFAULT_REDEEM_DELAY) + self.bot.cache.temporary_cache(cache, redeem_delay) else: - time_left = (last_redeem+redeem_delay)-time.time() + time_left = self.bot.cache.until_expiration(cache) event["stderr"].write("Please wait %s before redeeming" % Utils.to_pretty_time(math.ceil(time_left))) else: diff --git a/src/Cache.py b/src/Cache.py new file mode 100644 index 00000000..4d7c8def --- /dev/null +++ b/src/Cache.py @@ -0,0 +1,50 @@ +import time, uuid + +class Cache(object): + def __init__(self): + self._items = {} + self._item_to_id = {} + + def cache(self, item): + return self._cache(item, None) + def temporary_cache(self, item, timeout): + return self._cache(item, timeout) + def _cache(self, item, timeout): + id = str(uuid.uuid4()) + self._items[id] = [item, time.monotonic()+timeout] + self._item_to_id[item] = id + return id + + def next_expiration(self): + expirations = [self._items[id][1] for id in self._items] + expirations = list(filter(None, expirations)) + if not expirations: + return None + expirations = [e-time.monotonic() for e in expirations] + return max(min(expirations), 0) + + def expire(self): + now = time.monotonic() + expired = [] + for id in self._items: + item, expiration = self._items[id] + if expiration and expiration <= now: + expired.append(id) + for id in expired: + del self._items[id] + del self._item_to_id[item] + + def has_item(self, item): + return item in self._item_to_id + + def get(self, id): + item, expiration = self._items[id] + return item + + def get_expiration(self, item): + id = self._item_to_id[item] + item, expiration = self._items[id] + return expiration + def until_expiration(self, item): + expiration = self.get_expiration(item) + return expiration-time.monotonic() diff --git a/src/IRCBot.py b/src/IRCBot.py index f4c96627..ff5157cd 100644 --- a/src/IRCBot.py +++ b/src/IRCBot.py @@ -2,12 +2,12 @@ import os, select, sys, threading, time, traceback, uuid from . import EventManager, Exports, IRCLineHandler, IRCServer, Logging from . import ModuleManager - class Bot(object): - def __init__(self, directory, args, config, database, events, exports, - line_handler, log, modules, timers): + def __init__(self, directory, args, cache, config, database, events, + exports, line_handler, log, modules, timers): self.directory = directory self.args = args + self.cache = cache self.config = config self.database = database self._events = events @@ -79,6 +79,7 @@ class Bot(object): timeouts.append(self.next_send()) timeouts.append(self.next_ping()) timeouts.append(self.next_read_timeout()) + timeouts.append(self.cache.next_expiration()) return min([timeout for timeout in timeouts if not timeout == None]) def register_read(self, server): @@ -120,6 +121,7 @@ class Bot(object): self.lock.acquire() events = self.poll.poll(self.get_poll_timeout()) self.timers.call() + self.cache.expire() for fd, event in events: if fd in self.servers: diff --git a/start.py b/start.py index 4094bfbd..132d7fb7 100755 --- a/start.py +++ b/start.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import argparse, os, sys, time -from src import Config, Database, EventManager, Exports, IRCBot +from src import Cache, Config, Database, EventManager, Exports, IRCBot from src import IRCLineHandler, Logging, ModuleManager, Timers def bool_input(s): @@ -31,6 +31,7 @@ args = arg_parser.parse_args() log = Logging.Log(args.log) +cache = Cache.Cache() config = Config.Config(args.config) database = Database.Database(log, args.database) events = events = EventManager.EventHook(log) @@ -40,8 +41,8 @@ line_handler = IRCLineHandler.LineHandler(events, timers) modules = modules = ModuleManager.ModuleManager(events, exports, config, log, os.path.join(directory, "modules")) -bot = IRCBot.Bot(directory, args, config, database, events, exports, - line_handler, log, modules, timers) +bot = IRCBot.Bot(directory, args, cache, config, database, events, + exports, line_handler, log, modules, timers) whitelist = bot.get_setting("module-whitelist", []) blacklist = bot.get_setting("module-blacklist", [])