mud_server.api.server

FastAPI backend server for the MUD.

This module initializes and configures the FastAPI application that serves as the backend API for the Multi-User Dungeon (MUD) game. It sets up: - CORS middleware for cross-origin requests from the admin WebUI - The game engine instance that handles all game logic - All API route endpoints for player actions and admin functions

The server runs on port 8000 by default and accepts connections from any host to allow network access from other machines. If the default port is in use, the server will automatically find an available port in the 8000-8099 range.

Configuration:

Server settings are loaded from config/server.ini with environment variable overrides. See mud_server.config for details.

Key environment variables:

MUD_HOST: Network interface to bind to MUD_PORT: Port number MUD_PRODUCTION: Enable production mode MUD_CORS_ORIGINS: Comma-separated allowed origins

Attributes

SERVICE_LOG_LABEL

docs_url

redoc_url

app

engine

DEFAULT_PORT

PORT_RANGE_START

PORT_RANGE_END

Functions

lifespan(app)

Handle server startup and shutdown tasks.

is_port_available(port[, host])

Check if a TCP port is available for binding on the specified host.

find_available_port([preferred_port, host, ...])

Find an available TCP port, starting with the preferred port.

start_server([host, port, auto_discover])

Start the MUD API server with configurable host and port.

Module Contents

mud_server.api.server.SERVICE_LOG_LABEL = 'mud-server'
async mud_server.api.server.lifespan(app)[source]

Handle server startup and shutdown tasks.

Startup:
  • Clears any stale sessions from previous runs to ensure a clean state.

  • These may exist if the server crashed or was killed without proper shutdown.

Shutdown:
  • Currently no cleanup needed (sessions cleared on next startup).

mud_server.api.server.docs_url = '/docs'
mud_server.api.server.redoc_url = '/redoc'
mud_server.api.server.app
mud_server.api.server.engine
mud_server.api.server.DEFAULT_PORT = 8000
mud_server.api.server.PORT_RANGE_START = 8000
mud_server.api.server.PORT_RANGE_END = 8099
mud_server.api.server.is_port_available(port, host='0.0.0.0')[source]

Check if a TCP port is available for binding on the specified host.

This function attempts to bind a socket to the given host:port combination. If the bind succeeds, the port is available. If it fails with OSError (typically EADDRINUSE), the port is already in use.

Technical Details:
  • Uses a TCP socket (SOCK_STREAM) for the check

  • Sets SO_REUSEADDR to handle TIME_WAIT state from recently closed sockets

  • The socket is automatically closed via context manager

  • Works correctly even if another process is listening on a different interface (e.g., 127.0.0.1 vs 0.0.0.0)

Parameters:
  • port (int) – TCP port number to check (1-65535)

  • host (str) – Host interface to check. Common values: - “0.0.0.0”: All interfaces (default, most common) - “127.0.0.1”: Localhost only - Specific IP: Check only that interface

Returns:

True if the port is available for binding, False otherwise

Return type:

bool

Example

>>> is_port_available(8000)
True  # Port 8000 is free
>>> is_port_available(80)
False  # Port 80 likely in use by web server
mud_server.api.server.find_available_port(preferred_port=DEFAULT_PORT, host='0.0.0.0', range_start=PORT_RANGE_START, range_end=PORT_RANGE_END)[source]

Find an available TCP port, starting with the preferred port.

This function implements a simple port scanning algorithm: 1. First, try the preferred port (most common case - it’s usually free) 2. If unavailable, scan sequentially through the range 3. Skip the preferred port during the scan (already tried)

The sequential scan ensures deterministic behavior - given the same system state, you’ll always get the same port. This is important for automated testing and reproducible deployments.

Parameters:
  • preferred_port (int) – The first port to try. Defaults to 8000. This is typically the user-configured or default port.

  • host (str) – Host interface to check availability on. Defaults to “0.0.0.0” (all interfaces). Use “127.0.0.1” for localhost-only binding.

  • range_start (int) – First port in the scan range (inclusive). Defaults to 8000.

  • range_end (int) – Last port in the scan range (inclusive). Defaults to 8099.

Returns:

An available port number within the range None: If no ports are available in the entire range

Return type:

int

Example

>>> # Normal case - preferred port is available
>>> find_available_port(8000)
8000
>>> # Preferred port in use - finds next available
>>> find_available_port(8000)  # 8000 in use
8001
>>> # All ports in use (unusual)
>>> find_available_port(8000)  # 8000-8099 all in use
None

Note

There’s a small race condition between checking and binding. Another process could grab the port between our check and the actual server startup. This is acceptable for development servers but should be handled in production deployments.

mud_server.api.server.start_server(host=None, port=None, auto_discover=True)[source]

Start the MUD API server with configurable host and port.

This is the main entry point for running the FastAPI backend server. It handles configuration resolution from multiple sources and implements automatic port discovery when the preferred port is unavailable.

Configuration Resolution Order:

For both host and port, configuration is resolved in this priority: 1. Explicit function parameter (highest priority) 2. Environment variable (MUD_HOST, MUD_PORT) 3. Config file (config/server.ini) 4. Default value (0.0.0.0:8000)

This allows flexible deployment: developers can use defaults, CI/CD can use environment variables, and CLI users can specify exact values.

Auto-Discovery Behavior:

When auto_discover=True (default): - If the configured port is in use, scans 8000-8099 for an available port - Prints a message when using an alternate port - Raises RuntimeError only if ALL ports in the range are unavailable

When auto_discover=False: - Fails immediately with OSError if port is unavailable - Useful when you need a specific port (e.g., load balancer config)

Parameters:
  • host (str | None) – Network interface to bind to. Common values: - None: Use config/env var, or “0.0.0.0” (all interfaces) - “0.0.0.0”: Accept connections from any network interface - “127.0.0.1”: Accept only local connections (localhost) - Specific IP: Bind to a specific network interface

  • port (int | None) – TCP port number to listen on. Values: - None: Use config/env var, or 8000 - Integer: Use this specific port (subject to auto_discover)

  • auto_discover (bool) – Enable automatic port discovery. Defaults to True. Set to False for production deployments where port must be exact.

Raises:
  • RuntimeError – When auto_discover=True but no port is available in the 8000-8099 range. This is unusual and indicates a serious system configuration issue.

  • OSError – When auto_discover=False and the specified port is in use. The error message will include details about the conflict.

Example

# Default configuration (most common) start_server() # Uses 0.0.0.0:8000 with auto-discovery

# Explicit port for development start_server(port=9000) # Uses 0.0.0.0:9000

# Production deployment (fail if port unavailable) start_server(port=8000, auto_discover=False)

# Local development only start_server(host=”127.0.0.1”)

Note

This function blocks until the server is stopped (Ctrl+C or signal). It should typically be called in the main thread or a dedicated process.