init
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
import socketio
|
||||
|
||||
from app.models.database import async_session_maker
|
||||
from app.models.orm import Character, Clue, Message, Vote
|
||||
from app.models.schemas import GamePhase
|
||||
from app.services.agent_scheduler import agent_scheduler
|
||||
from app.services.game_state_manager import game_state_manager
|
||||
from sqlalchemy import select
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
sio = socketio.AsyncServer(
|
||||
async_mode="asgi",
|
||||
cors_allowed_origins="*",
|
||||
logger=False,
|
||||
)
|
||||
|
||||
connected_clients: dict[str, dict] = {}
|
||||
_tracked_tasks: set[asyncio.Task] = set()
|
||||
|
||||
|
||||
@sio.event
|
||||
async def connect(sid, environ, auth):
|
||||
connected_clients[sid] = {"sid": sid, "role": "viewer"}
|
||||
await sio.emit("system", {"message": "Connected to Hermes Live Show"}, to=sid)
|
||||
|
||||
|
||||
@sio.event
|
||||
async def disconnect(sid):
|
||||
connected_clients.pop(sid, None)
|
||||
|
||||
|
||||
@sio.event
|
||||
async def set_role(sid, data):
|
||||
if sid in connected_clients:
|
||||
connected_clients[sid]["role"] = data.get("role", "viewer")
|
||||
|
||||
|
||||
@sio.event
|
||||
async def send_message(sid, data):
|
||||
character_id = data.get("character_id")
|
||||
content = data.get("content", "")
|
||||
msg_type = data.get("msg_type", "character")
|
||||
game_phase = data.get("game_phase", "")
|
||||
target_character_id = data.get("target_character_id")
|
||||
|
||||
if async_session_maker:
|
||||
async with async_session_maker() as session:
|
||||
msg = Message(
|
||||
character_id=character_id,
|
||||
game_phase=game_phase,
|
||||
msg_type=msg_type,
|
||||
content=content,
|
||||
target_character_id=target_character_id,
|
||||
)
|
||||
session.add(msg)
|
||||
await session.commit()
|
||||
|
||||
await sio.emit("new_message", {
|
||||
"character_id": character_id,
|
||||
"content": content,
|
||||
"msg_type": msg_type,
|
||||
"game_phase": game_phase,
|
||||
"target_character_id": target_character_id,
|
||||
})
|
||||
|
||||
|
||||
@sio.event
|
||||
async def dm_command(sid, data):
|
||||
command = data.get("command", "")
|
||||
args = data.get("args", {})
|
||||
|
||||
if async_session_maker:
|
||||
async with async_session_maker() as session:
|
||||
if command == "next_phase":
|
||||
state = await game_state_manager.next_phase(session)
|
||||
await sio.emit("state_change", {
|
||||
"phase": state.current_phase,
|
||||
"progress": game_state_manager.get_progress_percent(state),
|
||||
})
|
||||
|
||||
elif command == "prev_phase":
|
||||
state = await game_state_manager.prev_phase(session)
|
||||
await sio.emit("state_change", {
|
||||
"phase": state.current_phase,
|
||||
"progress": game_state_manager.get_progress_percent(state),
|
||||
})
|
||||
|
||||
elif command == "unlock_clue":
|
||||
clue_id = args.get("clue_id")
|
||||
character_id = args.get("character_id")
|
||||
if clue_id and character_id:
|
||||
result = await session.execute(select(Clue).where(Clue.id == clue_id))
|
||||
clue = result.scalars().first()
|
||||
if clue:
|
||||
clue.is_unlocked = True
|
||||
clue.unlocked_by = character_id
|
||||
clue.unlocked_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await sio.emit("clue_unlocked", {
|
||||
"clue_id": clue.id,
|
||||
"clue_name": clue.name,
|
||||
"content": clue.content,
|
||||
"unlocked_by": character_id,
|
||||
})
|
||||
|
||||
elif command == "start_auto":
|
||||
state = await game_state_manager.get_state(session)
|
||||
script_id = args.get("script_id") or (state.active_script_id if state else None)
|
||||
if script_id:
|
||||
interval = float(args.get("interval", 8.0))
|
||||
rounds = int(args.get("rounds", 1))
|
||||
|
||||
async def emit(event, data):
|
||||
await sio.emit(event, data)
|
||||
|
||||
task = asyncio.create_task(
|
||||
agent_scheduler.run_auto_speaking(session, script_id, interval, rounds, emit)
|
||||
)
|
||||
_tracked_tasks.add(task)
|
||||
task.add_done_callback(_tracked_tasks.discard)
|
||||
await sio.emit("system", {"message": "Auto speaking started"})
|
||||
|
||||
elif command == "stop_auto":
|
||||
agent_scheduler.stop()
|
||||
await sio.emit("system", {"message": "Auto speaking stopped"})
|
||||
|
||||
elif command == "trigger_vote":
|
||||
state = await game_state_manager.get_state(session)
|
||||
script_id = args.get("script_id") or (state.active_script_id if state else None)
|
||||
if script_id:
|
||||
async def emit(event, data):
|
||||
await sio.emit(event, data)
|
||||
|
||||
votes = await agent_scheduler.trigger_voting(session, script_id, emit)
|
||||
|
||||
current_state = await game_state_manager.get_or_create_state(session)
|
||||
round_num = current_state.round_number if hasattr(current_state, 'round_number') else 1
|
||||
for v in votes:
|
||||
session.add(Vote(
|
||||
voter_id=v["voter_id"],
|
||||
target_id=v["target_id"],
|
||||
round_number=round_num,
|
||||
reason=v.get("reason", ""),
|
||||
))
|
||||
await session.commit()
|
||||
|
||||
await sio.emit("voting_results", {"votes": votes})
|
||||
|
||||
|
||||
@sio.event
|
||||
async def request_state(sid, data):
|
||||
if async_session_maker:
|
||||
async with async_session_maker() as session:
|
||||
state = await game_state_manager.get_or_create_state(session)
|
||||
await sio.emit("state_change", {
|
||||
"phase": state.current_phase,
|
||||
"progress": game_state_manager.get_progress_percent(state),
|
||||
"is_running": state.is_running,
|
||||
"is_paused": state.is_paused,
|
||||
}, to=sid)
|
||||
|
||||
|
||||
def create_socket_app(app):
|
||||
return socketio.ASGIApp(sio, other_app=app)
|
||||
Reference in New Issue
Block a user