feat(messaging): add Appwrite Push adapter for MQTT 5 integration - #161
Open
ArnabChatterjee20k wants to merge 7 commits into
Open
feat(messaging): add Appwrite Push adapter for MQTT 5 integration#161ArnabChatterjee20k wants to merge 7 commits into
ArnabChatterjee20k wants to merge 7 commits into
Conversation
ArnabChatterjee20k
requested review from
Meldiron,
abnegate,
eldadfux and
loks0n
as code owners
August 25, 2026 10:55
Align the ported MQTT 5 codec and Appwrite Push adapter with the monorepo's stricter toolchain: pint (per preset, native_function_invocation, cast spacing, trailing commas), rector 2.x (explicit bool compare, drop redundant casts, empty()->=== [], readonly promoted props, instanceof over !== null), and phpstan 2.x (cast unpack() result feeding the by-ref int $offset). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a spawned in-process MQTT 5 broker (FakeBroker) that speaks just enough protocol to accept the adapter's enhanced-auth CONNECT, ack QoS 1 PUBLISHes (optionally rejecting tokens), and record what it saw. AppwriteTest drives the publisher against it: device-topic publishes, pipelined PUBACK counting, expired-token reason codes, and the enhanced-auth CONNECT (projectId + credential in the property block, not username/password). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
encodeSubscribe() completes the subscriber role of the codec: one topic filter, a configurable max QoS, and optional User Properties (e.g. the subId the broker keys subscriptions on). Reserved fixed-header flags set to 0b0010 per spec. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pter The same enhanced-auth connection that publishes can now subscribe: consume() connects, subscribes to the given topics (subId as a User Property), and invokes a callback for each PUBLISH until a message limit or timeout is reached, acking QoS 1. This is what verifies broker fan-out end to end from the consumer side. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The adapter overrode the constructor without chaining to the base Adapter, so the send counter was never initialized and send() failed with "Typed property $sendCounter must not be accessed before initialization". Call parent::__construct and accept an optional Telemetry to inject, defaulting to the base no-op counter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add MQTT::parseSuback() and have consume() inspect the SUBACK reason codes: a code >= 0x80 (e.g. 0x87 Not Authorized from a broker ACL) now throws instead of silently subscribing to nothing, so subscribe-side authorization is observable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Appwrite Push (MQTT 5) adapter
Adds a
Pushadapter that talks to Appwrite's custom MQTT 5 broker, a minimal MQTT 5 control-packet codec (Helpers/MQTT), and a spawned mock broker for tests.The adapter speaks the broker's enhanced-authentication CONNECT dialect: the credential rides in the Authentication Method/Data properties and the project in a
projectIdUser Property. The broker scopes every topic by that project, so callers use bare device topics.Publish —
send()Publishes are pipelined at QoS 1 (send a window of PUBLISHes, drain PUBACKs by packet id, refill), so throughput scales with socket bandwidth rather than round-trip latency.
Consume —
consume()The same enhanced-auth connection can subscribe.
consume()subscribes to the given topics and invokes a callback for each message, until a message limit or timeout is reached (QoS 1 messages are acked):This is what verifies broker fan-out end to end from the consumer side (e.g. a device receiving what a publisher sent).
Telemetry
An optional
Telemetryadapter can be injected; it defaults to the base no-op counter:Codec —
Helpers/MQTTA transport-agnostic MQTT 5 codec: encode/parse CONNECT, CONNACK, PUBLISH, PUBACK, SUBSCRIBE, SUBACK, PINGREQ/RESP, DISCONNECT, and the v5 property block (User Properties, enhanced-auth, message expiry, …). Both the adapter and the tests build on it.
Tests
tests/Messaging/Adapter/Push/AppwriteTest.phpdrives the adapter against a spawned in-process mock broker (FakeBroker.php) that accepts the enhanced-auth CONNECT and acks QoS 1 publishes: device-topic publishes, pipelined PUBACK counting, expired-token reason codes, and the CONNECT property block (projectId+ credential, not username/password).