e7c1a04 · Reload the map on SIGHUP · 5 days ago
1
"""Axiom scoped relay.2
3
Reads a channel-mapping markdown file (path or https URL), then:4
1. Listens on management channels (direction: in)5
2. Fans broadcasts into scoped rooms6
3. Collects replies and posts a report7
8
Scope is a wall. Channels not listed in the mapping are invisible.9
SIGHUP reloads the map without a restart.10
"""11
12
from __future__ import annotations13
14
import argparse15
import logging16
import signal17
import sys18
from pathlib import Path19
20
if __package__ is None:21
sys.path.insert(0, str(Path(__file__).resolve().parent))22
23
from discord_adapter import DiscordAdapter24
from mapping import load_mapping_from25
from report import format_report26
from scope import ScopeGuard27
from slack_adapter import SlackAdapter28
29
ADAPTERS = {30
"slack": SlackAdapter,31
"discord": DiscordAdapter,32
}33
34
35
class Runtime:36
def __init__(self, source: str, platform: str | None) -> None:37
self.source = source38
self.platform_override = platform39
self.reload()40
41
def reload(self) -> None:42
mapping = load_mapping_from(self.source)43
platform = self.platform_override or mapping.platform44
if platform not in ADAPTERS:45
raise SystemExit(f"unknown platform: {platform}")46
self.mapping = mapping47
self.platform = platform48
self.guard = ScopeGuard(mapping)49
self.adapter = ADAPTERS[platform](mapping, self.guard)50
logging.info("loaded scope=%s ids=%d", mapping.scope, len(mapping.ids()))51
52
53
def main(argv: list[str] | None = None) -> int:54
parser = argparse.ArgumentParser(prog="axiom-relay")55
parser.add_argument("--mapping", required=True, help="path or https URL")56
parser.add_argument("--platform", choices=sorted(ADAPTERS))57
parser.add_argument("--dry-run", action="store_true")58
parser.add_argument("--collect-seconds", type=int, default=None)59
args = parser.parse_args(argv)60
61
runtime = Runtime(args.mapping, args.platform)62
collect = args.collect_seconds or runtime.mapping.collect_seconds63
64
if args.dry_run:65
runtime.adapter.describe(sys.stdout)66
sys.stdout.write(format_report(67
mapping=runtime.mapping,68
guard=runtime.guard,69
broadcast_id=runtime.mapping.by_role("management")[0].id,70
reply_count=0,71
collect_seconds=collect,72
))73
return 074
75
if hasattr(signal, "SIGHUP"):76
signal.signal(signal.SIGHUP, lambda *_: runtime.reload())77
78
runtime.adapter.run(collect_seconds=collect)79
return 080
81
82
if __name__ == "__main__":83
raise SystemExit(main())84