|
| 1 | +# Changelog |
| 2 | + |
| 3 | +All notable changes to this project will be documented in this file. |
| 4 | + |
| 5 | +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) |
| 6 | +and this project adheres to [Semantic Versioning 2.0.0](https://semver.org/). |
| 7 | + |
| 8 | +## [Unreleased] |
| 9 | + |
| 10 | +## [2.0.0] — TBD |
| 11 | + |
| 12 | +### Highlights |
| 13 | + |
| 14 | +The 2.0 line is a clean break from 1.x — the previous server loop had |
| 15 | +race conditions, lost inbound data through its liveness check, and |
| 16 | +stored transport state on a `static` property that leaked between |
| 17 | +instances. The new shape ships with explicit enums, per-transport |
| 18 | +`Channel` strategies, a non-blocking `select`-driven loop and full |
| 19 | +PHP 8.1+ typing. |
| 20 | + |
| 21 | +### Added |
| 22 | + |
| 23 | +- **PHP 8.1+ enums** — `Transport`, `Domain` and `CryptoMethod` replace |
| 24 | + magic integer / string flags. |
| 25 | +- **`ChannelInterface` + `TcpChannel` / `UdpChannel` / `StreamChannel`** — |
| 26 | + per-transport I/O strategy. `ServerConnection` is now just identity |
| 27 | + plus delegation. |
| 28 | +- **`SocketExceptionInterface`** — marker implemented by every exception |
| 29 | + in the package, so a single catch covers them all. |
| 30 | +- **`tick(callable, float): int`** — single-iteration accept/dispatch |
| 31 | + method on every server. Use it to embed the package in your own |
| 32 | + event loop or to drive servers deterministically in tests. |
| 33 | +- **`stop()` / `isRunning()`** — cooperative shutdown for the `live()` |
| 34 | + loop. |
| 35 | +- **`register(int|string, SocketConnectionInterface): bool`** — promoted |
| 36 | + to `SocketServerInterface`; the 1.x package-private `clientRegister()` |
| 37 | + is replaced by an interface method with a stable contract. |
| 38 | +- **PHPUnit 10 test suite** — 36 unit + integration tests covering |
| 39 | + enums, exception hierarchy, factory, channels, broadcast/register |
| 40 | + logic, TCP echo, UDP per-peer routing, TLS handshake (forked). |
| 41 | +- **CI pipeline** — GitHub Actions matrix across PHP 8.1, 8.2, 8.3 with |
| 42 | + PHPStan level 8, PHP-CS-Fixer and Codecov upload. |
| 43 | +- **`docs/` directory** — getting started, architecture, per-transport |
| 44 | + server and client guides, cookbook (chat server, raw SMTP) and the |
| 45 | + migration guide. |
| 46 | + |
| 47 | +### Changed |
| 48 | + |
| 49 | +- **Minimum PHP version** is now `^8.1` (was `>=7.4`). |
| 50 | +- **`composer.json`** now requires `ext-openssl` in addition to |
| 51 | + `ext-sockets`. |
| 52 | +- **Server method renames** — `connection()` → `listen()`, |
| 53 | + `disconnect()` → `close()`. `live()` signature now takes |
| 54 | + `float $idleSeconds` instead of `int $usleep`. `wait()` is typed |
| 55 | + `float $seconds`. |
| 56 | +- **`SocketServerClientInterface` renamed to `SocketConnectionInterface`.** |
| 57 | + `push()` is now `write()`. `isDisconnected()` is replaced by the |
| 58 | + non-destructive `isAlive()`. |
| 59 | +- **Exception hierarchy** — `SocketException` extends |
| 60 | + `\RuntimeException`. `SocketConnectionException` and |
| 61 | + `SocketListenException` now extend `SocketException` (previously |
| 62 | + `\Exception`). `SocketInvalidArgumentException` still extends |
| 63 | + `\InvalidArgumentException` and additionally implements |
| 64 | + `SocketExceptionInterface`. |
| 65 | + |
| 66 | +### Removed |
| 67 | + |
| 68 | +- `Common/BaseClient`, `Common/BaseCommon`, `Common/BaseServer`, |
| 69 | + `Common/ServerTrait`, `Common/StreamClientTrait`, |
| 70 | + `Common/StreamServerTrait` — replaced by `Client/AbstractClient`, |
| 71 | + `Client/AbstractStreamClient`, `Server/AbstractServer` and |
| 72 | + `Server/AbstractStreamServer`. |
| 73 | +- `Server/ServerClient` — replaced by `Server/ServerConnection`. |
| 74 | +- `Interfaces/SocketServerClientInterface` — replaced by |
| 75 | + `Interfaces/SocketConnectionInterface`. |
| 76 | +- `Socket::TCP`, `Socket::UDP`, `Socket::TLS`, `Socket::SSL` integer |
| 77 | + constants — replaced by the `Transport` enum. |
| 78 | +- The mystery-typed `$argument` parameter on the factory and on every |
| 79 | + constructor — replaced by explicit `?Domain $domain` / `?float $timeout` |
| 80 | + named parameters. |
| 81 | +- All `__setSocket()` / `__setCallbacks()` / `__removeCallbacks()` |
| 82 | + magic-prefixed methods. |
| 83 | +- The static `ServerClient::$credentials` array that leaked transport |
| 84 | + state between server instances. |
| 85 | +- `echo` calls inside `ServerClient` that wrote |
| 86 | + `"New client connected."` / `"Client disconnected."` to STDOUT. |
| 87 | + |
| 88 | +### Fixed |
| 89 | + |
| 90 | +- **Server loop accepts more than one client.** The 1.x `connection()` |
| 91 | + performed a blocking `socket_accept()` before `live()` was even |
| 92 | + called, capping the server at a single connection per process. |
| 93 | +- **TLS / SSL servers use the right accept call.** The 1.x loop called |
| 94 | + `socket_accept()` on a stream resource (always wrong for TLS / SSL) |
| 95 | + and never accepted the second connection. |
| 96 | +- **Liveness checks no longer consume data.** The 1.x |
| 97 | + `isDisconnected()` read a line off every client every iteration |
| 98 | + and discarded it, so application-level reads never saw any data. |
| 99 | +- **Client id map survives disconnects.** The 1.x `clientMap` stored |
| 100 | + raw array indices that became dangling after `unset()` on a |
| 101 | + disconnected client. The new `clientIdMap` uses monotonic keys and |
| 102 | + cleans up on eviction. |
| 103 | +- **UDP server demultiplexes peers correctly.** The 1.x server |
| 104 | + registered the listening socket itself as a "client" and broadcast |
| 105 | + back to its own host/port. |
| 106 | +- **TLS handshake has enough time.** The 1.x server left the listening |
| 107 | + stream non-blocking and called `stream_socket_accept(..., 0.0)`, |
| 108 | + which prevented the handshake from completing under load. The new |
| 109 | + loop keeps the listening stream blocking and drives readiness via |
| 110 | + `stream_select`, giving the handshake the full timeout. |
| 111 | + |
| 112 | +### Migration |
| 113 | + |
| 114 | +See [`docs/migration-1.x-to-2.x.md`](./docs/migration-1.x-to-2.x.md) for |
| 115 | +a step-by-step upgrade guide. |
| 116 | + |
| 117 | +[Unreleased]: https://github.com/InitPHP/Socket/compare/v2.0.0...HEAD |
| 118 | +[2.0.0]: https://github.com/InitPHP/Socket/releases/tag/v2.0.0 |
0 commit comments