Made TickerHandler more general.

This commit is contained in:
Griatch 2014-02-11 21:30:05 +01:00
parent 205960948d
commit afc7fd758f

View file

@ -9,36 +9,35 @@ method "at_tick".
from twisted.internet.task import LoopingCall from twisted.internet.task import LoopingCall
from src.server.models import ServerConfig from src.server.models import ServerConfig
from src.utils.logger import log_trace from src.utils.logger import log_trace
from src.utils.utils import to_str
from src.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj, unpack_dbobj from src.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj, unpack_dbobj
_GA = object.__getattribute__ _GA = object.__getattribute__
_SA = object.__setattr__ _SA = object.__setattr__
class _Ticker(object): class Ticker(object):
""" """
Represents a repeatedly running task that calls Represents a repeatedly running task that calls
hooks repeatedly. hooks repeatedly.
""" """
def __init__(self, interval, hook_key="at_tick"): def __init__(self, interval):
""" """
Set up the ticker Set up the ticker
""" """
def callback(self): def callback(self):
"This should be fed _Task as argument" "This should be fed _Task as argument"
hook_key = self.hook_key for key, (obj, args, kwargs) in self.subscriptions.items():
for key, obj in self.subscriptions.items(): hook_key = kwargs.get("hook_key", "at_tick")
try: try:
_GA(obj, hook_key)() _GA(obj, hook_key)(*args, **kwargs)
except Exception: except Exception:
log_trace() log_trace()
self.interval = interval self.interval = interval
self.hook_key = hook_key
self.subscriptions = {} self.subscriptions = {}
self.task = LoopingCall(callback, self) self.task = LoopingCall(callback, self)
def validate(self): def validate(self):
""" """
Start/stop the task depending on how many Start/stop the task depending on how many
@ -55,11 +54,11 @@ class _Ticker(object):
elif subs: elif subs:
self.task.start(self.interval, now=False) self.task.start(self.interval, now=False)
def add(self, store_key, obj): def add(self, store_key, obj, *args, **kwargs):
""" """
Sign up a subscriber to this ticker Sign up a subscriber to this ticker
""" """
self.subscriptions[store_key] = obj self.subscriptions[store_key] = (obj, args, kwargs)
self.validate() self.validate()
def remove(self, store_key): def remove(self, store_key):
@ -76,22 +75,22 @@ class _Ticker(object):
self.subscriptions = {} self.subscriptions = {}
self.validate() self.validate()
class _TickerPool(object): class TickerPool(object):
""" """
This maintains a pool of Twisted LoopingCall tasks This maintains a pool of Twisted LoopingCall tasks
for calling subscribed objects at given times. for calling subscribed objects at given times.
""" """
def __init__(self, hook_key="at_tick"): def __init__(self):
"Initialize the pool" "Initialize the pool"
self.tickers = {} self.tickers = {}
def add(self, store_key, obj, interval, hook_key="at_tick"): def add(self, store_key, obj, interval, *args, **kwargs):
""" """
Add new ticker subscriber Add new ticker subscriber
""" """
if interval not in self.tickers: if interval not in self.tickers:
self.tickers[interval] = _Ticker(interval, hook_key=hook_key) self.tickers[interval] = Ticker(interval)
self.tickers[interval].add(store_key, obj) self.tickers[interval].add(store_key, obj, *args, **kwargs)
def remove(self, store_key, interval): def remove(self, store_key, interval):
""" """
@ -119,14 +118,15 @@ class TickerHandler(object):
objects to various tick rates. The pool maintains creation objects to various tick rates. The pool maintains creation
instructions and and re-applies them at a server restart. instructions and and re-applies them at a server restart.
""" """
def __init__(self): def __init__(self, save_name="ticker_storage"):
""" """
Initialize handler Initialize handler
""" """
self.ticker_storage = {} self.ticker_storage = {}
self.ticker_pool = _TickerPool() self.save_name = save_name
self.ticker_pool = TickerPool()
def _store_key(self, obj, interval, hook_key): def _store_key(self, obj, interval):
""" """
Tries to create a store_key for the object. Tries to create a store_key for the object.
Returns a tuple (isdb, store_key) where isdb Returns a tuple (isdb, store_key) where isdb
@ -155,7 +155,7 @@ class TickerHandler(object):
objkey = id(obj) objkey = id(obj)
isdb = False isdb = False
# return sidb and store_key # return sidb and store_key
return isdb, (objkey, interval, hook_key) return isdb, (objkey, interval)
def save(self): def save(self):
""" """
@ -164,42 +164,42 @@ class TickerHandler(object):
""" """
#print "save:", self.ticker_storage #print "save:", self.ticker_storage
if self.ticker_storage: if self.ticker_storage:
ServerConfig.objects.conf(key="ticker_storage", ServerConfig.objects.conf(key=self.save_name,
value=dbserialize(self.ticker_storage)) value=dbserialize(self.ticker_storage))
else: else:
ServerConfig.objects.conf(key="ticker_storage", delete=True) ServerConfig.objects.conf(key=self.save_name, delete=True)
def restore(self): def restore(self):
""" """
Restore ticker_storage from database and re-initialize the handler from storage. This is triggered by the server at restart. Restore ticker_storage from database and re-initialize the handler from storage. This is triggered by the server at restart.
""" """
# load stored command instructions and use them to re-initialize handler # load stored command instructions and use them to re-initialize handler
ticker_storage = ServerConfig.objects.conf(key="ticker_storage") ticker_storage = ServerConfig.objects.conf(key=self.save_name)
if ticker_storage: if ticker_storage:
self.ticker_storage = dbunserialize(ticker_storage) self.ticker_storage = dbunserialize(ticker_storage)
#print "restore:", self.ticker_storage print "restore:", self.ticker_storage
for (obj, interval, hook_key) in self.ticker_storage.values(): for (obj, interval), (args, kwargs) in self.ticker_storage.items():
obj = unpack_dbobj(obj) obj = unpack_dbobj(obj)
_, store_key = self._store_key(obj, interval, hook_key) _, store_key = self._store_key(obj, interval)
self.ticker_pool.add(store_key, obj, interval, hook_key) self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
def add(self, obj, interval, hook_key="at_tick"): def add(self, obj, interval, *args, **kwargs):
""" """
Add object to tickerhandler. The object must have an at_tick Add object to tickerhandler. The object must have an at_tick
method. This will be called every interval seconds until the method. This will be called every interval seconds until the
object is unsubscribed from the ticker. object is unsubscribed from the ticker.
""" """
isdb, store_key = self._store_key(obj, interval, hook_key) isdb, store_key = self._store_key(obj, interval)
if isdb: if isdb:
self.ticker_storage[store_key] = store_key self.ticker_storage[store_key] = (args, kwargs)
self.save() self.save()
self.ticker_pool.add(store_key, obj, interval, hook_key) self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
def remove(self, obj, interval, hook_key="at_tick"): def remove(self, obj, interval):
""" """
Remove object from ticker with given interval. Remove object from ticker with given interval.
""" """
isdb, store_key = self._store_key(obj, interval, hook_key) isdb, store_key = self._store_key(obj, interval)
if isdb: if isdb:
self.ticker_storage.pop(store_key, None) self.ticker_storage.pop(store_key, None)
self.save() self.save()