class TimedEventFailureLog(Item): typeName = 'timed_event_failure_log' schemaVersion = 1 desiredTime = timestamp() actualTime = timestamp() runnable = reference() traceback = bytes()
class SubScheduler(Item, SchedulerMixin): """ Track and execute persistent timed events for a substore. """ schemaVersion = 1 typeName = 'axiom_subscheduler' implements(IScheduler) powerupInterfaces = (IScheduler, ) eventsRun = integer(default=0) lastEventAt = timestamp() nextEventAt = timestamp() # Also testing hooks now = inmemory() def __repr__(self): return '<SubScheduler for %r>' % (self.store, ) def activate(self): self.now = Time def _transientSchedule(self, when, now): if self.store.parent is not None: loginAccount = self.store.parent.getItemByID(self.store.idInParent) hook = self.store.parent.findOrCreate( _SubSchedulerParentHook, lambda hook: installOn(hook, hook.store), loginAccount=loginAccount) hook._schedule(when) def migrateDown(self): """ Remove the components in the site store for this SubScheduler. """ loginAccount = self.store.parent.getItemByID(self.store.idInParent) ssph = self.store.parent.findUnique( _SubSchedulerParentHook, _SubSchedulerParentHook.loginAccount == loginAccount, default=None) if ssph is not None: te = self.store.parent.findUnique(TimedEvent, TimedEvent.runnable == ssph, default=None) if te is not None: te.deleteFromStore() ssph.deleteFromStore() def migrateUp(self): """ Recreate the hooks in the site store to trigger this SubScheduler. """ te = self.store.findFirst(TimedEvent, sort=TimedEvent.time.descending) if te is not None: self._transientSchedule(te.time, Time)
class DBShortMessage(item.Item): """ I represent a contact on the DB """ # (id integer, category integer, number text, date text, smstext text) typeName = 'DBShortMessage' schemaVersion = 1 date = attributes.timestamp(allowNone=False) number = attributes.text(allowNone=False) text = attributes.text(allowNone=False) where = attributes.integer(allowNone=False) def __repr__(self): args = (self.number, self.text, self.date) return '<DBShortMessage number="%s" text="%s" date="%s">' % args def __eq__(self, m): if isinstance(m, DBShortMessage): return (self.number == m.number and self.text == m.text and self.date == m.date) return False def __ne__(self, m): return not (self.number == m.number and self.text == m.text and self.date == m.date) def get_index(self): return self.storeID def get_number(self): return self.number def get_text(self): return self.text
class UsageItem(item.Item): umts = attributes.boolean(allowNone=False) start_time = attributes.timestamp(allowNone=False) end_time = attributes.timestamp(allowNone=False) bits_recv = attributes.integer(allowNone=False) bits_sent = attributes.integer(allowNone=False) def __repr__(self): _type = (self.umts == True) and 'UMTS' or 'GPRS' args = (_type, self.end_time - self.start_time, self.bits_recv + self.bits_sent) return "<%s UsageItem time: %s total bits: %d>" % args def __eq__(self, other): if not isinstance(other, UsageItem): raise ValueError("Cannot reliably compare myself with %s" % other) return self.storeID == other.storeID def __ne__(self, other): return not self.__eq__(other)
class TimedEvent(Item): typeName = 'timed_event' schemaVersion = 1 time = timestamp(indexed=True) runnable = reference() def _rescheduleFromRun(self, newTime): """ Schedule this event to be run at the indicated time, or if the indicated time is None, delete this event. """ if newTime is None: self.deleteFromStore() else: self.time = newTime def invokeRunnable(self): """ Run my runnable, and reschedule or delete myself based on its result. Must be run in a transaction. """ runnable = self.runnable if runnable is None: self.deleteFromStore() else: self._rescheduleFromRun(runnable.run()) def handleError(self, now, failureObj): """ An error occurred running my runnable. Check my runnable for an error-handling method called 'timedEventErrorHandler' that will take the given failure as an argument, and execute that if available: otherwise, create a TimedEventFailureLog with information about what happened to this event. Must be run in a transaction. """ errorHandler = getattr(self.runnable, 'timedEventErrorHandler', None) if errorHandler is not None: self._rescheduleFromRun(errorHandler(self, failureObj)) else: self._defaultErrorHandler(now, failureObj) def _defaultErrorHandler(self, now, failureObj): tefl = TimedEventFailureLog(store=self.store, desiredTime=self.time, actualTime=now, runnable=self.runnable, traceback=failureObj.getTraceback()) self.deleteFromStore()
class DBShortMessage(item.Item): """ I represent a contact on the DB """ # (id integer, category integer, number text, date text, smstext text) typeName = 'DBShortMessage' schemaVersion = 1 date = attributes.timestamp(allowNone=False) number = attributes.text(allowNone=False) text = attributes.text(allowNone=False) where = attributes.integer(allowNone=False) def __repr__(self): args = (self.number, self.text, self.date) return '<DBShortMessage number="%s" text="%s" date="%s">' % args def __eq__(self, m): if isinstance(m, DBShortMessage): return (self.number == m.number and self.text == m.text and self.date == m.date) return False def __ne__(self, m): return not (self.number == m.number and self.text == m.text and self.date == m.date) def get_index(self): return self.storeID def get_number(self): return self.number def get_text(self): return self.text def to_csv(self): """Returns a list with the date, number and text formatted for csv""" tzinfo = osobj.get_tzinfo() date = '"' + time.strftime( "%c", self.date.asDatetime(tzinfo=tzinfo).timetuple()) + '"' number = '"' + self.number + '"' text = '"' + self.text + '"' return [date, number, text]
class _SubSchedulerParentHook(Item): schemaVersion = 2 typeName = 'axiom_subscheduler_parent_hook' loginAccount = reference() scheduledAt = timestamp(default=None) scheduler = dependsOn(Scheduler) def run(self): self.scheduledAt = None IScheduler(self.loginAccount).tick() def _schedule(self, when): if self.scheduledAt is not None: if when < self.scheduledAt: self.scheduler.reschedule(self, self.scheduledAt, when) self.scheduledAt = when else: self.scheduler.schedule(self, when) self.scheduledAt = when
class Tag(Item): typeName = 'tag' schemaVersion = 1 name = text(doc=""" The short string which is being applied as a tag to an Item. """) created = timestamp(doc=""" When this tag was applied to the Item to which it applies. """) object = reference(doc=""" The Item to which this tag applies. """) catalog = reference(doc=""" The L{Catalog} item in which this tag was created. """) tagger = reference(doc=""" An optional reference to the Item which is responsible for this tag's existence. """)
class Scheduler(Item, Service, SchedulerMixin): """ Track and execute persistent timed events for a I{site} store. """ typeName = 'axiom_scheduler' schemaVersion = 1 implements(IService, IScheduler) powerupInterfaces = (IService, IScheduler) parent = inmemory() name = inmemory() timer = inmemory() # Also testing hooks callLater = inmemory() now = inmemory() eventsRun = integer() lastEventAt = timestamp() nextEventAt = timestamp() class running(descriptor.attribute): def get(self): return (self.parent is self.store._axiom_service and self.store._axiom_service is not None and self.store._axiom_service.running) def set(self, value): # Eh whatever pass def __init__(self, **kw): super(Scheduler, self).__init__(**kw) self.eventsRun = 0 self.lastEventAt = None self.nextEventAt = None def __repr__(self): return '<Scheduler>' def installed(self): self.setServiceParent(IService(self.store)) def activate(self): self.timer = None self.callLater = reactor.callLater self.now = Time def startService(self): """ Start calling persistent timed events whose time has come. """ super(Scheduler, self).startService() self._transientSchedule(self.now(), self.now()) def stopService(self): """ Stop calling persistent timed events. """ super(Scheduler, self).stopService() if self.timer is not None: self.timer.cancel() self.timer = None def tick(self): self.timer = None return super(Scheduler, self).tick() def _transientSchedule(self, when, now): if not self.running: return if self.timer is not None: if self.timer.getTime() < when.asPOSIXTimestamp(): return self.timer.cancel() delay = when.asPOSIXTimestamp() - now.asPOSIXTimestamp() # reactor.callLater allows only positive delay values. The scheduler # may want to have scheduled things in the past and that's OK, since we # are dealing with Time() instances it's impossible to predict what # they are relative to the current time from user code anyway. delay = max(_EPSILON, delay) self.timer = self.callLater(delay, self.tick) self.nextEventAt = when