reactphp-kernel/README.md

4.9 KiB

Blax Software OSS

ReactPHP Kernel

PHP Version Built on ReactPHP Tests Assertions License

A tiny, protocol-agnostic ReactPHP backbone — one long-lived process, one event loop, one IPC primitive, and one graceful-shutdown story that many protocol servers attach to.

Features

  • 🧩 One loop, many protocols — WebSockets, WebRTC signaling, SIP and more share a single Kernel instead of each spinning up its own runtime
  • 🔌 Tiny Server contract — implement boot(LoopInterface) + shutdown() and you're on the shared loop
  • 🧵 Socket-pair IPC — event-driven parent↔child messaging with zero polling
  • 🛎️ Graceful shutdown — SIGINT/SIGTERM tear every server down cleanly before the loop stops
  • 🧹 Child reaping built in — no zombie processes from forked workers (SIGCHLD + periodic backstop)
  • 🔐 Plain or TLS listeners — one factory, no framework coupling
  • 🪶 Dependency-light — just react/event-loop, react/socket, react/stream

Installation

composer require blax-software/reactphp-kernel

Requires PHP 8.1+, plus ext-pcntl (signals + child reaping) and ext-sockets (IPC) for the full feature set.

Quick Start

Implement a Server, register it, run():

use Blax\ReactPhpKernel\Kernel;
use Blax\ReactPhpKernel\Contracts\Server;
use Blax\ReactPhpKernel\Server\SocketServerFactory;
use React\EventLoop\LoopInterface;
use React\Socket\ConnectionInterface;

final class EchoServer implements Server
{
    private $socket = null;

    public function name(): string
    {
        return 'echo';
    }

    public function boot(LoopInterface $loop): void
    {
        $this->socket = SocketServerFactory::create('0.0.0.0:9001', $loop);
        $this->socket->on('connection', function (ConnectionInterface $conn) {
            $conn->on('data', fn ($data) => $conn->write($data)); // echo it back
        });
    }

    public function shutdown(): void
    {
        $this->socket?->close();
    }
}

(new Kernel())
    ->reapChildren()               // auto-reap forked children
    ->register(new EchoServer())
    ->onBoot(fn (Kernel $k) => fwrite(STDERR, "ready\n"))
    ->run();                       // boots servers, installs signals, runs the loop (blocks)

Ctrl-C (SIGINT) or SIGTERM triggers a graceful stop(): every registered server's shutdown() runs, then the loop stops.

What's in the box

Class Responsibility
Kernel Owns the loop; register() servers; installs signals; run() / graceful stop().
Contracts\Server An attachable protocol server: boot(LoopInterface) (non-blocking) + shutdown().
Server\SocketServerFactory Plain-TCP or TLS listening socket.
Ipc\SocketPairIpc Event-driven parent/child IPC over a Unix socket pair.
Process\SignalHandler SIGINT/SIGTERM → graceful shutdown.
Process\ChildReaper Reaps exited forked children (SIGCHLD + periodic backstop).

Why

It's the shared foundation extracted from blax-software/laravel-websockets so that WebSockets and blax-software/laravel-webrtc (WebRTC signaling + a Rust/str0m media core) don't each re-implement the loop, IPC, signals and supervision. A new protocol gets the plumbing for free.

reactphp-kernel                 this package — the backbone
   ├─ laravel-websockets        WS on the kernel
   └─ laravel-webrtc            WebRTC signaling on the kernel
         └─ Rust/str0m core     via ext-php-rs

Testing

composer install
composer test

The suite runs against a real ReactPHP loop, with no external services.

License

MIT. See LICENSE.

Star History

Star History Chart