diff --git a/README.md b/README.md index e488dee..019022e 100644 --- a/README.md +++ b/README.md @@ -1,206 +1,75 @@ -# PurrLobby 🐱 +# PurrLobby -A lightweight, fast, and reliable lobby service for multiplayer games. PurrLobby provides an alternative to Steam Lobby Service and Unity Lobby Service, offering real-time lobby management with WebSocket communication. +Lightweight, fast lobby service for [PurrNet](https://github.com/PurrNet/PurrNet) multiplayer games. Alternative to Steam or Unity lobby lobby services. -## 🌟 Features +## Implementation Overview -- **Multi-Game Support**: Scope lobbies per game using unique Game IDs -- **Real-time Updates**: WebSocket-based live lobby updates and member status changes -- **Player Management**: Join/leave lobbies, ready status, custom display names -- **Custom Properties**: Store arbitrary key-value data on lobbies -- **Search & Discovery**: Find available lobbies with filtering -- **Rate Limiting**: Built-in protection against abuse (300 requests/minute per IP) -- **Statistics**: Global and per-game player/lobby statistics -- **Production Ready**: Includes compression, HTTPS, security headers, and proxy support -- **Web Interface**: Built-in dashboard for monitoring and testing -- **OpenAPI/Swagger**: Full API documentation with interactive testing +* **Multi-game scoping**: Each game has isolated lobbies via Game ID +* **Real-time WebSocket events**: member join/leave, ready status, lobby data updates +* **Custom lobby properties**: Store arbitrary key-value data per lobby +* **Built-in stats**: Global & per-game player/lobby counts +* **Rate limiting**: Protects against abuse by default +* **Web dashboard + Swagger**: Monitor lobbies and test API -## 🚀 Quick Start +## Quick Start -### Prerequisites - -- [.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) -- Windows, macOS, or Linux - -### Installation & Running - -1. Clone the repository: ```bash git clone https://github.com/ExilProductions/PurrLobby.git cd PurrLobby -``` - -2. Build the project: -```bash dotnet build -``` - -3. Run the service: -```bash -cd PurrLobby dotnet run ``` -4. Access the web interface: [https://localhost:7225](https://localhost:7225) -5. View API documentation: [https://localhost:7225/swagger](https://localhost:7225/swagger) +Dashboard: [https://purrlobby.exil.dev](https://purrlobby.exil.dev) +API docs: [https://purrlobby.exil.dev/swagger](https://purrlobby.exil.dev/swagger) -## 🔧 Configuration +## Configuration -### Environment Variables +* `ASPNETCORE_ENVIRONMENT=Production` +* `ASPNETCORE_URLS=https://localhost:7225;http://localhost:5123` +* Cookie domain (production): `Program.cs → Domain = "your-domain.com"` -Configure the service using `appsettings.json` or environment variables: +## API Essentials -- `ASPNETCORE_ENVIRONMENT`: Set to `Production` for production deployment -- `ASPNETCORE_URLS`: Configure listening URLs (default: `https://localhost:7225;http://localhost:5123`) - -### Domain Configuration - -For production deployment, update the cookie domain in `Program.cs`: -```csharp -Domain = "your-domain.com" // Line 134 -``` - -### Rate Limiting - -Default rate limits (configurable in `Program.cs`): -- **300 requests per minute** per IP address -- **100 queued requests** per IP -- Returns `429 Too Many Requests` when exceeded - -## 📚 API Usage - -### 1. Set Game Context - -Before using lobby endpoints, set your game's GUID: +Set game context (required): ```bash curl -X POST "https://your-domain.com/session/game" \ - -H "Content-Type: application/json" \ - -d '{"gameId": "your-game-guid-here"}' +-H "Content-Type: application/json" \ +-d '{"gameId":"your-game-guid"}' ``` -This sets a secure cookie that scopes all subsequent requests to your game. - -### 2. Create a Lobby +Create a lobby: ```bash curl -X POST "https://your-domain.com/lobbies" \ - -H "Content-Type: application/json" \ - -H "Cookie: gameId=your-game-guid" \ - -d '{ - "ownerUserId": "player123", - "ownerDisplayName": "PlayerName", - "maxPlayers": 4, - "properties": { - "gameMode": "competitive", - "map": "dust2" - } - }' +-H "Content-Type: application/json" \ +-H "Cookie: gameId=your-game-guid" \ +-d '{"ownerUserId":"player1","ownerDisplayName":"Player","maxPlayers":4,"properties":{"mode":"casual"}}' ``` -### 3. Search Lobbies +Join/search lobbies using `/lobbies/{id}/join` and `/lobbies/search`. -```bash -curl "https://your-domain.com/lobbies/search?maxRoomsToFind=10" \ - -H "Cookie: gameId=your-game-guid" -``` - -### 4. Join a Lobby - -```bash -curl -X POST "https://your-domain.com/lobbies/{lobbyId}/join" \ - -H "Content-Type: application/json" \ - -H "Cookie: gameId=your-game-guid" \ - -d '{ - "userId": "player456", - "displayName": "AnotherPlayer" - }' -``` - -### 5. WebSocket Connection for Real-time Updates - -Connect to lobby-specific WebSocket for live updates: +**WebSocket** (live updates): ```javascript const ws = new WebSocket(`wss://your-domain.com/ws/lobbies/${lobbyId}?userId=${userId}`); - -ws.onmessage = function(event) { - const data = JSON.parse(event.data); - console.log('Lobby update:', data); - // Handle events: member_joined, member_left, member_ready, lobby_data, etc. -}; +ws.onmessage = e => console.log(JSON.parse(e.data)); ``` -## 🌐 Web Interface +## Deployment -The service includes a web dashboard at the root URL featuring: +**Docker** -- **Global Statistics**: Total players and lobbies across all games -- **Game-Specific Stats**: Players and lobbies for your specific game -- **Game ID Management**: Easy way to set and track your game -- **Direct API Access**: Links to Swagger documentation - -## 📊 Monitoring & Statistics - -### Global Statistics -- `GET /stats/global/players` - Total players across all games -- `GET /stats/global/lobbies` - Total lobbies across all games - -### Game-Specific Statistics -- `GET /stats/{gameId}/players` - Active players for a specific game -- `GET /stats/{gameId}/lobbies` - Lobby count for a specific game - -### Health Check -- `GET /health` - Service health status - -## 🏗️ Architecture - -### Components - -- **Program.cs**: Main application configuration and API endpoints -- **LobbyService**: Core business logic for lobby management -- **LobbyEventHub**: WebSocket connection management and real-time events -- **Lobby Models**: Data structures for lobbies and users - -### Key Features Implementation - -- **Cookie-based Game Scoping**: Uses secure HTTP-only cookies for game context -- **In-Memory Storage**: Fast performance with concurrent collections -- **Event-Driven Updates**: Real-time WebSocket notifications for all lobby changes -- **Production Security**: Rate limiting, HTTPS enforcement, proxy header trust -- **Comprehensive Logging**: HTTP request logging and structured application logs - -## 🚢 Deployment - -### Docker (Recommended) - -Create a `Dockerfile`: ```dockerfile -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app -EXPOSE 80 -EXPOSE 443 - -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build -WORKDIR /src -COPY ["PurrLobby/PurrLobby.csproj", "PurrLobby/"] -RUN dotnet restore "PurrLobby/PurrLobby.csproj" +EXPOSE 80 443 COPY . . -WORKDIR "/src/PurrLobby" -RUN dotnet build "PurrLobby.csproj" -c Release -o /app/build - -FROM build AS publish -RUN dotnet publish "PurrLobby.csproj" -c Release -o /app/publish - -FROM base AS final -WORKDIR /app -COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "PurrLobby.dll"] +ENTRYPOINT ["dotnet","PurrLobby.dll"] ``` -### Reverse Proxy Configuration - -For production deployment behind a reverse proxy (nginx, Apache, etc.), ensure proper header forwarding for rate limiting and security: +**Reverse Proxy (nginx)** ```nginx proxy_set_header X-Real-IP $remote_addr; @@ -209,145 +78,10 @@ proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; ``` -## 🔌 Client Integration Examples +## Contributing -### Unity C# -```csharp -public async Task CreateLobby(string gameId, string userId, string displayName) -{ - var client = new HttpClient(); - - // Set game context - await client.PostAsync($"{baseUrl}/session/game", - new StringContent($"{{\"gameId\": \"{gameId}\"}}", Encoding.UTF8, "application/json")); - - // Create lobby - var lobbyData = new { - ownerUserId = userId, - ownerDisplayName = displayName, - maxPlayers = 4, - properties = new { gameMode = "casual" } - }; - - var response = await client.PostAsync($"{baseUrl}/lobbies", - new StringContent(JsonUtility.ToJson(lobbyData), Encoding.UTF8, "application/json")); - - return response.IsSuccessStatusCode; -} -``` +Fork → branch → PR. Use tests & pass code analysis. Report issues on GitHub. -### JavaScript/Web -```javascript -class PurrLobbyClient { - constructor(baseUrl, gameId) { - this.baseUrl = baseUrl; - this.gameId = gameId; - } - - async setGameContext() { - await fetch(`${this.baseUrl}/session/game`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - credentials: 'include', - body: JSON.stringify({ gameId: this.gameId }) - }); - } - - async createLobby(userId, displayName, maxPlayers = 4) { - const response = await fetch(`${this.baseUrl}/lobbies`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - credentials: 'include', - body: JSON.stringify({ - ownerUserId: userId, - ownerDisplayName: displayName, - maxPlayers: maxPlayers, - properties: {} - }) - }); - return response.json(); - } -} -``` +## License -## 🛠️ Development - -### Building from Source -```bash -# Clone repository -git clone https://github.com/ExilProductions/PurrLobby.git -cd PurrLobby - -# Restore dependencies and build -dotnet restore -dotnet build - -# Run with hot reload for development -cd PurrLobby -dotnet watch run -``` - -### Running Tests -```bash -dotnet test -``` - -### Code Analysis -The project includes code analysis rules. Fix any warnings before deploying: -```bash -dotnet build --verbosity normal -``` - -## 📝 API Reference - -Full API documentation is available via Swagger UI when the service is running: -- **Local**: [https://localhost:7225/swagger](https://localhost:7225/swagger) -- **Production**: `https://your-domain.com/swagger` - -### Authentication -Most endpoints require a `gameId` cookie set via `POST /session/game`. The cookie: -- Is HTTP-only and secure -- Expires after 7 days -- Scopes all requests to your specific game - -### WebSocket Events -The lobby WebSocket (`/ws/lobbies/{lobbyId}`) broadcasts these events: -- `member_joined` - New player joined -- `member_left` - Player left lobby -- `member_ready` - Player readiness changed -- `lobby_data` - Custom lobby property updated -- `lobby_deleted` - Lobby was deleted - -## 🤝 Contributing - -This is an independent project by ExilProductions, not affiliated with PurrNet. - -### Issues & Support -- For bugs or feature requests, open an issue on GitHub -- For direct support, contact: **exil_s** on Discord -- Please don't contact PurrNet developers about this service - -### Development Guidelines -1. Fork the repository -2. Create a feature branch -3. Make your changes with appropriate tests -4. Ensure code analysis passes -5. Submit a pull request - -## ⚠️ Disclaimer - -This service is independent and runs on personal infrastructure. It may experience downtime or instability. It's provided as-is for development and testing purposes. For production use, consider self-hosting or implementing additional redundancy. - -## 📄 License - -This project is open source. Check the repository for license details. - -## 🔗 Links - -- **Live Instance**: [https://purrlobby.exil.dev](https://purrlobby.exil.dev) -- **API Documentation**: [https://purrlobby.exil.dev/swagger](https://purrlobby.exil.dev/swagger) -- **GitHub Repository**: [https://github.com/ExilProductions/PurrLobby](https://github.com/ExilProductions/PurrLobby) - ---- - -Made with 💜 by ExilProductions \ No newline at end of file +MIT