import threading import requests, json from planetstack.config import Config from observer.deleter import Deleter import uuid import os import imp import inspect import base64 from fofum import Fofum import json import traceback random_client_id=None def get_random_client_id(): global random_client_id if (random_client_id is None) and os.path.exists("/opt/planetstack/random_client_id"): # try to use the last one we used, if we saved it try: random_client_id = open("/opt/planetstack/random_client_id","r").readline().strip() print "get_random_client_id: loaded %s" % random_client_id except: print "get_random_client_id: failed to read /opt/planetstack/random_client_id" if random_client_id is None: random_client_id = base64.urlsafe_b64encode(os.urandom(12)) print "get_random_client_id: generated new id %s" % random_client_id # try to save it for later (XXX: could race with another client here) try: open("/opt/planetstack/random_client_id","w").write("%s\n" % random_client_id) except: print "get_random_client_id: failed to write /opt/planetstack/random_client_id" return random_client_id # decorator that marks dispatachable event methods def event(func): setattr(func, 'event', func.__name__) return func class EventHandler: # This code is currently not in use. def __init__(self): pass @staticmethod def get_events(): events = [] for name in dir(EventHandler): attribute = getattr(EventHandler, name) if hasattr(attribute, 'event'): events.append(getattr(attribute, 'event')) return events def dispatch(self, event, *args, **kwds): if hasattr(self, event): return getattr(self, event)(*args, **kwds) class EventSender: def __init__(self,user=None,clientid=None): try: user = Config().feefie_client_user except: user = 'pl' try: clid = Config().feefie_client_id except: clid = get_random_client_id() print "EventSender: no feefie_client_id configured. Using random id %s" % clid self.fofum = Fofum(user=user) self.fofum.make(clid) def fire(self,**kwargs): kwargs["uuid"] = str(uuid.uuid1()) self.fofum.fire(json.dumps(kwargs)) class EventListener: def __init__(self,wake_up=None): self.handler = EventHandler() self.wake_up = wake_up self.deleters = {} self.load_deleter_modules() def load_deleter_modules(self, deleter_dir=None): if deleter_dir is None: if hasattr(Config(), "observer_deleters_dir"): deleter_dir = Config().observer_deleters_dir else: deleter_dir = "/opt/planetstack/observer/deleters" for fn in os.listdir(deleter_dir): pathname = os.path.join(deleter_dir,fn) if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"): module = imp.load_source(fn[:-3],pathname) for classname in dir(module): c = getattr(module, classname, None) # make sure 'c' is a descendent of Deleter and has a # provides field (this eliminates the abstract base classes # since they don't have a provides) if inspect.isclass(c) and issubclass(c, Deleter) and hasattr(c,"model") and c.model!=None: modelName = c.model if not modelName in self.deleters: self.deleters[modelName] = [] if not (c in self.deleters[modelName]): self.deleters[modelName].append(c) print 'loaded deleters: %s' % ",".join(self.deleters.keys()) def handle_event(self, payload): payload_dict = json.loads(payload) try: deletion = payload_dict.get('delete_flag', False) if (deletion): model = payload_dict['model'] pk = payload_dict['pk'] model_dict = payload_dict['model_dict'] for deleter in self.deleters[model]: try: deleter()(pk, model_dict) except: # something is silently eating these # exceptions... traceback.print_exc() raise except: deletion = False if (not deletion and self.wake_up): self.wake_up() def run(self): # This is our unique client id, to be used when firing and receiving events # It needs to be generated once and placed in the config file try: user = Config().feefie_client_user except: user = 'pl' try: clid = Config().feefie_client_id except: clid = get_random_client_id() print "EventListener: no feefie_client_id configured. Using random id %s" % clid f = Fofum(user=user) listener_thread = threading.Thread(target=f.listen_for_event,args=(clid,self.handle_event)) listener_thread.start()