apntalk/esl-core
Composer 安装命令:
composer require apntalk/esl-core
包简介
Framework-agnostic, transport-neutral, typed FreeSWITCH ESL protocol library for PHP with replay-safe protocol primitives
README 文档
README
Framework-agnostic, transport-neutral, typed FreeSWITCH ESL protocol substrate for PHP with replay-safe primitives.
What this package is
apntalk/esl-core is a protocol substrate for FreeSWITCH Event Socket Layer (ESL) clients.
It provides:
- A truthful ESL wire model (framing, parsing, serialization)
- Deterministic message classification (auth, command replies, events, bgapi)
- Typed command and reply objects
- A normalized event model with selective typed event families and safe degradation for unknown event types
- Correlation and session metadata primitives
- Replay-safe protocol envelopes and reconstruction-oriented hook contracts
- Capability declaration of supported surfaces
- Canonical protocol/core truth vocabulary for queue, retry, drain, lifecycle, terminal-publication, corpus-row, bounded-variance, and replay-adjacent blocker-family terms
- A minimal transport abstraction for testing and smoke-path use
It is designed to sit below runtime, framework, and replay packages such as
apntalk/esl-react, apntalk/laravel-freeswitch-esl, and
apntalk/esl-replay.
What this package is not
This package does not provide:
- Laravel service container bindings
- ReactPHP or Amp event loop integration
- Reconnect or supervision logic
- Worker assignment or routing
- Cluster or multi-PBX orchestration
- Database-backed registry behavior
- Durable replay execution engines
- Replay re-injection or replay scheduling
- Health endpoints
Those concerns belong in upper-layer packages that depend on this one:
apntalk/esl-react owns runtime/reconnect behavior,
apntalk/laravel-freeswitch-esl owns Laravel integration and persistence
concerns, and apntalk/esl-replay owns replay execution/re-injection.
Requirements
- PHP 8.1 or higher
ext-domenabled- No runtime framework dependencies
Installation
composer require apntalk/esl-core
Stability
This package follows SemVer, but it is still pre-1.0.0.
- Public namespaces are documented in
docs/public-api.md - The supported inbound decode surface is now
Apntalk\EslCore\Inbound\InboundPipeline - Internal parser/classifier implementations remain intentionally unstable before
1.0.0 - Replay envelopes and reconstruction-oriented contracts should be treated as provisional surfaces until
1.0.0
See docs/stability-policy.md for full details.
The canonical vocabulary surfaces are documented in
docs/canonical-truth-vocabulary.md.
Architecture overview
The library is organized in layers:
| Layer | Responsibility |
|---|---|
| Wire | Bytes, headers, body, framing, parsing, serialization |
| Classification | Session/auth state, message category, reply vs event distinction |
| Typed domain | Commands, replies, normalized events, correlation metadata |
| Canonical vocabulary | Capability, queue/retry/drain, lifecycle, terminal-publication, corpus-row, bounded-variance, and replay-adjacent truth terms |
| Replay substrate | Replay envelopes, capture policies, reconstruction hooks |
| Transport boundary | Minimal read/write contracts, in-memory transport |
See docs/architecture.md for the full architecture description.
Quick start
The supported public surface is centered on typed commands, the inbound decoding facade, normalized/typed events, correlation metadata, replay envelopes, capabilities, and the minimal transport boundary.
For new integrations, start from InboundPipeline::withDefaults() for raw byte decoding, SocketTransportFactory for endpoint/stream transport construction, and InboundConnectionFactory when a listener/runtime has already accepted a stream and needs one supported bootstrap bundle.
Direct InboundPipeline::__construct(...) collaborator injection and parser/classifier/reply-factory composition remain available for advanced fixture-backed work, but they are not the preferred downstream ingress path at this checkpoint and are not being soft-deprecated in this release line. For advanced callers that need parser/classifier replacement through public contracts, use InboundPipeline::withContracts(...); treat that as an advanced extension seam, not a co-equal integration route.
For one concise downstream integration map, see docs/downstream-integration.md.
Downstream integration map
For packages such as apntalk/laravel-freeswitch-esl, the supported integration choices are:
| Downstream need | Preferred public seam | Ownership that stays outside esl-core |
|---|---|---|
| Open a client connection from host/port settings | SocketTransportFactory::connect() + InboundPipeline::withDefaults() |
reconnect/backoff, read loops, auth/session policy, event subscription policy |
| Bootstrap one already-accepted inbound stream | InboundConnectionFactory::prepareAcceptedStream() |
listener ownership, accept loops, per-session supervision |
| Compose directly from frames / normalized events | ReplyFactory::fromFrame(), ReplyFactory::fromClassification(), EventFactory, EventClassifier, lower-level contracts |
byte-ingress defaults, stable constructor ergonomics, protection from provisional coupling |
Use CorrelationContext after decode when your upper layer needs per-session ordering or derived job/channel correlation. Use ReplayEnvelopeFactory only for replay-safe capture/export hooks; storage, scheduling, replay execution, and replay re-injection stay in upper layers such as apntalk/esl-replay.
Preferred ingress facade
Use InboundPipeline::withDefaults() when you need the supported raw-byte decode path without coupling to the current parser/classifier implementation details.
use Apntalk\EslCore\Commands\AuthCommand; use Apntalk\EslCore\Correlation\ConnectionSessionId; use Apntalk\EslCore\Correlation\CorrelationContext; use Apntalk\EslCore\Inbound\InboundPipeline; use Apntalk\EslCore\Replay\ReplayEnvelopeFactory; use Apntalk\EslCore\Transport\InMemoryTransport; // InMemoryTransport is a test/smoke transport, not a runtime owner. $transport = new InMemoryTransport(); $transport->write((new AuthCommand('ClueCon'))->serialize()); $inbound = InboundPipeline::withDefaults(); $transport->enqueueInbound("Content-Type: auth/request\n\n"); $messages = $inbound->decode($transport->read(4096) ?? ''); $messages[0]->isServerAuthRequest(); // true $sessionId = ConnectionSessionId::generate(); $correlation = new CorrelationContext($sessionId); $replay = ReplayEnvelopeFactory::withSession($sessionId);
Preferred transport construction seam
Use SocketTransportFactory when you need core to create or wrap a real byte-stream transport while keeping lifecycle policy outside esl-core.
use Apntalk\EslCore\Transport\SocketEndpoint; use Apntalk\EslCore\Transport\SocketTransportFactory; $socketFactory = new SocketTransportFactory(); $transport = $socketFactory->connect(SocketEndpoint::tcp('127.0.0.1', 8021));
TransportInterface::read() returns '' as a non-blocking "no data yet"
signal only when the underlying transport is configured for non-blocking reads.
SocketTransportFactory preserves the current blocking mode of the PHP stream
it connects or wraps; if your runtime polls, configure the stream accordingly.
For this release line, TransportInterface::write() assumes the wrapped stream
is currently writable and is expected to be used with a blocking stream or with
runtime-managed write readiness. Core does not implement async retry,
would-block buffering, or write scheduling; non-writable writes fail with
TransportException.
Accepted-stream bootstrap seam
Use InboundConnectionFactory when your listener/runtime has already accepted a PHP stream and now needs the supported core bootstrap bundle.
use Apntalk\EslCore\Inbound\InboundConnectionFactory; [$acceptedPhpStream] = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0); $acceptedFactory = new InboundConnectionFactory(); $prepared = $acceptedFactory->prepareAcceptedStream($acceptedPhpStream); $prepared->pipeline()->push($prepared->transport()->read(4096) ?? '');
In production, $acceptedPhpStream is provided by your listener/runtime layer after accept. If prepareAcceptedStream() is called without a ConnectionSessionId, core generates one for that connection and binds it to the returned CorrelationContext. That bootstrap step still does not imply listener ownership, a read loop, replay bootstrap integration, or any higher-level session supervision.
If you need the current low-level parser/classifier implementations directly, they are still available in the repository and fixture-backed, but they remain pre-1.0 unstable implementation surfaces rather than the disciplined public API boundary.
Upper layers should prefer InboundPipeline::withDefaults() instead of composing FrameParser, InboundMessageClassifier, ReplyFactory, and EventFactory directly, unless they intentionally need frame-level control and accept lower-level coupling. Use InboundPipeline::withContracts(...) when that customization must be expressed through public parser/classifier contracts.
For that advanced composition path, the current staged migration posture is:
- consume classified output through
Contracts\\ClassifiedMessageInterface - pass it to
ReplyFactory::fromClassification()when you need typed replies - implement
InboundMessageClassifierInterfaceagainst the publicClassifiedMessageInterfaceresult contract when you need custom classification
For typed events, the built-in event wrappers currently expose a public readonly
$normalized property and also implement
Contracts\ProvidesNormalizedSubstrateInterface. Treat the interface or
DecodedInboundMessage::normalizedEvent() as the supported substrate seam for
downstream code; a similarly named property on custom wrappers is not enough to
participate in correlation/replay substrate extraction.
Preferred vs advanced seam posture
| Posture | What to build on first |
|---|---|
| Preferred public seams | InboundPipeline::withDefaults(), SocketTransportFactory, InboundConnectionFactory, typed commands/replies/events, CorrelationContext, ReplayEnvelopeFactory |
| Advanced public seams | InboundPipeline::withContracts(...), InboundPipeline::__construct(...), ReplyFactory::fromFrame(), ReplyFactory::fromClassification(), ReplyFactory::fromClassified(), EventFactory, EventClassifier, Contracts\ClassifiedMessageInterface, Contracts\CompletableFrameParserInterface, Contracts\ProvidesNormalizedSubstrateInterface, Contracts\FrameSerializerInterface, lower-level Contracts\* parser/classifier interfaces |
| Internal or provisional implementation details | Parsing\*, Internal\*, most of Protocol\* other than Frame and HeaderBag |
Current release scope
- Typed commands and replies for auth, command replies,
api, andbgapi - Stable inbound byte-stream decoding via
InboundPipeline - Stable accepted-stream inbound bootstrap via
InboundConnectionFactory+PreparedInboundConnection - Normalized events for
text/event-plainandtext/event-json - Provisional normalized event decoding for
text/event-xml - Selective typed event families: background job, channel lifecycle, bridge, hangup, playback, and custom events
- Correlation/session metadata and replay-safe envelopes
- Canonical truth vocabulary under
Apntalk\EslCore\Vocabularyfor blocker-family terms needed by downstream runtime/replay packages - Minimal in-memory transport and explicit failure taxonomy
- Stable public socket transport construction via
SocketEndpoint+SocketTransportFactory - Internal-only stream/socket smoke-path validation over a real PHP stream resource
- Fixture-backed behavior, PHPUnit coverage, PHPStan, and capability verification
Still provisional or deferred from this release:
- live-backed
text/event-xmlevidence beyond constructed fixtures - framework/runtime integrations
- broader transport runtime expansion beyond the minimal socket construction seam
- replay storage, scheduling, execution, re-injection, or orchestration
- downstream queue execution, retry scheduling, drain orchestration, lifecycle projection state machines, and terminal-publication dispatch
Smoke check
For a fast confidence pass that the current substrate composes cleanly on its happy paths, run:
composer smoke
This smoke path exercises the supported inbound facade together with the typed command/reply and async event pipelines, including correlation/session metadata and replay-envelope creation.
Maintainer verification
Use the narrowest useful check first:
composer unitfor low-level value-object and wire-model regressionscomposer contractfor public seam and fixture-backed behavior checkscomposer integrationfor composed in-memory/socket/inbound-path verificationcomposer smokefor a fast supported-path sanity passcomposer checkfor the full local release gate (cs-check,analyse, andtest)composer validate --strictwhen changing package metadata or Composer scripts
Live tools/smoke/* helpers remain optional operator validation support for fixture work and PBX-side evidence gathering. They are not part of the package API or the default local release gate.
Current release-line status
The repository is currently positioned as a small pre-1.0.0 release line with the core seams in place and residual provisional surfaces explicitly documented.
That means:
- the supported ingress contract is explicit and documented around
InboundPipeline - XML event decoding exists, but is still declared provisional pending broader evidence
- stream/socket validation is stronger, but remains internal smoke support only
- residual pre-1.0 gaps are documented rather than hidden
For shipped version history and current unreleased changes, treat
CHANGELOG.md plus the published git tags/GitHub releases as
the release source of truth. Historical draft notes under docs/releases/
remain maintainer context only.
Documentation
docs/architecture.mddocs/protocol-model.mddocs/protocol-state.mddocs/fixtures.mddocs/replay-primitives.mddocs/public-api.mddocs/downstream-integration.mddocs/stability-policy.mddocs/capabilities.mddocs/release-checklist.md
License
MIT. See LICENSE.
apntalk/esl-core 适用场景与选型建议
apntalk/esl-core 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 92 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 04 月 14 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「protocol」 「telephony」 「freeswitch」 「esl」 「event-socket」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 apntalk/esl-core 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 apntalk/esl-core 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 apntalk/esl-core 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Asterisk Manager Interface (AMI) client for PHP, event driven, object oriented (Fork)
A PHP 5.3 library for interacting with mod_event_socket on FreeSWITCH.
A small client implementing the Measurement Protocol for Google Analytics 4.
Client library for connecting to SignalWire.
Yii2 Extension for sending push notification with both Firebase Cloud Messaging (FCM) HTTP Server Protocols (APIs).
Fork of marcelog's Asterisk Manager Interface (AMI) client for PHP, event driven, object oriented
统计信息
- 总下载量: 92
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 35
- 依赖项目数: 2
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-04-14