98 lines
3.2 KiB
Python
98 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
ONI Agent Event Daemon
|
|
======================
|
|
Continuous event poller. Polls game events every N seconds and displays
|
|
critical/warning/info events to the console (for AI input stream).
|
|
|
|
Usage:
|
|
python event_daemon.py [interval_seconds]
|
|
"""
|
|
|
|
import json, os, sys, time, datetime
|
|
|
|
TOOLS_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'tools')
|
|
sys.path.insert(0, TOOLS_DIR)
|
|
|
|
from oni_api import api_get, api_post, load_config
|
|
|
|
POLL_INTERVAL = 5
|
|
MAX_EVENTS = 200
|
|
|
|
class EventHistory:
|
|
def __init__(self, maxlen=200):
|
|
self.events = []
|
|
self.maxlen = maxlen
|
|
self.last_seq = -1
|
|
self.stats = {"critical": 0, "warning": 0, "info": 0}
|
|
|
|
def add(self, event):
|
|
self.events.append(event)
|
|
if len(self.events) > self.maxlen:
|
|
self.events.pop(0)
|
|
sev = event.get('severity', 'info')
|
|
self.stats[sev] = self.stats.get(sev, 0) + 1
|
|
|
|
def get_recent(self, n=10):
|
|
return self.events[-n:]
|
|
|
|
def main():
|
|
interval = int(sys.argv[1]) if len(sys.argv) > 1 else POLL_INTERVAL
|
|
history = EventHistory(MAX_EVENTS)
|
|
consecutive_errors = 0
|
|
|
|
print(f"[EventDaemon] Starting — poll interval {interval}s")
|
|
print(f"[EventDaemon] Config: {json.dumps(load_config())}")
|
|
|
|
while True:
|
|
try:
|
|
r = api_get(f'/api/state/events?since={history.last_seq}')
|
|
if not r.get("success"):
|
|
consecutive_errors += 1
|
|
if consecutive_errors > 3:
|
|
print(f"[EventDaemon] {consecutive_errors} consecutive errors — mod may be offline")
|
|
time.sleep(interval)
|
|
continue
|
|
|
|
consecutive_errors = 0
|
|
data = r.get("data", {})
|
|
events = data.get("events", [])
|
|
next_seq = data.get("nextSeq", history.last_seq)
|
|
|
|
for ev in events:
|
|
history.add(ev)
|
|
sev = ev.get('severity', 'info')
|
|
title = ev.get('title', '')
|
|
message = ev.get('message', '')
|
|
ts = ev.get('timestamp', 0)
|
|
dt = datetime.datetime.fromtimestamp(ts).strftime('%H:%M:%S') if ts else ''
|
|
|
|
if sev in ('critical', 'error'):
|
|
print(f"\n⚠️ [{dt}] CRITICAL: {title} {message}")
|
|
elif sev in ('warning',):
|
|
print(f"\n🟡 [{dt}] WARNING: {title} {message}")
|
|
else:
|
|
print(f"🔵 [{dt}] INFO: {title} {message}")
|
|
|
|
if events:
|
|
history.last_seq = next_seq
|
|
|
|
# Show summary every 30 seconds
|
|
if history.events and int(time.time()) % 30 < interval:
|
|
c = history.stats.get('critical', 0)
|
|
w = history.stats.get('warning', 0)
|
|
print(f"[EventDaemon] Stats | critical={c} warning={w} total={len(history.events)} | seq={history.last_seq}")
|
|
|
|
except KeyboardInterrupt:
|
|
print("\n[EventDaemon] Stopped")
|
|
break
|
|
except Exception as ex:
|
|
print(f"[EventDaemon] Error: {ex}")
|
|
time.sleep(interval)
|
|
continue
|
|
|
|
time.sleep(interval)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|