borgend/dreamtime.py

changeset 101
3068b0de12ee
parent 100
b141bed9e718
child 106
a7bdc239ef62
--- 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):

mercurial