83 lines
2.6 KiB
Python
83 lines
2.6 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import datetime, timezone
|
|
|
|
from .config import Settings
|
|
from .engine import Notice, decide
|
|
from .fluxer_api import FluxerAPI, FluxerAPIError
|
|
from .notifiers import NotifierError, Message, build_notifiers
|
|
from .sources import SOURCES, Item
|
|
from .state import StateStore
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
KIND_PREFIX = {
|
|
"new": "New",
|
|
"reminder": "Still open",
|
|
"repeat": "Reminder",
|
|
"cleared": "Cleared",
|
|
}
|
|
|
|
|
|
def _to_message(notice: Notice, admin_ui_url: str) -> Message:
|
|
link = f"{admin_ui_url}{notice.path}" if notice.path else admin_ui_url
|
|
return Message(
|
|
title=f"{KIND_PREFIX[notice.kind]}: {notice.title}",
|
|
body=notice.detail,
|
|
link=link,
|
|
urgent=notice.urgent,
|
|
)
|
|
|
|
|
|
def run(settings: Settings, dry_run: bool = False) -> int:
|
|
api = FluxerAPI(settings.api_url, settings.api_key, settings.request_timeout)
|
|
now = datetime.now(timezone.utc)
|
|
failures = 0
|
|
checked: set[str] = set()
|
|
seen: dict[str, tuple[str, Item]] = {}
|
|
|
|
for source in SOURCES:
|
|
cfg = settings.sources[source.name]
|
|
if not cfg.enabled:
|
|
log.debug("%s: disabled", source.name)
|
|
continue
|
|
try:
|
|
items = source.fetch(api, cfg)
|
|
except FluxerAPIError as exc:
|
|
log.error("%s: %s", source.name, exc)
|
|
failures += 1
|
|
continue
|
|
checked.add(source.name)
|
|
log.info("%s: %d open", source.name, len(items))
|
|
for item in items:
|
|
seen[item.key] = (source.name, item)
|
|
|
|
store = StateStore(settings.state_file)
|
|
try:
|
|
known = store.load()
|
|
plan = decide(now, seen, known, checked, settings.realert, settings.notify_cleared)
|
|
messages = [_to_message(n, settings.admin_ui_url) for n in plan.notices]
|
|
|
|
if dry_run:
|
|
for message in messages:
|
|
log.info("would send: %s | %s | %s", message.title, message.body.replace("\n", " / "), message.link)
|
|
log.info("dry run: %d messages, %d state changes, nothing sent or saved", len(messages), len(plan.records))
|
|
return 1 if failures else 0
|
|
|
|
if messages:
|
|
try:
|
|
for notifier in build_notifiers(settings):
|
|
notifier.send(messages)
|
|
except NotifierError as exc:
|
|
log.error("%s; nothing was recorded, so these will be retried next run", exc)
|
|
return 1
|
|
log.info("sent %d messages", len(messages))
|
|
else:
|
|
log.info("nothing new to send")
|
|
|
|
store.save(plan.records)
|
|
finally:
|
|
store.close()
|
|
|
|
return 1 if failures else 0
|