# Socket.IO Module

Real-time WebSocket communication for active game sessions.

## Architecture

```
Client <--WebSocket--> Socket.IO Server <--> GameService <--> GameEngine
                            |
                            v
                      ConnectionManager <--> Redis (presence tracking)
```

## Components

| Component | Responsibility | DI Pattern |
|-----------|---------------|------------|
| `server.py` | Socket.IO server setup, event handlers | Uses `auth_handler` |
| `auth.py` | `AuthHandler` class for JWT authentication | `token_verifier`, `conn_manager` |

## AuthHandler

Handles JWT-based authentication with injectable dependencies:

```python
class AuthHandler:
    def __init__(
        self,
        token_verifier: TokenVerifier | None = None,  # Callable[[str], UUID | None]
        conn_manager: ConnectionManager | None = None,
    ) -> None:
        self._token_verifier = token_verifier or verify_access_token
        self._connection_manager = conn_manager or connection_manager

# Global singleton for production
auth_handler = AuthHandler()

# Tests inject mocks via constructor
handler = AuthHandler(
    token_verifier=lambda token: user_id,
    conn_manager=mock_connection_manager,
)
```

### Methods

| Method | Purpose |
|--------|---------|
| `authenticate_connection(sid, auth)` | Validate JWT, return `AuthResult` |
| `setup_authenticated_session(sio, sid, user_id)` | Save session, register connection |
| `cleanup_authenticated_session(sid)` | Unregister connection, return user_id |

## Event Handlers

All handlers are in the `/game` namespace:

| Event | Direction | Purpose |
|-------|-----------|---------|
| `connect` | Client→Server | Authenticate and establish session |
| `disconnect` | Client→Server | Clean up session and notify opponent |
| `game:join` | Client→Server | Join/rejoin a game session |
| `game:action` | Client→Server | Execute a game action |
| `game:resign` | Client→Server | Resign from game |
| `game:heartbeat` | Client→Server | Keep connection alive |

## Client Connection

```javascript
const socket = io("wss://api.example.com", {
    auth: { token: "JWT_ACCESS_TOKEN" }
});

socket.on("connect", () => {
    socket.emit("game:join", { game_id: "uuid" });
});

socket.on("game:state", (state) => {
    // Full game state update
});

socket.on("auth_error", (error) => {
    // { code: "invalid_token", message: "..." }
});
```

## Testing

Use dependency injection - no monkey patching:

```python
@pytest.fixture
def mock_token_verifier():
    return MagicMock(return_value=uuid4())

@pytest.fixture
def mock_connection_manager():
    cm = AsyncMock()
    cm.register_connection = AsyncMock()
    return cm

@pytest.fixture
def auth_handler(mock_token_verifier, mock_connection_manager):
    return AuthHandler(
        token_verifier=mock_token_verifier,
        conn_manager=mock_connection_manager,
    )

async def test_authenticate_success(auth_handler, mock_token_verifier):
    """Test successful authentication with valid JWT."""
    result = await auth_handler.authenticate_connection("sid", {"token": "valid"})
    assert result.success
    mock_token_verifier.assert_called_once_with("valid")
```

## See Also

- `app/services/connection_manager.py` - Connection presence tracking
- `app/services/game_service.py` - Game orchestration
- `app/schemas/ws_messages.py` - WebSocket message schemas
- `CLAUDE.md` - Architecture guidelines
