# HG changeset patch # User Tuomo Valkonen # Date 1517137492 0 # Node ID 83b43987e61ec23cf5716bf9655ce25830762e1a # Parent e8773133bf79be9a985518cc64fa9b75cb157129 Renamed the "sleep" module "dreamtime" diff -r e8773133bf79 -r 83b43987e61e backup.py --- a/backup.py Sun Jan 28 11:01:45 2018 +0000 +++ b/backup.py Sun Jan 28 11:04:52 2018 +0000 @@ -7,7 +7,7 @@ import time import borgend import repository -import sleep +import dreamtime from enum import IntEnum from instance import BorgInstance from threading import Thread, Lock, Condition @@ -143,9 +143,9 @@ default="dreamtime") if scheduling=="dreamtime": - self.timeclass=sleep.DreamTime + self.timeclass=dreamtime.DreamTime elif scheduling=="realtime": - self.timeclass=sleep.MonotonicTime + self.timeclass=dreamtime.MonotonicTime elif scheduling=="manual": self.backup_interval=0 else: @@ -172,7 +172,7 @@ self.lastrun_finished=None self.state=State.INACTIVE self.errors=Errors.OK - self.timeclass=sleep.DreamTime + self.timeclass=dreamtime.DreamTime self.__decode_config(cfg) @@ -300,7 +300,7 @@ self.current_operation=op # Update scheduled time to real starting time to schedule # next run relative to this - self.current_operation.time=sleep.MonotonicTime.now() + self.current_operation.time=dreamtime.MonotonicTime.now() self.state=State.ACTIVE # Reset error status when starting a new operation self.errors=Errors.OK @@ -472,7 +472,7 @@ if self.retry_interval==0: return None else: - tm=sleep.MonotonicTime(self.lastrun_finished+self.retry_interval) + tm=dreamtime.MonotonicTime(self.lastrun_finished+self.retry_interval) return Operation(Operation.CREATE, tm, reason='retry') else: if self.backup_interval==0: @@ -518,13 +518,13 @@ return res[0] def create(self): - op=Operation(Operation.CREATE, sleep.MonotonicTime.now(), reason='manual') + op=Operation(Operation.CREATE, dreamtime.MonotonicTime.now(), reason='manual') with self._cond: self.scheduled_operation=op self._cond.notify() def prune(self): - op=Operation(Operation.PRUNE, sleep.MonotonicTime.now(), reason='manual') + op=Operation(Operation.PRUNE, dreamtime.MonotonicTime.now(), reason='manual') with self._cond: self.scheduled_operation=op self._cond.notify() diff -r e8773133bf79 -r 83b43987e61e borgend.py --- a/borgend.py Sun Jan 28 11:01:45 2018 +0000 +++ b/borgend.py Sun Jan 28 11:04:52 2018 +0000 @@ -103,9 +103,9 @@ from backup import Backup from queue import Queue import signal, os - import sleep + import dreamtime - sleep.start_monitoring() + dreamtime.start_monitoring() scheduler = Scheduler() scheduler.start() diff -r e8773133bf79 -r 83b43987e61e dreamtime.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dreamtime.py Sun Jan 28 11:04:52 2018 +0000 @@ -0,0 +1,212 @@ +# +# Wake/sleep detection for scheduling adjustments +# + +import Foundation +import AppKit +import platform +import time +import threading +import weakref +import datetime +import borgend + +logger=borgend.logger.getChild(__name__) + +_dreamtime_monitor=None + +# +# Support classes for dealing with different times +# + +# Return difference (delay) of "dreamtime" to monotonic time +def dreamtime_difference(): + if _dreamtime_monitor: + return _dreamtime_monitor.diff() + else: + return time.monotonic() + +# Return "dreamtime" +def dreamtime(): + return max(0, time.monotonic()-dreamtime_difference()) + +class Time: + def realtime(self): + raise NotImplementedError + + def monotonic(self): + raise NotImplementedError + + @staticmethod + def _now(): + raise NotImplementedError + + @classmethod + def now(cls): + return cls(cls._now()) + + @classmethod + def from_realtime(cls, realtime): + return cls(realtime-time.time()+cls._now()) + + @classmethod + def from_monotonic(cls, monotonic): + return cls(monotonic-time.monotonic()+cls._now()) + + @classmethod + def after(cls, seconds): + return cls(cls._now()+seconds) + + def datetime(self): + return datetime.datetime.fromtimestamp(self.realtime()) + + def seconds_to(self): + return self._value-self._now() + + def __lt__(self, other): + return self.monotonic() < other.monotonic() + + def __gt__(self, other): + return self.monotonic() > other.monotonic() + + def __le__(self, other): + return self.monotonic() <= other.monotonic() + + def __ge__(self, other): + return self.monotonic() >= other.monotonic() + + def __eq__(self, other): + return self.monotonic() == other.realtime() + +class RealTime(Time): + def __init__(self, when): + self._value=when + + def realtime(self): + return self._value + + def monotonic(self): + return self._value+(time.monotonic()-time.time()) + + @staticmethod + def _now(): + return time.time() + +class MonotonicTime(Time): + def __init__(self, when): + self._value=when + + def realtime(self): + return self._value+(time.time()-time.monotonic()) + + def monotonic(self): + return self._value + + @staticmethod + def _now(): + return time.monotonic() + +class DreamTime(Time): + def __init__(self, when): + self._value=when + + def realtime(self): + return self._value+(time.time()-dreamtime()) + + # Important: monotonic is "static" within a wakeup period + # and does not need to call time.monotonic(), as it gets compared + # to a specific time.monotonic() realisation + def monotonic(self): + return self._value+dreamtime_difference() + + @staticmethod + def _now(): + return dreamtime() + +# +# Wake up / sleep handling +# + +class SleepHandler(Foundation.NSObject): + """ Handle wake/sleep notifications """ + + def init(self): + self.__sleeptime=None + self.__slept=0 + self.__epoch=time.monotonic() + self.__lock=threading.Lock() + self.__callbacks=weakref.WeakKeyDictionary() + + return self + + def handleSleepNotification_(self, aNotification): + logger.info("System going to sleep") + now=time.monotonic() + with self.__lock: + self.__sleeptime=now + + def handleWakeNotification_(self, aNotification): + logger.info("System waking up from sleep") + try: + now=time.monotonic() + with self.__lock: + if self.__sleeptime: + slept=max(0, now-self.__sleeptime) + logger.info("Slept %f seconds" % slept) + self.__slept=self.__slept+slept + self.__sleeptime=None + callbacks=self.__callbacks.copy() + except: + logger.exception("Bug in wakeup handler") + + for callback in callbacks.values(): + try: + callback() + except Exception: + logger.exception("Error in wake notification callback") + + # Return difference to time.monotonic() + def diff(self): + with self.__lock: + diff=self.__epoch+self.__slept + return diff + + # Weirdo (Py)ObjC naming to stop it form choking up + def addForObj_aCallback_(self, obj, callback): + with self.__lock: + self.__callbacks[obj]=callback + +# obj is to use a a key in a weak key dictionary +def add_callback(obj, callback): + global _dreamtime_monitor + + monitor=_dreamtime_monitor + if not monitor: + raise Exception("Dreamtime monitor not started") + else: + monitor.addForObj_aCallback_(obj, callback) + +def start_monitoring(): + global _dreamtime_monitor + + if platform.system()=='Darwin': + logger.debug("Starting to monitor system sleep") + workspace = AppKit.NSWorkspace.sharedWorkspace() + notification_center = workspace.notificationCenter() + _dreamtime_monitor = SleepHandler.new() + + notification_center.addObserver_selector_name_object_( + _dreamtime_monitor, + "handleSleepNotification:", + AppKit.NSWorkspaceWillSleepNotification, + None) + + notification_center.addObserver_selector_name_object_( + _dreamtime_monitor, + "handleWakeNotification:", + AppKit.NSWorkspaceDidWakeNotification, + None) + else: + logger.warning(("No system sleep monitor implemented for '%s'" + % platform.system())) + diff -r e8773133bf79 -r 83b43987e61e scheduler.py --- a/scheduler.py Sun Jan 28 11:01:45 2018 +0000 +++ b/scheduler.py Sun Jan 28 11:04:52 2018 +0000 @@ -6,7 +6,7 @@ import time import borgend -import sleep +import dreamtime from threading import Condition, Lock, Thread logger=borgend.logger.getChild(__name__) @@ -50,7 +50,7 @@ self.prev=None class ScheduledEvent(QueuedEvent): - #@accepts(ScheduledEvent, sleep.Time, threading.Cond, str) + #@accepts(ScheduledEvent, dreamtime.Time, threading.Cond, str) def __init__(self, when, cond, name=None): super().__init__(cond, name=name) self.when=when @@ -113,7 +113,7 @@ self.precision = precision self._next_event_time = None super().__init__(target = self._scheduler_thread, name = 'Scheduler') - sleep.add_callback(self, self._wakeup_callback) + dreamtime.add_callback(self, self._wakeup_callback) def _scheduler_thread(self): logger.debug("Scheduler thread started") diff -r e8773133bf79 -r 83b43987e61e sleep.py --- a/sleep.py Sun Jan 28 11:01:45 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -# -# Wake/sleep detection for scheduling adjustments -# - -import Foundation -import AppKit -import platform -import time -import threading -import weakref -import datetime -import borgend - -logger=borgend.logger.getChild(__name__) - -_dreamtime_monitor=None - -# -# Support classes for dealing with different times -# - -# Return difference (delay) of "dreamtime" to monotonic time -def dreamtime_difference(): - if _dreamtime_monitor: - return _dreamtime_monitor.diff() - else: - return time.monotonic() - -# Return "dreamtime" -def dreamtime(): - return max(0, time.monotonic()-dreamtime_difference()) - -class Time: - def realtime(self): - raise NotImplementedError - - def monotonic(self): - raise NotImplementedError - - @staticmethod - def _now(): - raise NotImplementedError - - @classmethod - def now(cls): - return cls(cls._now()) - - @classmethod - def from_realtime(cls, realtime): - return cls(realtime-time.time()+cls._now()) - - @classmethod - def from_monotonic(cls, monotonic): - return cls(monotonic-time.monotonic()+cls._now()) - - @classmethod - def after(cls, seconds): - return cls(cls._now()+seconds) - - def datetime(self): - return datetime.datetime.fromtimestamp(self.realtime()) - - def seconds_to(self): - return self._value-self._now() - - def __lt__(self, other): - return self.monotonic() < other.monotonic() - - def __gt__(self, other): - return self.monotonic() > other.monotonic() - - def __le__(self, other): - return self.monotonic() <= other.monotonic() - - def __ge__(self, other): - return self.monotonic() >= other.monotonic() - - def __eq__(self, other): - return self.monotonic() == other.realtime() - -class RealTime(Time): - def __init__(self, when): - self._value=when - - def realtime(self): - return self._value - - def monotonic(self): - return self._value+(time.monotonic()-time.time()) - - @staticmethod - def _now(): - return time.time() - -class MonotonicTime(Time): - def __init__(self, when): - self._value=when - - def realtime(self): - return self._value+(time.time()-time.monotonic()) - - def monotonic(self): - return self._value - - @staticmethod - def _now(): - return time.monotonic() - -class DreamTime(Time): - def __init__(self, when): - self._value=when - - def realtime(self): - return self._value+(time.time()-dreamtime()) - - # Important: monotonic is "static" within a wakeup period - # and does not need to call time.monotonic(), as it gets compared - # to a specific time.monotonic() realisation - def monotonic(self): - return self._value+dreamtime_difference() - - @staticmethod - def _now(): - return dreamtime() - -# -# Wake up / sleep handling -# - -class SleepHandler(Foundation.NSObject): - """ Handle wake/sleep notifications """ - - def init(self): - self.__sleeptime=None - self.__slept=0 - self.__epoch=time.monotonic() - self.__lock=threading.Lock() - self.__callbacks=weakref.WeakKeyDictionary() - - return self - - def handleSleepNotification_(self, aNotification): - logger.info("System going to sleep") - now=time.monotonic() - with self.__lock: - self.__sleeptime=now - - def handleWakeNotification_(self, aNotification): - logger.info("System waking up from sleep") - try: - now=time.monotonic() - with self.__lock: - if self.__sleeptime: - slept=max(0, now-self.__sleeptime) - logger.info("Slept %f seconds" % slept) - self.__slept=self.__slept+slept - self.__sleeptime=None - callbacks=self.__callbacks.copy() - except: - logger.exception("Bug in wakeup handler") - - for callback in callbacks.values(): - try: - callback() - except Exception: - logger.exception("Error in wake notification callback") - - # Return difference to time.monotonic() - def diff(self): - with self.__lock: - diff=self.__epoch+self.__slept - return diff - - # Weirdo (Py)ObjC naming to stop it form choking up - def addForObj_aCallback_(self, obj, callback): - with self.__lock: - self.__callbacks[obj]=callback - -# obj is to use a a key in a weak key dictionary -def add_callback(obj, callback): - global _dreamtime_monitor - - monitor=_dreamtime_monitor - if not monitor: - raise Exception("Dreamtime monitor not started") - else: - monitor.addForObj_aCallback_(obj, callback) - -def start_monitoring(): - global _dreamtime_monitor - - if platform.system()=='Darwin': - logger.debug("Starting to monitor system sleep") - workspace = AppKit.NSWorkspace.sharedWorkspace() - notification_center = workspace.notificationCenter() - _dreamtime_monitor = SleepHandler.new() - - notification_center.addObserver_selector_name_object_( - _dreamtime_monitor, - "handleSleepNotification:", - AppKit.NSWorkspaceWillSleepNotification, - None) - - notification_center.addObserver_selector_name_object_( - _dreamtime_monitor, - "handleWakeNotification:", - AppKit.NSWorkspaceDidWakeNotification, - None) - else: - logger.warning(("No system sleep monitor implemented for '%s'" - % platform.system())) - diff -r e8773133bf79 -r 83b43987e61e ui.py --- a/ui.py Sun Jan 28 11:01:45 2018 +0000 +++ b/ui.py Sun Jan 28 11:04:52 2018 +0000 @@ -8,7 +8,7 @@ import logging import borgend import backup -import sleep +import dreamtime from threading import Lock, Timer from config import settings import objc @@ -173,7 +173,7 @@ self.__status_callback(_index, status, errorlog=errors)) backups[index].set_status_update_callback(cb) - sleep.add_callback(self, self.refresh_ui) + dreamtime.add_callback(self, self.refresh_ui) def __rebuild_menu(self): menu=[]