monkeyscloud/monkeyslegion-sockets

High-performance, secure, and cluster-ready WebSocket architecture for the MonkeysLegion ecosystem. Features active liveness monitoring, distributed state management, and multi-driver support (Native, ReactPHP, Swoole).

Maintainers

Package info

github.com/MonkeysCloud/MonkeysLegion-Sockets

pkg:composer/monkeyscloud/monkeyslegion-sockets

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.1.1 2026-04-24 21:38 UTC

This package is auto-updated.

Last update: 2026-04-24 23:23:09 UTC


README

High-performance, secure, and cluster-ready WebSocket architecture for the MonkeysLegion framework. Designed for massive scalability, distributed state, and adversarial resilience.

πŸš€ Quick Setup

Install the package and publish the configuration:

composer require monkeyscloud/monkeyslegion-sockets

# Interactive installer for config and JS client assets
php ml socket:install

Starting the Cluster

# Start the production server
php ml socket:serve start

# Or specify host/port
php ml socket:serve start --host=0.0.0.0 --port=9000

πŸ› οΈ Usage Examples

Server-Side Broadcasting

Target dynamic user streams or rooms with ease:

// Broadcast to a specific user on all connected devices
$broadcaster->channel('User.{id}', ['id' => 42])->emit('message', [
    'text' => 'Hello Monkey!'
]);

// Broadcast to a room
$broadcaster->to('room:lobby')->emit('message', 'Hello Monkeys!');

Event Handling

Define your socket events in your service providers or controllers:

$server->on('message', function($connection, $message) {
    echo "Received: " . $message->getPayload();
});

πŸ“š Documentation

For exhaustive, professional documentation covering every layer of the architecture, please see the docs/ folder:

πŸ—οΈ Architectural Overview

MonkeysLegion Sockets is a "Pure Consumer" DI-oriented library that decouples the transport layer (TCP/WebSockets) from the application logic.

Core Components

  • Broadcaster: Handles signal distribution from the application to the WebSocket workers (via Redis Pub/Sub or Unix Socket IPC).
  • Registry: Manages distributed connection state (Tags, Rooms, Occupants). Supports Redis-backed clusters for multi-node deployments.
  • Drivers: Transport implementations (Native Stream, ReactPHP, Swoole).
  • Middleware: Handshake-level filtering (Authentication, Origin Check, Rate Limiting).

πŸ“Š Choosing the Right Driver

Selecting the right engine depends on your concurrency needs:

Driver Best For Pros Cons
Native Dev / Small App Zero dependencies, Pure PHP Blocking loop (High CPU)
React High Concurrency Asynchronous, Pure PHP Higher Memory
Swoole 50k+ Connections C-Extension Performance, Lowest Footprint Requires Swoole Ext

🏠 Public and Private Channels

MonkeysLegion Sockets provides a first-class, semantically clear system for managing communication groups.

🌍 Public Channels

Public channels are open to any connected client. Use them for global notifications, lobby chats, or public feeds.

// Server: Join a client to a public channel
$server->joinPublic($connection, 'lobby');

// Broadcast to a public channel
$broadcaster->publicChannel('lobby')->emit('announcement', 'Welcome!');

πŸ”’ Private Channels

Private channels require server-side authorization. Use them for sensitive data, one-to-one messaging, or restricted groups.

// Server: Join with authorization logic (Requires ChannelAuthorizerInterface)
$server->joinPrivate($connection, 'team-alpha', ['token' => '...']);

// Broadcast to a private channel
$broadcaster->privateChannel('team-alpha')->emit('covert_op', 'Go!');

πŸ‘₯ Presence Channels

A specialized type of private channel that tracks "Who's Online".

// Server: Join and get current occupants
$members = $server->joinPresence($connection, 'status-room');

// 1. Automatically emits 'presence:joined' to existing members
// 2. Returns an array of current members to the joiner

For more details on implementing security rules, see the Rooms and Channels Architecture guide.

πŸ”’ Security Hardening

  • Strict Liveness (Heartbeats): Proactive Ping/Pong cycles ensure the server reaps zombie clients and bypasses protocol-level tricks.
  • Backpressure Protection: Configurable write_buffer_size prevents memory exhaustion attacks.
  • Protocol Integrity: Rigid RFC 6455 enforcement; only valid WebSocket frames reset liveness timers.
  • CSWH Protection: Built-in AllowedOriginsMiddleware.

πŸ—οΈ Full Configuration Reference

The config/sockets.mlc file controls every aspect of your cluster. Below is the complete schema with default values:

sockets {
    # Transport driver: "stream", "swoole", or "react"
    driver ${WS_DRIVER:-stream},

    # State tracking: "local" or "redis"
    registry ${WS_REGISTRY:-local},

    # Pub/Sub strategy: "unix" (single-server) or "redis" (cluster)
    broadcast ${WS_BROADCAST:-redis},

    # Protocol Formatter: "json" or "msgpack"
    formatter ${WS_FORMATTER:-json},

    # Listening address and port
    host ${WS_HOST:-0.0.0.0},
    port ${WS_PORT:-8080},

    # Unix Socket path (required if broadcast is "unix")
    unix {
        path ${WS_UNIX_PATH:-/tmp/ml_sockets.sock},
    }

    # Low-level transport options
    options {
        # Maximum allowed WebSocket message size (Default: 10MB)
        max_message_size ${WS_MAX_MESSAGE_SIZE:-10485760},
        
        # Max outbound buffer per connection (Default: 5MB)
        write_buffer_size ${WS_WRITE_BUFFER_SIZE:-5242880},
        
        # Interval for active WebSocket Pings (Seconds)
        heartbeat_interval ${WS_HEARTBEAT_INTERVAL:-60},
    }

    # Handshake security
    security {
        # List of allowed domains for WebSocket handshakes (CSWH Protection)
        allowed_origins [
            "http://localhost:3000",
            "https://app.yoursite.com"
        ],
    }
}

πŸ“‘ Communication Life-Cycles

To master the MonkeysLegion ecosystem, it is essential to understand the "Hub and Spoke" model. The architecture distinguishes between Long-Lived listeners and Short-Lived emitters to ensure maximum performance.

1. Server-to-Server (The Internal Bridge)

This flow connects your application logic (e.g., a Controller, Command, or Job) to the WebSocket cluster.

  • The Listener (Always Live): When you run php ml socket:serve, the server starts a permanent loop. It keeps an "Eternal Ear" open to the Redis Pub/Sub or Unix Socket channel.
  • The Broadcaster (Flash Messenger): When your app calls $broadcaster->emit(), it "lives" for a few millisecondsβ€”just long enough to throw the message into the channelβ€”and then "dies" immediately.
  • Benefit: Your web request is never slowed down by the WebSocket delivery process. It's a "fire and forget" system.

2. Client-to-Server (The Upstream Flow)

Standard communication from the JS client to your backend logic.

  • The Flow: The MonkeysSocket JS client initiates a handshake and remains "Live" in the browser. When it emits an event, the server's Middleware validates the request and triggers your defined event handlers.
  • Liveness: Every message sent by the client resets the server-side "Heartbeat" timer, proving the connection is still active.

3. Client-to-Client (The Secure Relay)

Clients never talk directly to each other (P2P). Instead, the server acts as a secure Mediator.

  • The Process: Client A emits to the server. The server verifies the permissions, looks up Client B in the Registry, and "relays" the message.
  • Echo Logic: By default, the server broadcasts to "Everyone Else" (excluding the sender). This prevents "double-message" glitches in the sender's UI while ensuring the rest of the room is updated instantly.

πŸ“Š Summary Table

Flow Type Listener (Always Live) Emitter (Lives & Dies) Purpose
Server-to-Server Socket Server (Worker) App Broadcaster Pushing logic updates to users
Client-to-Server Socket Server (Worker) JS Client Sending user actions to backend
Client-to-Client Other Connected Clients The Sending Client Private messaging / Chat rooms

πŸ—οΈ Real-World Implementation Guide

Understanding which component to use and where to place your logic is key to a robust implementation.

🌲 The Architectural Tree

This map shows the hierarchy of responsibility within the system:

WebSocketServer (The Orchestrator)
β”œβ”€β”€ Handshake (Middleware Pipeline)
β”‚   └── Rejects unauthorized HTTP requests before they become WebSockets.
β”œβ”€β”€ Registry (State Manager)
β”‚   └── Tracks who is online and what tags they have.
β”œβ”€β”€ RoomManager (High-Level Logic)
β”‚   β”œβ”€β”€ Public (Open rooms)
β”‚   β”œβ”€β”€ Private (Authorized channels)
β”‚   └── Presence (Real-time occupant tracking)
└── Broadcaster (Distribution Bridge)
    β”œβ”€β”€ Local (Internal delivery to local workers)
    └── Global (Distributed delivery via Redis/Unix)

πŸš€ Full Implementation Scenario: Secure Team Chat

1. Define Authorization (The Policy)

Create a class that implements ChannelAuthorizerInterface to protect your channels.

class ChatAuthorizer implements ChannelAuthorizerInterface 
{
    public function authorize(ConnectionInterface $connection, string $channel, array $params = []): bool 
    {
        $userId = $connection->getMetadata()['user_id'] ?? null;
        
        // Example: Only members of Team 5 can join 'team-5'
        if (str_starts_with($channel, 'team-')) {
            $teamId = (int) substr($channel, 5);
            return $this->db->isMember($userId, $teamId);
        }
        
        return true; // Allow other channels
    }
}

πŸ’‘ Advanced: Authorization Pipelines

For complex applications, you can decouple your rules into a Pipeline. This allows you to split logic (e.g. Rate Limiting vs Database checks) into separate, reusable classes.

$pipeline = new AuthorizerPipeline();
$pipeline->addAuthorizer(new IpBlockerAuthorizer(), 100); // Check IP first (High priority)
$pipeline->addAuthorizer(new DatabaseAuthorizer(), 10);    // Check DB second

$server = new WebSocketServer($registry, $broadcaster, $formatter, $pipeline);

2. Bootstrap the Server

In your Service Provider or entry point, wire up the components.

$server = new WebSocketServer(
    $registry, 
    $broadcaster, 
    $formatter, 
    new ChatAuthorizer() // Inject your policy
);

// Attach event logic
$server->on('message', function($connection, $data) use ($server) {
    if ($data['event'] === 'join_team') {
        $server->joinPrivate($connection, "team-{$data['team_id']}");
    }
});

3. Emitting from your Application

Anywhere in your app (Controllers, Jobs, Commands), use the Broadcaster to push updates.

// In a Controller after a database update
$broadcaster->privateChannel('team-5')->emit('task_updated', [
    'task_id' => 123,
    'status' => 'completed'
]);

πŸ—οΈ Developer Notes & Standards

MonkeysLegion v2 Standards

This project strictly adheres to the MonkeysLegion PHP 8.4 Code Standards, including:

  • Attribute-First Configuration: Metadata driven by native PHP 8.4 attributes.
  • Type-Safe Everything: Mandatory strict types and PHPStan Level 9 compliance.
  • Asymmetric Visibility: Using modern property hooks and refined visibility.
  • PSR Compliance: Adherence to PSR-1, 4, 7, 11, 12, and 15.

To contribute or work on the library, ensure you have the pcntl and posix extensions for integration testing.

Built with ❀️ by the MonkeysLegion Team (Advanced Agentic Coding).