mirror of
https://github.com/samjage/metro-warden.git
synced 2026-06-06 01:00:41 +00:00
89 lines
2.3 KiB
Python
89 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Metro Warden — entry point.
|
|
|
|
Usage:
|
|
python main.py [--debug] [--log-file PATH]
|
|
|
|
The application reads config/defaults.toml on startup and can be
|
|
overridden via CLI flags.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import logging
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def _configure_logging(level: str, log_file: str) -> None:
|
|
fmt = "%(asctime)s %(levelname)-8s %(name)s %(message)s"
|
|
handlers: list[logging.Handler] = [logging.StreamHandler(sys.stderr)]
|
|
if log_file:
|
|
handlers.append(logging.FileHandler(log_file))
|
|
logging.basicConfig(level=getattr(logging, level.upper(), logging.INFO), format=fmt, handlers=handlers)
|
|
|
|
|
|
def _parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(
|
|
prog="metro-warden",
|
|
description="Metro Warden — Industrial Dark Network Operations Centre",
|
|
)
|
|
parser.add_argument(
|
|
"--debug",
|
|
action="store_true",
|
|
help="Enable DEBUG log level",
|
|
)
|
|
parser.add_argument(
|
|
"--log-file",
|
|
default="",
|
|
metavar="PATH",
|
|
help="Write logs to this file in addition to stderr",
|
|
)
|
|
parser.add_argument(
|
|
"--config",
|
|
default="",
|
|
metavar="PATH",
|
|
help="Path to TOML config file (default: config/defaults.toml)",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def _load_config(path: str) -> dict:
|
|
config_path = Path(path) if path else Path(__file__).parent / "config" / "defaults.toml"
|
|
if not config_path.exists():
|
|
return {}
|
|
try:
|
|
import toml
|
|
return toml.loads(config_path.read_text())
|
|
except Exception as exc:
|
|
logging.warning("could not load config %s: %s", config_path, exc)
|
|
return {}
|
|
|
|
|
|
def main() -> None:
|
|
args = _parse_args()
|
|
log_level = "DEBUG" if args.debug else "INFO"
|
|
_configure_logging(log_level, args.log_file)
|
|
|
|
raw_config = _load_config(args.config)
|
|
|
|
# Flatten config sections into state-key style for the app
|
|
config: dict = {}
|
|
polling = raw_config.get("polling", {})
|
|
display = raw_config.get("display", {})
|
|
for k, v in polling.items():
|
|
config[f"settings.{k}"] = v
|
|
for k, v in display.items():
|
|
config[f"settings.{k}"] = v
|
|
|
|
from core.app import MetroWarden
|
|
|
|
app = MetroWarden(config=config)
|
|
app.run()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|