Full implementation from spec: ZNC/IRC client with TLS, Ollama LLM backend, per-user SQLite conversation memory, and Flask web admin portal with 7 pages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
2.0 KiB
Python
69 lines
2.0 KiB
Python
import json
|
|
import logging
|
|
import os
|
|
import signal
|
|
import socket
|
|
import sys
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CONFIG_PATH = "config/config.json"
|
|
PID_PATH = "data/ircbot.pid"
|
|
SOCK_PATH = "data/ircbot.sock"
|
|
|
|
|
|
def load_config() -> dict:
|
|
if not os.path.exists(CONFIG_PATH):
|
|
return {}
|
|
with open(CONFIG_PATH, "r") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def save_config(cfg: dict) -> None:
|
|
os.makedirs("config", exist_ok=True)
|
|
with open(CONFIG_PATH, "w") as f:
|
|
json.dump(cfg, f, indent=2)
|
|
logger.info("[CONFIG] Saved config.json")
|
|
|
|
|
|
def signal_bot_reload() -> bool:
|
|
"""Signal bot to reload config. Returns True on success."""
|
|
# Try Unix socket first (Docker mode)
|
|
if sys.platform != "win32" and os.path.exists(SOCK_PATH):
|
|
try:
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
s.connect(SOCK_PATH)
|
|
s.sendall(b"RELOAD")
|
|
s.close()
|
|
logger.info("[CONFIG] Sent RELOAD via Unix socket")
|
|
return True
|
|
except Exception as e:
|
|
logger.warning(f"[CONFIG] Socket reload failed: {e}")
|
|
|
|
# Fall back to SIGHUP
|
|
if sys.platform != "win32" and os.path.exists(PID_PATH):
|
|
try:
|
|
with open(PID_PATH) as f:
|
|
pid = int(f.read().strip())
|
|
os.kill(pid, signal.SIGHUP)
|
|
logger.info(f"[CONFIG] Sent SIGHUP to PID {pid}")
|
|
return True
|
|
except Exception as e:
|
|
logger.warning(f"[CONFIG] SIGHUP failed: {e}")
|
|
|
|
logger.warning("[CONFIG] Could not signal bot (no socket or PID available)")
|
|
return False
|
|
|
|
|
|
def signal_bot_reconnect() -> bool:
|
|
if sys.platform != "win32" and os.path.exists(SOCK_PATH):
|
|
try:
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
s.connect(SOCK_PATH)
|
|
s.sendall(b"RECONNECT")
|
|
s.close()
|
|
return True
|
|
except Exception as e:
|
|
logger.warning(f"[CONFIG] Reconnect signal failed: {e}")
|
|
return False
|