emmental/emmental/alarm.py

49 lines
1.3 KiB
Python

# Copyright 2023 (c) Anna Schumaker.
"""Functions for configuring a callback at a specific time."""
import datetime
import math
from gi.repository import GLib
_GSOURCE_MAPPING = dict()
_NEXT_ALARM_ID = 1
def _calc_seconds(time: datetime.time) -> int:
"""Calculate the number of seconds until the given time."""
now = datetime.datetime.now()
then = datetime.datetime.combine(now.date(), time)
if now >= then:
then += datetime.timedelta(days=1)
return math.ceil((then - now).total_seconds())
def __set_alarm(time: datetime.time, func: callable, alarm_id: int) -> None:
gsrcid = GLib.timeout_add_seconds(_calc_seconds(time), _do_alarm,
time, func, alarm_id)
_GSOURCE_MAPPING[alarm_id] = gsrcid
return alarm_id
def _do_alarm(time: datetime.time, func: callable, alarm_id: int) -> bool:
"""Run an alarm callback."""
func()
__set_alarm(time, func, alarm_id)
return GLib.SOURCE_REMOVE
def set_alarm(time: datetime.time, func: callable) -> int:
"""Register a callback to be called at a specific time."""
global _NEXT_ALARM_ID
res = __set_alarm(time, func, _NEXT_ALARM_ID)
_NEXT_ALARM_ID += 1
return res
def cancel_alarm(alarm_id: int) -> None:
"""Cancel an alarm."""
GLib.source_remove(_GSOURCE_MAPPING[alarm_id])
del _GSOURCE_MAPPING[alarm_id]