cleanup: remove ONIModTutorial (unrelated), merge skills/oni_agent.md into SKILL.md, move event_daemon.py to tools/
This commit is contained in:
97
tools/event_daemon.py
Normal file
97
tools/event_daemon.py
Normal file
@ -0,0 +1,97 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user