--- a/borgend/dreamtime.py Sun Feb 04 00:22:20 2018 +0000 +++ b/borgend/dreamtime.py Sun Feb 04 01:27:38 2018 +0000 @@ -10,6 +10,7 @@ import weakref import datetime import logging +import math logger=logging.getLogger(__name__) @@ -26,6 +27,7 @@ self._monotonic=None self._realtime=None self._dreamtime=None + self._sleeping=None def monotonic(self): if self._monotonic is None: @@ -37,13 +39,21 @@ self._realtime=time.time() return self._realtime - def dreamtime(self): + def dreamtime_sleeping(self): if self._dreamtime is None: if _dreamtime_monitor: - self._dreamtime=_dreamtime_monitor.dreamtime(snapshot=self) + self._dreamtime, self._sleeping=_dreamtime_monitor.dreamtime_sleeping(snapshot=self) else: - self._dreamtime=self.monotonic() - return self._dreamtime + self._dreamtime, self._sleeping=self.monotonic(), False + return self._dreamtime, self._sleeping + + def dreamtime(self): + time, _=self.dreamtime_sleeping() + return time + + def sleeping(self): + _, sleeping=self.dreamtime_sleeping() + return sleeping # The main Time class, for time advancing in various paces class Time: @@ -84,20 +94,26 @@ return cls.from_monotonic(other._monotonic(snapshot)+seconds, snapshot) - def datetime(self): - return datetime.datetime.fromtimestamp(self.realtime()) + def datetime(self, snapshot=Snapshot()): + return datetime.datetime.fromtimestamp(self._realtime(snapshot)) - def seconds_to(self): - return self._value-self._now(Snapshot()) + def seconds_to(self, snapshot=Snapshot()): + return self._value-self._now(snapshot) def isoformat(self): return self.datetime().isoformat() - def realtime(self): - return self._realtime(Snapshot()) + def realtime(self, snapshot=Snapshot()): + return self._realtime(snapshot) + + def monotonic(self, snapshot=Snapshot()): + return self._monotonic(snapshot) - def monotonic(self): - return self._monotonic(Snapshot()) + # Counted from the monotonic epoch, how far is this event? Usually should + # equal self.monotonic(), but Dreamtime can be stopped by system sleep, + # and will return ∞ (math.inf). + def horizon(self, snapshot=Snapshot()): + return self._monotonic(snapshot) def __compare(self, other, fn): if isinstance(other, self.__class__): @@ -143,6 +159,20 @@ def _now(snapshot): return snapshot.monotonic() +# class Infinity(Time): +# def __init__(self): +# super().__init__(math.inf) +# +# def _realtime(self, snapshot): +# return math.inf +# +# def _monotonic(self, snapshot): +# return math.inf +# +# @staticmethod +# def _now(snapshot): +# return 0 + class DreamTime(Time): def _realtime(self, snapshot): return self._value+(snapshot.realtime()-snapshot.dreamtime()) @@ -153,6 +183,12 @@ def _monotonic(self, snapshot): return self._value+(snapshot.monotonic()-snapshot.dreamtime()) + def horizon(self, snapshot=Snapshot()): + if snapshot.sleeping(): + return math.inf + else: + return self._monotonic(snapshot) + @staticmethod def _now(snapshot): return snapshot.dreamtime() @@ -163,6 +199,13 @@ import Foundation import AppKit + def do_callbacks(callbacks, woke): + for callback in callbacks.values(): + try: + callback(woke) + except Exception: + logger.exception("Error in sleep/wake notification callback") + # # Wake up / sleep handling # @@ -181,9 +224,14 @@ def handleSleepNotification_(self, aNotification): logger.info("System going to sleep") - now=time.monotonic() - with self.__lock: - self.__sleeptime=now + try: + now=time.monotonic() + with self.__lock: + self.__sleeptime=now + callbacks=self.__callbacks.copy() + do_callbacks(callbacks, False) + except: + logger.exception("Bug in sleep handler") def handleWakeNotification_(self, aNotification): logger.info("System waking up from sleep") @@ -196,17 +244,13 @@ self.__slept=self.__slept+slept self.__sleeptime=None callbacks=self.__callbacks.copy() + do_callbacks(callbacks, True) except: logger.exception("Bug in wakeup handler") - for callback in callbacks.values(): - try: - callback() - except Exception: - logger.exception("Error in wake notification callback") - # Return dreamtime - def dreamtime(self, snapshot=Snapshot()): + def dreamtime_sleeping(self, snapshot=Snapshot()): + sleeping=False with self.__lock: # macOS "sleep" signals / status are complete bollocks: at least # when plugged in, the system is actually sometimes running all @@ -215,10 +259,11 @@ # we should be sleeping! if self.__sleeptime is not None: now_monotonic=self.__sleeptime + sleeping=True else: now_monotonic=snapshot.monotonic() now_dreamtime=max(0, now_monotonic-self.__epoch-self.__slept) - return now_dreamtime + return now_dreamtime, sleeping # Weirdo (Py)ObjC naming to stop it form choking up def addForObj_aCallback_(self, obj, callback):