init
This commit is contained in:
21
vendor/binsoul/net-mqtt-client-react/LICENSE.md
vendored
Executable file
21
vendor/binsoul/net-mqtt-client-react/LICENSE.md
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
# The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Sebastian Mößler <code@binsoul.de>
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
145
vendor/binsoul/net-mqtt-client-react/README.md
vendored
Executable file
145
vendor/binsoul/net-mqtt-client-react/README.md
vendored
Executable file
@@ -0,0 +1,145 @@
|
||||
# net-mqtt-client-react
|
||||
|
||||
[![Latest Version on Packagist][ico-version]][link-packagist]
|
||||
[![Software License][ico-license]](LICENSE.md)
|
||||
[![Total Downloads][ico-downloads]][link-downloads]
|
||||
|
||||
This package provides an asynchronous MQTT client built on the [React socket](https://github.com/reactphp/socket) library. All client methods return a promise which is fulfilled if the operation succeeded or rejected if the operation failed. Incoming messages of subscribed topics are delivered via the "message" event.
|
||||
|
||||
## Install
|
||||
|
||||
Via composer:
|
||||
|
||||
``` bash
|
||||
$ composer require binsoul/net-mqtt-client-react
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Connect to a public broker and run forever.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
|
||||
use BinSoul\Net\Mqtt\Client\React\ReactMqttClient;
|
||||
use BinSoul\Net\Mqtt\Connection;
|
||||
use BinSoul\Net\Mqtt\DefaultMessage;
|
||||
use BinSoul\Net\Mqtt\DefaultSubscription;
|
||||
use BinSoul\Net\Mqtt\Message;
|
||||
use BinSoul\Net\Mqtt\Subscription;
|
||||
use React\Socket\DnsConnector;
|
||||
use React\Socket\TcpConnector;
|
||||
|
||||
include 'vendor/autoload.php';
|
||||
|
||||
// Setup client
|
||||
$loop = \React\EventLoop\Factory::create();
|
||||
$dnsResolverFactory = new \React\Dns\Resolver\Factory();
|
||||
$connector = new DnsConnector(new TcpConnector($loop), $dnsResolverFactory->createCached('8.8.8.8', $loop));
|
||||
$client = new ReactMqttClient($connector, $loop);
|
||||
|
||||
// Bind to events
|
||||
$client->on('open', function () use ($client) {
|
||||
// Network connection established
|
||||
echo sprintf("Open: %s:%s\n", $client->getHost(), $client->getPort());
|
||||
});
|
||||
|
||||
$client->on('close', function () use ($client, $loop) {
|
||||
// Network connection closed
|
||||
echo sprintf("Close: %s:%s\n", $client->getHost(), $client->getPort());
|
||||
|
||||
$loop->stop();
|
||||
});
|
||||
|
||||
$client->on('connect', function (Connection $connection) {
|
||||
// Broker connected
|
||||
echo sprintf("Connect: client=%s\n", $connection->getClientID());
|
||||
});
|
||||
|
||||
$client->on('disconnect', function (Connection $connection) {
|
||||
// Broker disconnected
|
||||
echo sprintf("Disconnect: client=%s\n", $connection->getClientID());
|
||||
});
|
||||
|
||||
$client->on('message', function (Message $message) {
|
||||
// Incoming message
|
||||
echo 'Message';
|
||||
|
||||
if ($message->isDuplicate()) {
|
||||
echo ' (duplicate)';
|
||||
}
|
||||
|
||||
if ($message->isRetained()) {
|
||||
echo ' (retained)';
|
||||
}
|
||||
|
||||
echo ': '.$message->getTopic().' => '.mb_strimwidth($message->getPayload(), 0, 50, '...');
|
||||
echo "\n";
|
||||
});
|
||||
|
||||
$client->on('warning', function (\Exception $e) {
|
||||
echo sprintf("Warning: %s\n", $e->getMessage());
|
||||
});
|
||||
|
||||
$client->on('error', function (\Exception $e) use ($loop) {
|
||||
echo sprintf("Error: %s\n", $e->getMessage());
|
||||
|
||||
$loop->stop();
|
||||
});
|
||||
|
||||
// Connect to broker
|
||||
$client->connect('test.mosquitto.org')->then(
|
||||
function () use ($client) {
|
||||
// Subscribe to all topics
|
||||
$client->subscribe(new DefaultSubscription('#'))
|
||||
->then(function (Subscription $subscription) {
|
||||
echo sprintf("Subscribe: %s\n", $subscription->getFilter());
|
||||
})
|
||||
->otherwise(function (\Exception $e) {
|
||||
echo sprintf("Error: %s\n", $e->getMessage());
|
||||
});
|
||||
|
||||
// Publish humidity once
|
||||
$client->publish(new DefaultMessage('sensors/humidity', '55%'))
|
||||
->then(function (Message $message) {
|
||||
echo sprintf("Publish: %s => %s\n", $message->getTopic(), $message->getPayload());
|
||||
})
|
||||
->otherwise(function (\Exception $e) {
|
||||
echo sprintf("Error: %s\n", $e->getMessage());
|
||||
});
|
||||
|
||||
// Publish a random temperature every 10 seconds
|
||||
$generator = function () {
|
||||
return mt_rand(-20, 30);
|
||||
};
|
||||
|
||||
$client->publishPeriodically(10, new DefaultMessage('sensors/temperature'), $generator)
|
||||
->progress(function (Message $message) {
|
||||
echo sprintf("Publish: %s => %s\n", $message->getTopic(), $message->getPayload());
|
||||
})
|
||||
->otherwise(function (\Exception $e) {
|
||||
echo sprintf("Error: %s\n", $e->getMessage());
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
$loop->run();
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
``` bash
|
||||
$ composer test
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||
|
||||
[ico-version]: https://img.shields.io/packagist/v/binsoul/net-mqtt-client-react.svg?style=flat-square
|
||||
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
|
||||
[ico-downloads]: https://img.shields.io/packagist/dt/binsoul/net-mqtt-client-react.svg?style=flat-square
|
||||
|
||||
[link-packagist]: https://packagist.org/packages/binsoul/net-mqtt-client-react
|
||||
[link-downloads]: https://packagist.org/packages/binsoul/net-mqtt-client-react
|
||||
[link-author]: https://github.com/binsoul
|
||||
51
vendor/binsoul/net-mqtt-client-react/composer.json
vendored
Executable file
51
vendor/binsoul/net-mqtt-client-react/composer.json
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "binsoul/net-mqtt-client-react",
|
||||
"description": "Asynchronous MQTT client built on React",
|
||||
"keywords": [
|
||||
"net",
|
||||
"mqtt",
|
||||
"client"
|
||||
],
|
||||
"homepage": "https://github.com/binsoul/net-mqtt-client-react",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Mößler",
|
||||
"email": "code@binsoul.de",
|
||||
"homepage": "https://github.com/binsoul",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "~5.6|~7.0",
|
||||
"binsoul/net-mqtt": "~0.2",
|
||||
"react/promise": "~2.0",
|
||||
"react/socket": "~0.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0||~5.0",
|
||||
"friendsofphp/php-cs-fixer": "~1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BinSoul\\Net\\Mqtt\\Client\\React\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"BinSoul\\Test\\Net\\Mqtt\\Client\\React\\": "tests"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit",
|
||||
"fix-style": [
|
||||
"php-cs-fixer fix src",
|
||||
"php-cs-fixer fix tests"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
112
vendor/binsoul/net-mqtt-client-react/src/ReactFlow.php
vendored
Executable file
112
vendor/binsoul/net-mqtt-client-react/src/ReactFlow.php
vendored
Executable file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Client\React;
|
||||
|
||||
use BinSoul\Net\Mqtt\Flow;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use React\Promise\Deferred;
|
||||
|
||||
/**
|
||||
* Decorates flows with data required for the {@see ReactMqttClient} class.
|
||||
*/
|
||||
class ReactFlow implements Flow
|
||||
{
|
||||
/** @var Flow */
|
||||
private $decorated;
|
||||
/** @var Deferred */
|
||||
private $deferred;
|
||||
/** @var Packet */
|
||||
private $packet;
|
||||
/** @var bool */
|
||||
private $isSilent;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param Flow $decorated
|
||||
* @param Deferred $deferred
|
||||
* @param Packet $packet
|
||||
* @param bool $isSilent
|
||||
*/
|
||||
public function __construct(Flow $decorated, Deferred $deferred, Packet $packet = null, $isSilent = false)
|
||||
{
|
||||
$this->decorated = $decorated;
|
||||
$this->deferred = $deferred;
|
||||
$this->packet = $packet;
|
||||
$this->isSilent = $isSilent;
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return $this->decorated->getCode();
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$this->packet = $this->decorated->start();
|
||||
|
||||
return $this->packet;
|
||||
}
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
return $this->decorated->accept($packet);
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
$this->packet = $this->decorated->next($packet);
|
||||
|
||||
return $this->packet;
|
||||
}
|
||||
|
||||
public function isFinished()
|
||||
{
|
||||
return $this->decorated->isFinished();
|
||||
}
|
||||
|
||||
public function isSuccess()
|
||||
{
|
||||
return $this->decorated->isSuccess();
|
||||
}
|
||||
|
||||
public function getResult()
|
||||
{
|
||||
return $this->decorated->getResult();
|
||||
}
|
||||
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->decorated->getErrorMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated deferred.
|
||||
*
|
||||
* @return Deferred
|
||||
*/
|
||||
public function getDeferred()
|
||||
{
|
||||
return $this->deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current packet.
|
||||
*
|
||||
* @return Packet
|
||||
*/
|
||||
public function getPacket()
|
||||
{
|
||||
return $this->packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the flow should emit events.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSilent()
|
||||
{
|
||||
return $this->isSilent;
|
||||
}
|
||||
}
|
||||
701
vendor/binsoul/net-mqtt-client-react/src/ReactMqttClient.php
vendored
Executable file
701
vendor/binsoul/net-mqtt-client-react/src/ReactMqttClient.php
vendored
Executable file
@@ -0,0 +1,701 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Client\React;
|
||||
|
||||
use BinSoul\Net\Mqtt\Connection;
|
||||
use BinSoul\Net\Mqtt\DefaultConnection;
|
||||
use BinSoul\Net\Mqtt\DefaultIdentifierGenerator;
|
||||
use BinSoul\Net\Mqtt\Flow;
|
||||
use BinSoul\Net\Mqtt\Flow\IncomingPublishFlow;
|
||||
use BinSoul\Net\Mqtt\Flow\OutgoingConnectFlow;
|
||||
use BinSoul\Net\Mqtt\Flow\OutgoingDisconnectFlow;
|
||||
use BinSoul\Net\Mqtt\Flow\OutgoingPingFlow;
|
||||
use BinSoul\Net\Mqtt\Flow\OutgoingPublishFlow;
|
||||
use BinSoul\Net\Mqtt\Flow\OutgoingSubscribeFlow;
|
||||
use BinSoul\Net\Mqtt\Flow\OutgoingUnsubscribeFlow;
|
||||
use BinSoul\Net\Mqtt\DefaultMessage;
|
||||
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||
use BinSoul\Net\Mqtt\Message;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishRequestPacket;
|
||||
use BinSoul\Net\Mqtt\StreamParser;
|
||||
use BinSoul\Net\Mqtt\Subscription;
|
||||
use Evenement\EventEmitter;
|
||||
use React\EventLoop\Timer\TimerInterface;
|
||||
use React\Promise\Deferred;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise\ExtendedPromiseInterface;
|
||||
use React\Promise\RejectedPromise;
|
||||
use React\Socket\ConnectorInterface;
|
||||
use React\Stream\DuplexStreamInterface;
|
||||
|
||||
/**
|
||||
* Connects to a MQTT broker and subscribes to topics or publishes messages.
|
||||
*
|
||||
* The following events are emitted:
|
||||
* - open - The network connection to the server is established.
|
||||
* - close - The network connection to the server is closed.
|
||||
* - warning - An event of severity "warning" occurred.
|
||||
* - error - An event of severity "error" occurred.
|
||||
*
|
||||
* If a flow finishes it's result is also emitted, e.g.:
|
||||
* - connect - The client connected to the broker.
|
||||
* - disconnect - The client disconnected from the broker.
|
||||
* - subscribe - The client subscribed to a topic filter.
|
||||
* - unsubscribe - The client unsubscribed from topic filter.
|
||||
* - publish - A message was published.
|
||||
* - message - A message was received.
|
||||
*/
|
||||
class ReactMqttClient extends EventEmitter
|
||||
{
|
||||
/** @var ConnectorInterface */
|
||||
private $connector;
|
||||
/** @var LoopInterface */
|
||||
private $loop;
|
||||
/** @var DuplexStreamInterface */
|
||||
private $stream;
|
||||
/** @var StreamParser */
|
||||
private $parser;
|
||||
/** @var IdentifierGenerator */
|
||||
private $identifierGenerator;
|
||||
|
||||
/** @var string */
|
||||
private $host;
|
||||
/** @var int */
|
||||
private $port;
|
||||
/** @var Connection */
|
||||
private $connection;
|
||||
/** @var bool */
|
||||
private $isConnected = false;
|
||||
/** @var bool */
|
||||
private $isConnecting = false;
|
||||
/** @var bool */
|
||||
private $isDisconnecting = false;
|
||||
|
||||
/** @var TimerInterface[] */
|
||||
private $timer = [];
|
||||
|
||||
/** @var ReactFlow[] */
|
||||
private $receivingFlows = [];
|
||||
/** @var ReactFlow[] */
|
||||
private $sendingFlows = [];
|
||||
/** @var ReactFlow */
|
||||
private $writtenFlow;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param ConnectorInterface $connector
|
||||
* @param LoopInterface $loop
|
||||
* @param IdentifierGenerator $identifierGenerator
|
||||
* @param StreamParser $parser
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectorInterface $connector,
|
||||
LoopInterface $loop,
|
||||
IdentifierGenerator $identifierGenerator = null,
|
||||
StreamParser $parser = null
|
||||
) {
|
||||
$this->connector = $connector;
|
||||
$this->loop = $loop;
|
||||
|
||||
$this->parser = $parser;
|
||||
if ($this->parser === null) {
|
||||
$this->parser = new StreamParser();
|
||||
}
|
||||
|
||||
$this->parser->onError(function (\Exception $e) {
|
||||
$this->emitWarning($e);
|
||||
});
|
||||
|
||||
$this->identifierGenerator = $identifierGenerator;
|
||||
if ($this->identifierGenerator === null) {
|
||||
$this->identifierGenerator = new DefaultIdentifierGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the host.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHost()
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the port.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPort()
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the client is connected.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return $this->isConnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying stream or null if the client is not connected.
|
||||
*
|
||||
* @return DuplexStreamInterface|null
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a broker.
|
||||
*
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param Connection $connection
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
public function connect($host, $port = 1883, Connection $connection = null, $timeout = 5)
|
||||
{
|
||||
if ($this->isConnected || $this->isConnecting) {
|
||||
return new RejectedPromise(new \LogicException('The client is already connected.'));
|
||||
}
|
||||
|
||||
$this->isConnecting = true;
|
||||
$this->isConnected = false;
|
||||
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
|
||||
if ($connection === null) {
|
||||
$connection = new DefaultConnection();
|
||||
}
|
||||
|
||||
if ($connection->isCleanSession()) {
|
||||
$this->cleanPreviousSession();
|
||||
}
|
||||
|
||||
if ($connection->getClientID() === '') {
|
||||
$connection = $connection->withClientID($this->identifierGenerator->generateClientID());
|
||||
}
|
||||
|
||||
$deferred = new Deferred();
|
||||
|
||||
$this->establishConnection($this->host, $this->port, $timeout)
|
||||
->then(function (DuplexStreamInterface $stream) use ($connection, $deferred, $timeout) {
|
||||
$this->stream = $stream;
|
||||
|
||||
$this->emit('open', [$connection, $this]);
|
||||
|
||||
$this->registerClient($connection, $timeout)
|
||||
->then(function (Connection $connection) use ($deferred) {
|
||||
$this->isConnecting = false;
|
||||
$this->isConnected = true;
|
||||
$this->connection = $connection;
|
||||
|
||||
$this->emit('connect', [$connection, $this]);
|
||||
$deferred->resolve($this->connection);
|
||||
})
|
||||
->otherwise(function (\Exception $e) use ($deferred, $connection) {
|
||||
$this->isConnecting = false;
|
||||
|
||||
$this->emitError($e);
|
||||
$deferred->reject($e);
|
||||
|
||||
if ($this->stream !== null) {
|
||||
$this->stream->close();
|
||||
}
|
||||
|
||||
$this->emit('close', [$connection, $this]);
|
||||
});
|
||||
})
|
||||
->otherwise(function (\Exception $e) use ($deferred) {
|
||||
$this->isConnecting = false;
|
||||
|
||||
$this->emitError($e);
|
||||
$deferred->reject($e);
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects from a broker.
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
if (!$this->isConnected || $this->isDisconnecting) {
|
||||
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||
}
|
||||
|
||||
$this->isDisconnecting = true;
|
||||
|
||||
$deferred = new Deferred();
|
||||
|
||||
$this->startFlow(new OutgoingDisconnectFlow($this->connection), true)
|
||||
->then(function (Connection $connection) use ($deferred) {
|
||||
$this->isDisconnecting = false;
|
||||
$this->isConnected = false;
|
||||
|
||||
$this->emit('disconnect', [$connection, $this]);
|
||||
$deferred->resolve($connection);
|
||||
|
||||
if ($this->stream !== null) {
|
||||
$this->stream->close();
|
||||
}
|
||||
})
|
||||
->otherwise(function () use ($deferred) {
|
||||
$this->isDisconnecting = false;
|
||||
$deferred->reject($this->connection);
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to a topic filter.
|
||||
*
|
||||
* @param Subscription $subscription
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
public function subscribe(Subscription $subscription)
|
||||
{
|
||||
if (!$this->isConnected) {
|
||||
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||
}
|
||||
|
||||
return $this->startFlow(new OutgoingSubscribeFlow([$subscription], $this->identifierGenerator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes from a topic filter.
|
||||
*
|
||||
* @param Subscription $subscription
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
public function unsubscribe(Subscription $subscription)
|
||||
{
|
||||
if (!$this->isConnected) {
|
||||
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||
}
|
||||
|
||||
return $this->startFlow(new OutgoingUnsubscribeFlow([$subscription], $this->identifierGenerator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes a message.
|
||||
*
|
||||
* @param Message $message
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
public function publish(Message $message)
|
||||
{
|
||||
if (!$this->isConnected) {
|
||||
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||
}
|
||||
|
||||
return $this->startFlow(new OutgoingPublishFlow($message, $this->identifierGenerator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given generator periodically and publishes the return value.
|
||||
*
|
||||
* @param int $interval
|
||||
* @param Message $message
|
||||
* @param callable $generator
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
public function publishPeriodically($interval, Message $message, callable $generator)
|
||||
{
|
||||
if (!$this->isConnected) {
|
||||
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||
}
|
||||
|
||||
$deferred = new Deferred();
|
||||
|
||||
$this->timer[] = $this->loop->addPeriodicTimer(
|
||||
$interval,
|
||||
function () use ($message, $generator, $deferred) {
|
||||
$this->publish($message->withPayload($generator($message->getTopic())))->then(
|
||||
function ($value) use ($deferred) {
|
||||
$deferred->notify($value);
|
||||
},
|
||||
function (\Exception $e) use ($deferred) {
|
||||
$deferred->reject($e);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits warnings.
|
||||
*
|
||||
* @param \Exception $e
|
||||
*/
|
||||
private function emitWarning(\Exception $e)
|
||||
{
|
||||
$this->emit('warning', [$e, $this]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits errors.
|
||||
*
|
||||
* @param \Exception $e
|
||||
*/
|
||||
private function emitError(\Exception $e)
|
||||
{
|
||||
$this->emit('error', [$e, $this]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a network connection to a server.
|
||||
*
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
private function establishConnection($host, $port, $timeout)
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
|
||||
$timer = $this->loop->addTimer(
|
||||
$timeout,
|
||||
function () use ($deferred, $timeout) {
|
||||
$exception = new \RuntimeException(sprintf('Connection timed out after %d seconds.', $timeout));
|
||||
$deferred->reject($exception);
|
||||
}
|
||||
);
|
||||
|
||||
$this->connector->connect($host.':'.$port)
|
||||
->always(function () use ($timer) {
|
||||
$this->loop->cancelTimer($timer);
|
||||
})
|
||||
->then(function (DuplexStreamInterface $stream) use ($deferred) {
|
||||
$stream->on('data', function ($data) {
|
||||
$this->handleReceive($data);
|
||||
});
|
||||
|
||||
$stream->on('close', function () {
|
||||
$this->handleClose();
|
||||
});
|
||||
|
||||
$stream->on('error', function (\Exception $e) {
|
||||
$this->handleError($e);
|
||||
});
|
||||
|
||||
$deferred->resolve($stream);
|
||||
})
|
||||
->otherwise(function (\Exception $e) use ($deferred) {
|
||||
$deferred->reject($e);
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new client with the broker.
|
||||
*
|
||||
* @param Connection $connection
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
private function registerClient(Connection $connection, $timeout)
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
|
||||
$responseTimer = $this->loop->addTimer(
|
||||
$timeout,
|
||||
function () use ($deferred, $timeout) {
|
||||
$exception = new \RuntimeException(sprintf('No response after %d seconds.', $timeout));
|
||||
$deferred->reject($exception);
|
||||
}
|
||||
);
|
||||
|
||||
$this->startFlow(new OutgoingConnectFlow($connection, $this->identifierGenerator), true)
|
||||
->always(function () use ($responseTimer) {
|
||||
$this->loop->cancelTimer($responseTimer);
|
||||
})->then(function (Connection $connection) use ($deferred) {
|
||||
$this->timer[] = $this->loop->addPeriodicTimer(
|
||||
floor($connection->getKeepAlive() * 0.75),
|
||||
function () {
|
||||
$this->startFlow(new OutgoingPingFlow());
|
||||
}
|
||||
);
|
||||
|
||||
$deferred->resolve($connection);
|
||||
})->otherwise(function (\Exception $e) use ($deferred) {
|
||||
$deferred->reject($e);
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming data.
|
||||
*
|
||||
* @param string $data
|
||||
*/
|
||||
private function handleReceive($data)
|
||||
{
|
||||
if (!$this->isConnected && !$this->isConnecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
$flowCount = count($this->receivingFlows);
|
||||
|
||||
$packets = $this->parser->push($data);
|
||||
foreach ($packets as $packet) {
|
||||
$this->handlePacket($packet);
|
||||
}
|
||||
|
||||
if ($flowCount > count($this->receivingFlows)) {
|
||||
$this->receivingFlows = array_values($this->receivingFlows);
|
||||
}
|
||||
|
||||
$this->handleSend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an incoming packet.
|
||||
*
|
||||
* @param Packet $packet
|
||||
*/
|
||||
private function handlePacket(Packet $packet)
|
||||
{
|
||||
switch ($packet->getPacketType()) {
|
||||
case Packet::TYPE_PUBLISH:
|
||||
/* @var PublishRequestPacket $packet */
|
||||
$message = new DefaultMessage(
|
||||
$packet->getTopic(),
|
||||
$packet->getPayload(),
|
||||
$packet->getQosLevel(),
|
||||
$packet->isRetained(),
|
||||
$packet->isDuplicate()
|
||||
);
|
||||
|
||||
$this->startFlow(new IncomingPublishFlow($message, $packet->getIdentifier()));
|
||||
break;
|
||||
case Packet::TYPE_CONNACK:
|
||||
case Packet::TYPE_PINGRESP:
|
||||
case Packet::TYPE_SUBACK:
|
||||
case Packet::TYPE_UNSUBACK:
|
||||
case Packet::TYPE_PUBREL:
|
||||
case Packet::TYPE_PUBACK:
|
||||
case Packet::TYPE_PUBREC:
|
||||
case Packet::TYPE_PUBCOMP:
|
||||
$flowFound = false;
|
||||
foreach ($this->receivingFlows as $index => $flow) {
|
||||
if ($flow->accept($packet)) {
|
||||
$flowFound = true;
|
||||
|
||||
unset($this->receivingFlows[$index]);
|
||||
$this->continueFlow($flow, $packet);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$flowFound) {
|
||||
$this->emitWarning(
|
||||
new \LogicException(sprintf('Received unexpected packet of type %d.', $packet->getPacketType()))
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->emitWarning(
|
||||
new \LogicException(sprintf('Cannot handle packet of type %d.', $packet->getPacketType()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles outgoing packets.
|
||||
*/
|
||||
private function handleSend()
|
||||
{
|
||||
$flow = null;
|
||||
if ($this->writtenFlow !== null) {
|
||||
$flow = $this->writtenFlow;
|
||||
$this->writtenFlow = null;
|
||||
}
|
||||
|
||||
if (count($this->sendingFlows) > 0) {
|
||||
$this->writtenFlow = array_shift($this->sendingFlows);
|
||||
$this->stream->write($this->writtenFlow->getPacket());
|
||||
}
|
||||
|
||||
if ($flow !== null) {
|
||||
if ($flow->isFinished()) {
|
||||
$this->loop->nextTick(function () use ($flow) {
|
||||
$this->finishFlow($flow);
|
||||
});
|
||||
} else {
|
||||
$this->receivingFlows[] = $flow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles closing of the stream.
|
||||
*/
|
||||
private function handleClose()
|
||||
{
|
||||
foreach ($this->timer as $timer) {
|
||||
$this->loop->cancelTimer($timer);
|
||||
}
|
||||
|
||||
$this->timer = [];
|
||||
|
||||
$connection = $this->connection;
|
||||
|
||||
$this->isConnecting = false;
|
||||
$this->isDisconnecting = false;
|
||||
$this->isConnected = false;
|
||||
$this->connection = null;
|
||||
$this->stream = null;
|
||||
|
||||
if ($connection !== null) {
|
||||
$this->emit('close', [$connection, $this]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors of the stream.
|
||||
*
|
||||
* @param \Exception $e
|
||||
*/
|
||||
private function handleError(\Exception $e)
|
||||
{
|
||||
$this->emitError($e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the given flow.
|
||||
*
|
||||
* @param Flow $flow
|
||||
* @param bool $isSilent
|
||||
*
|
||||
* @return ExtendedPromiseInterface
|
||||
*/
|
||||
private function startFlow(Flow $flow, $isSilent = false)
|
||||
{
|
||||
try {
|
||||
$packet = $flow->start();
|
||||
} catch (\Exception $e) {
|
||||
$this->emitError($e);
|
||||
|
||||
return new RejectedPromise($e);
|
||||
}
|
||||
|
||||
$deferred = new Deferred();
|
||||
$internalFlow = new ReactFlow($flow, $deferred, $packet, $isSilent);
|
||||
|
||||
if ($packet !== null) {
|
||||
if ($this->writtenFlow !== null) {
|
||||
$this->sendingFlows[] = $internalFlow;
|
||||
} else {
|
||||
$this->stream->write($packet);
|
||||
$this->writtenFlow = $internalFlow;
|
||||
$this->handleSend();
|
||||
}
|
||||
} else {
|
||||
$this->loop->nextTick(function () use ($internalFlow) {
|
||||
$this->finishFlow($internalFlow);
|
||||
});
|
||||
}
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Continues the given flow.
|
||||
*
|
||||
* @param ReactFlow $flow
|
||||
* @param Packet $packet
|
||||
*/
|
||||
private function continueFlow(ReactFlow $flow, Packet $packet)
|
||||
{
|
||||
try {
|
||||
$response = $flow->next($packet);
|
||||
} catch (\Exception $e) {
|
||||
$this->emitError($e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($response !== null) {
|
||||
if ($this->writtenFlow !== null) {
|
||||
$this->sendingFlows[] = $flow;
|
||||
} else {
|
||||
$this->stream->write($response);
|
||||
$this->writtenFlow = $flow;
|
||||
$this->handleSend();
|
||||
}
|
||||
} elseif ($flow->isFinished()) {
|
||||
$this->loop->nextTick(function () use ($flow) {
|
||||
$this->finishFlow($flow);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the given flow.
|
||||
*
|
||||
* @param ReactFlow $flow
|
||||
*/
|
||||
private function finishFlow(ReactFlow $flow)
|
||||
{
|
||||
if ($flow->isSuccess()) {
|
||||
if (!$flow->isSilent()) {
|
||||
$this->emit($flow->getCode(), [$flow->getResult(), $this]);
|
||||
}
|
||||
|
||||
$flow->getDeferred()->resolve($flow->getResult());
|
||||
} else {
|
||||
$result = new \RuntimeException($flow->getErrorMessage());
|
||||
$this->emitWarning($result);
|
||||
|
||||
$flow->getDeferred()->reject($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans previous session by rejecting all pending flows.
|
||||
*/
|
||||
private function cleanPreviousSession()
|
||||
{
|
||||
$error = new \RuntimeException('Connection has been closed.');
|
||||
|
||||
foreach ($this->receivingFlows as $receivingFlow) {
|
||||
$receivingFlow->getDeferred()->reject($error);
|
||||
}
|
||||
|
||||
foreach ($this->sendingFlows as $sendingFlow) {
|
||||
$sendingFlow->getDeferred()->reject($error);
|
||||
}
|
||||
|
||||
$this->receivingFlows = [];
|
||||
$this->sendingFlows = [];
|
||||
}
|
||||
}
|
||||
21
vendor/binsoul/net-mqtt/LICENSE.md
vendored
Executable file
21
vendor/binsoul/net-mqtt/LICENSE.md
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
# The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Sebastian Mößler <code@binsoul.de>
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
36
vendor/binsoul/net-mqtt/README.md
vendored
Executable file
36
vendor/binsoul/net-mqtt/README.md
vendored
Executable file
@@ -0,0 +1,36 @@
|
||||
# net-mqtt
|
||||
|
||||
[![Latest Version on Packagist][ico-version]][link-packagist]
|
||||
[![Software License][ico-license]](LICENSE.md)
|
||||
[![Total Downloads][ico-downloads]][link-downloads]
|
||||
|
||||
MQTT is a machine-to-machine (M2M) / Internet of Things (IoT) connectivity protocol. It provides a lightweight method of carrying out messaging using a publish/subscribe model.
|
||||
|
||||
This package implements the MQTT protocol versions 3.1 and 3.1.1.
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
Via composer:
|
||||
|
||||
``` bash
|
||||
$ composer require binsoul/net-mqtt
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
``` bash
|
||||
$ composer test
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||
|
||||
[ico-version]: https://img.shields.io/packagist/v/binsoul/net-mqtt.svg?style=flat-square
|
||||
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
|
||||
[ico-downloads]: https://img.shields.io/packagist/dt/binsoul/net-mqtt.svg?style=flat-square
|
||||
|
||||
[link-packagist]: https://packagist.org/packages/binsoul/net-mqtt
|
||||
[link-downloads]: https://packagist.org/packages/binsoul/net-mqtt
|
||||
[link-author]: https://github.com/binsoul
|
||||
47
vendor/binsoul/net-mqtt/composer.json
vendored
Executable file
47
vendor/binsoul/net-mqtt/composer.json
vendored
Executable file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "binsoul/net-mqtt",
|
||||
"description": "MQTT protocol implementation",
|
||||
"keywords": [
|
||||
"net",
|
||||
"mqtt"
|
||||
],
|
||||
"homepage": "https://github.com/binsoul/net-mqtt",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Mößler",
|
||||
"email": "code@binsoul.de",
|
||||
"homepage": "https://github.com/binsoul",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "~5.6|~7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0||~5.0",
|
||||
"friendsofphp/php-cs-fixer": "~1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BinSoul\\Net\\Mqtt\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"BinSoul\\Test\\Net\\Mqtt\\": "tests"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit",
|
||||
"fix-style": [
|
||||
"php-cs-fixer fix src",
|
||||
"php-cs-fixer fix tests"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
90
vendor/binsoul/net-mqtt/src/Connection.php
vendored
Executable file
90
vendor/binsoul/net-mqtt/src/Connection.php
vendored
Executable file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Represents the connection of a MQTT client.
|
||||
*/
|
||||
interface Connection
|
||||
{
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getProtocol();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientID();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCleanSession();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPassword();
|
||||
|
||||
/**
|
||||
* @return Message|null
|
||||
*/
|
||||
public function getWill();
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getKeepAlive();
|
||||
|
||||
/**
|
||||
* Returns a new connection with the given protocol.
|
||||
*
|
||||
* @param int $protocol
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withProtocol($protocol);
|
||||
|
||||
/**
|
||||
* Returns a new connection with the given client id.
|
||||
*
|
||||
* @param string $clientID
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withClientID($clientID);
|
||||
|
||||
/**
|
||||
* Returns a new connection with the given credentials.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withCredentials($username, $password);
|
||||
|
||||
/**
|
||||
* Returns a new connection with the given will.
|
||||
*
|
||||
* @param Message $will
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withWill(Message $will);
|
||||
|
||||
/**
|
||||
* Returns a new connection with the given keep alive timeout.
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withKeepAlive($timeout);
|
||||
}
|
||||
129
vendor/binsoul/net-mqtt/src/DefaultConnection.php
vendored
Executable file
129
vendor/binsoul/net-mqtt/src/DefaultConnection.php
vendored
Executable file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Provides a default implementation of the {@see Connection} interface.
|
||||
*/
|
||||
class DefaultConnection implements Connection
|
||||
{
|
||||
/** @var string */
|
||||
private $username;
|
||||
/** @var string */
|
||||
private $password;
|
||||
/** @var Message|null */
|
||||
private $will;
|
||||
/** @var string */
|
||||
private $clientID;
|
||||
/** @var int */
|
||||
private $keepAlive;
|
||||
/** @var int */
|
||||
private $protocol;
|
||||
/** @var bool */
|
||||
private $clean;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param Message|null $will
|
||||
* @param string $clientID
|
||||
* @param int $keepAlive
|
||||
* @param int $protocol
|
||||
* @param bool $clean
|
||||
*/
|
||||
public function __construct(
|
||||
$username = '',
|
||||
$password = '',
|
||||
Message $will = null,
|
||||
$clientID = '',
|
||||
$keepAlive = 60,
|
||||
$protocol = 4,
|
||||
$clean = true
|
||||
) {
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
$this->will = $will;
|
||||
$this->clientID = $clientID;
|
||||
$this->keepAlive = $keepAlive;
|
||||
$this->protocol = $protocol;
|
||||
$this->clean = $clean;
|
||||
}
|
||||
|
||||
public function getProtocol()
|
||||
{
|
||||
return $this->protocol;
|
||||
}
|
||||
|
||||
public function getClientID()
|
||||
{
|
||||
return $this->clientID;
|
||||
}
|
||||
|
||||
public function isCleanSession()
|
||||
{
|
||||
return $this->clean;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getWill()
|
||||
{
|
||||
return $this->will;
|
||||
}
|
||||
|
||||
public function getKeepAlive()
|
||||
{
|
||||
return $this->keepAlive;
|
||||
}
|
||||
|
||||
public function withProtocol($protocol)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->protocol = $protocol;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function withClientID($clientID)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->clientID = $clientID;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function withCredentials($username, $password)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->username = $username;
|
||||
$result->password = $password;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function withWill(Message $will = null)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->will = $will;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function withKeepAlive($timeout)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->keepAlive = $timeout;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
38
vendor/binsoul/net-mqtt/src/DefaultIdentifierGenerator.php
vendored
Executable file
38
vendor/binsoul/net-mqtt/src/DefaultIdentifierGenerator.php
vendored
Executable file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Provides a default implementation of the {@see IdentifierGenerator} interface.
|
||||
*/
|
||||
class DefaultIdentifierGenerator implements IdentifierGenerator
|
||||
{
|
||||
/** @var int */
|
||||
private $currentIdentifier = 0;
|
||||
|
||||
public function generatePacketID()
|
||||
{
|
||||
++$this->currentIdentifier;
|
||||
if ($this->currentIdentifier > 0xFFFF) {
|
||||
$this->currentIdentifier = 1;
|
||||
}
|
||||
|
||||
return $this->currentIdentifier;
|
||||
}
|
||||
|
||||
public function generateClientID()
|
||||
{
|
||||
if (function_exists('random_bytes')) {
|
||||
$data = random_bytes(9);
|
||||
} elseif (function_exists('openssl_random_pseudo_bytes')) {
|
||||
$data = openssl_random_pseudo_bytes(9);
|
||||
} else {
|
||||
$data = '';
|
||||
for ($i = 1; $i <= 8; ++$i) {
|
||||
$data = chr(mt_rand(0, 255)).$data;
|
||||
}
|
||||
}
|
||||
|
||||
return 'BNMCR'.bin2hex($data);
|
||||
}
|
||||
}
|
||||
119
vendor/binsoul/net-mqtt/src/DefaultMessage.php
vendored
Executable file
119
vendor/binsoul/net-mqtt/src/DefaultMessage.php
vendored
Executable file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Provides a default implementation of the {@see Message} interface.
|
||||
*/
|
||||
class DefaultMessage implements Message
|
||||
{
|
||||
/** @var string */
|
||||
private $topic;
|
||||
/** @var string */
|
||||
private $payload;
|
||||
/** @var bool */
|
||||
private $isRetained;
|
||||
/** @var bool */
|
||||
private $isDuplicate = false;
|
||||
/** @var int */
|
||||
private $qosLevel;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param string $topic
|
||||
* @param string $payload
|
||||
* @param int $qosLevel
|
||||
* @param bool $retain
|
||||
* @param bool $isDuplicate
|
||||
*/
|
||||
public function __construct($topic, $payload = '', $qosLevel = 0, $retain = false, $isDuplicate = false)
|
||||
{
|
||||
$this->topic = $topic;
|
||||
$this->payload = $payload;
|
||||
$this->isRetained = $retain;
|
||||
$this->qosLevel = $qosLevel;
|
||||
$this->isDuplicate = $isDuplicate;
|
||||
}
|
||||
|
||||
public function getTopic()
|
||||
{
|
||||
return $this->topic;
|
||||
}
|
||||
|
||||
public function getPayload()
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
public function getQosLevel()
|
||||
{
|
||||
return $this->qosLevel;
|
||||
}
|
||||
|
||||
public function isDuplicate()
|
||||
{
|
||||
return $this->isDuplicate;
|
||||
}
|
||||
|
||||
public function isRetained()
|
||||
{
|
||||
return $this->isRetained;
|
||||
}
|
||||
|
||||
public function withTopic($topic)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->topic = $topic;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function withPayload($payload)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->payload = $payload;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function withQosLevel($level)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->qosLevel = $level;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function retain()
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->isRetained = true;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function release()
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->isRetained = false;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function duplicate()
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->isDuplicate = true;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function original()
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->isDuplicate = false;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
52
vendor/binsoul/net-mqtt/src/DefaultSubscription.php
vendored
Executable file
52
vendor/binsoul/net-mqtt/src/DefaultSubscription.php
vendored
Executable file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Provides a default implementation of the {@see Subscription} interface.
|
||||
*/
|
||||
class DefaultSubscription implements Subscription
|
||||
{
|
||||
/** @var string */
|
||||
private $filter;
|
||||
/** @var int */
|
||||
private $qosLevel;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param string $filter
|
||||
* @param int $qosLevel
|
||||
*/
|
||||
public function __construct($filter, $qosLevel = 0)
|
||||
{
|
||||
$this->filter = $filter;
|
||||
$this->qosLevel = $qosLevel;
|
||||
}
|
||||
|
||||
public function getFilter()
|
||||
{
|
||||
return $this->filter;
|
||||
}
|
||||
|
||||
public function getQosLevel()
|
||||
{
|
||||
return $this->qosLevel;
|
||||
}
|
||||
|
||||
public function withFilter($filter)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->filter = $filter;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function withQosLevel($level)
|
||||
{
|
||||
$result = clone $this;
|
||||
$result->qosLevel = $level;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
10
vendor/binsoul/net-mqtt/src/Exception/EndOfStreamException.php
vendored
Executable file
10
vendor/binsoul/net-mqtt/src/Exception/EndOfStreamException.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Exception;
|
||||
|
||||
/**
|
||||
* Will be thrown if the end of a stream is reached but more bytes were requested.
|
||||
*/
|
||||
class EndOfStreamException extends \Exception
|
||||
{
|
||||
}
|
||||
10
vendor/binsoul/net-mqtt/src/Exception/MalformedPacketException.php
vendored
Executable file
10
vendor/binsoul/net-mqtt/src/Exception/MalformedPacketException.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Exception;
|
||||
|
||||
/**
|
||||
* Will be thrown if a packet is malformed.
|
||||
*/
|
||||
class MalformedPacketException extends \Exception
|
||||
{
|
||||
}
|
||||
10
vendor/binsoul/net-mqtt/src/Exception/UnknownPacketTypeException.php
vendored
Executable file
10
vendor/binsoul/net-mqtt/src/Exception/UnknownPacketTypeException.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Exception;
|
||||
|
||||
/**
|
||||
* Will be thrown if a packet type is unknown.
|
||||
*/
|
||||
class UnknownPacketTypeException extends \Exception
|
||||
{
|
||||
}
|
||||
71
vendor/binsoul/net-mqtt/src/Flow.php
vendored
Executable file
71
vendor/binsoul/net-mqtt/src/Flow.php
vendored
Executable file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Represents a sequence of packages exchanged between clients and brokers.
|
||||
*/
|
||||
interface Flow
|
||||
{
|
||||
/**
|
||||
* Returns the unique code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCode();
|
||||
|
||||
/**
|
||||
* Starts the flow.
|
||||
*
|
||||
* @return Packet|null First packet of the flow
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function start();
|
||||
|
||||
/**
|
||||
* Indicates if the flow can handle the given packet.
|
||||
*
|
||||
* @param Packet $packet Packet to accept
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function accept(Packet $packet);
|
||||
|
||||
/**
|
||||
* Continues the flow.
|
||||
*
|
||||
* @param Packet $packet Packet to respond
|
||||
*
|
||||
* @return Packet|null Next packet of the flow
|
||||
*/
|
||||
public function next(Packet $packet);
|
||||
|
||||
/**
|
||||
* Indicates if the flow is finished.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFinished();
|
||||
|
||||
/**
|
||||
* Indicates if the flow finished successfully.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuccess();
|
||||
|
||||
/**
|
||||
* Returns the result of the flow if it finished successfully.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResult();
|
||||
|
||||
/**
|
||||
* Returns an error message if the flow didn't finish successfully.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getErrorMessage();
|
||||
}
|
||||
74
vendor/binsoul/net-mqtt/src/Flow/AbstractFlow.php
vendored
Executable file
74
vendor/binsoul/net-mqtt/src/Flow/AbstractFlow.php
vendored
Executable file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\Flow;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Provides an abstract implementation of the {@see Flow} interface.
|
||||
*/
|
||||
abstract class AbstractFlow implements Flow
|
||||
{
|
||||
/** @var bool */
|
||||
private $isFinished = false;
|
||||
/** @var bool */
|
||||
private $isSuccess = false;
|
||||
/** @var mixed */
|
||||
private $result;
|
||||
/** @var string */
|
||||
private $error = '';
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
}
|
||||
|
||||
public function isFinished()
|
||||
{
|
||||
return $this->isFinished;
|
||||
}
|
||||
|
||||
public function isSuccess()
|
||||
{
|
||||
return $this->isFinished && $this->isSuccess;
|
||||
}
|
||||
|
||||
public function getResult()
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the flow as successful and sets the result.
|
||||
*
|
||||
* @param mixed|null $result
|
||||
*/
|
||||
protected function succeed($result = null)
|
||||
{
|
||||
$this->isFinished = true;
|
||||
$this->isSuccess = true;
|
||||
$this->result = $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the flow as failed and sets the error message.
|
||||
*
|
||||
* @param string $error
|
||||
*/
|
||||
protected function fail($error = '')
|
||||
{
|
||||
$this->isFinished = true;
|
||||
$this->isSuccess = false;
|
||||
$this->error = $error;
|
||||
}
|
||||
}
|
||||
23
vendor/binsoul/net-mqtt/src/Flow/IncomingPingFlow.php
vendored
Executable file
23
vendor/binsoul/net-mqtt/src/Flow/IncomingPingFlow.php
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\Packet\PingResponsePacket;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an incoming PING packet.
|
||||
*/
|
||||
class IncomingPingFlow extends AbstractFlow
|
||||
{
|
||||
public function getCode()
|
||||
{
|
||||
return 'pong';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$this->succeed();
|
||||
|
||||
return new PingResponsePacket();
|
||||
}
|
||||
}
|
||||
80
vendor/binsoul/net-mqtt/src/Flow/IncomingPublishFlow.php
vendored
Executable file
80
vendor/binsoul/net-mqtt/src/Flow/IncomingPublishFlow.php
vendored
Executable file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\Message;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishAckPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishCompletePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishReceivedPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishReleasePacket;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an incoming PUBLISH packet.
|
||||
*/
|
||||
class IncomingPublishFlow extends AbstractFlow
|
||||
{
|
||||
/** @var int|null */
|
||||
private $identifier;
|
||||
/** @var Message */
|
||||
private $message;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param Message $message
|
||||
* @param int|null $identifier
|
||||
*/
|
||||
public function __construct(Message $message, $identifier = null)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return 'message';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$packet = null;
|
||||
$emit = true;
|
||||
if ($this->message->getQosLevel() === 1) {
|
||||
$packet = new PublishAckPacket();
|
||||
} elseif ($this->message->getQosLevel() === 2) {
|
||||
$packet = new PublishReceivedPacket();
|
||||
$emit = false;
|
||||
}
|
||||
|
||||
if ($packet !== null) {
|
||||
$packet->setIdentifier($this->identifier);
|
||||
}
|
||||
|
||||
if ($emit) {
|
||||
$this->succeed($this->message);
|
||||
}
|
||||
|
||||
return $packet;
|
||||
}
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
if ($this->message->getQosLevel() !== 2 || $packet->getPacketType() !== Packet::TYPE_PUBREL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* @var PublishReleasePacket $packet */
|
||||
return $packet->getIdentifier() === $this->identifier;
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
$this->succeed($this->message);
|
||||
|
||||
$response = new PublishCompletePacket();
|
||||
$response->setIdentifier($this->identifier);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
70
vendor/binsoul/net-mqtt/src/Flow/OutgoingConnectFlow.php
vendored
Executable file
70
vendor/binsoul/net-mqtt/src/Flow/OutgoingConnectFlow.php
vendored
Executable file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\Connection;
|
||||
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use BinSoul\Net\Mqtt\Packet\ConnectRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\ConnectResponsePacket;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an outgoing CONNECT packet.
|
||||
*/
|
||||
class OutgoingConnectFlow extends AbstractFlow
|
||||
{
|
||||
/** @var Connection */
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param Connection $connection
|
||||
* @param IdentifierGenerator $generator
|
||||
*/
|
||||
public function __construct(Connection $connection, IdentifierGenerator $generator)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
|
||||
if ($this->connection->getClientID() === '') {
|
||||
$this->connection = $this->connection->withClientID($generator->generateClientID());
|
||||
}
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return 'connect';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$packet = new ConnectRequestPacket();
|
||||
$packet->setProtocolLevel($this->connection->getProtocol());
|
||||
$packet->setKeepAlive($this->connection->getKeepAlive());
|
||||
$packet->setClientID($this->connection->getClientID());
|
||||
$packet->setCleanSession($this->connection->isCleanSession());
|
||||
$packet->setUsername($this->connection->getUsername());
|
||||
$packet->setPassword($this->connection->getPassword());
|
||||
$will = $this->connection->getWill();
|
||||
if ($will !== null && $will->getTopic() !== '' && $will->getPayload() !== '') {
|
||||
$packet->setWill($will->getTopic(), $will->getPayload(), $will->getQosLevel(), $will->isRetained());
|
||||
}
|
||||
|
||||
return $packet;
|
||||
}
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
return $packet->getPacketType() === Packet::TYPE_CONNACK;
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
/** @var ConnectResponsePacket $packet */
|
||||
if ($packet->isSuccess()) {
|
||||
$this->succeed($this->connection);
|
||||
} else {
|
||||
$this->fail($packet->getErrorName());
|
||||
}
|
||||
}
|
||||
}
|
||||
37
vendor/binsoul/net-mqtt/src/Flow/OutgoingDisconnectFlow.php
vendored
Executable file
37
vendor/binsoul/net-mqtt/src/Flow/OutgoingDisconnectFlow.php
vendored
Executable file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\Connection;
|
||||
use BinSoul\Net\Mqtt\Packet\DisconnectRequestPacket;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an outgoing DISCONNECT packet.
|
||||
*/
|
||||
class OutgoingDisconnectFlow extends AbstractFlow
|
||||
{
|
||||
/** @var Connection */
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param Connection $connection
|
||||
*/
|
||||
public function __construct(Connection $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return 'disconnect';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$this->succeed($this->connection);
|
||||
|
||||
return new DisconnectRequestPacket();
|
||||
}
|
||||
}
|
||||
32
vendor/binsoul/net-mqtt/src/Flow/OutgoingPingFlow.php
vendored
Executable file
32
vendor/binsoul/net-mqtt/src/Flow/OutgoingPingFlow.php
vendored
Executable file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use BinSoul\Net\Mqtt\Packet\PingRequestPacket;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an outgoing PING packet.
|
||||
*/
|
||||
class OutgoingPingFlow extends AbstractFlow
|
||||
{
|
||||
public function getCode()
|
||||
{
|
||||
return 'ping';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
return new PingRequestPacket();
|
||||
}
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
return $packet->getPacketType() === Packet::TYPE_PINGRESP;
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
$this->succeed();
|
||||
}
|
||||
}
|
||||
102
vendor/binsoul/net-mqtt/src/Flow/OutgoingPublishFlow.php
vendored
Executable file
102
vendor/binsoul/net-mqtt/src/Flow/OutgoingPublishFlow.php
vendored
Executable file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||
use BinSoul\Net\Mqtt\Message;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishAckPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishCompletePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishReceivedPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishReleasePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishRequestPacket;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an outgoing PUBLISH packet.
|
||||
*/
|
||||
class OutgoingPublishFlow extends AbstractFlow
|
||||
{
|
||||
/** @var int|null */
|
||||
private $identifier;
|
||||
/** @var Message */
|
||||
private $message;
|
||||
/** @var bool */
|
||||
private $receivedPubRec = false;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param Message $message
|
||||
* @param IdentifierGenerator $generator
|
||||
*/
|
||||
public function __construct(Message $message, IdentifierGenerator $generator)
|
||||
{
|
||||
$this->message = $message;
|
||||
if ($this->message->getQosLevel() > 0) {
|
||||
$this->identifier = $generator->generatePacketID();
|
||||
}
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return 'publish';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$packet = new PublishRequestPacket();
|
||||
$packet->setTopic($this->message->getTopic());
|
||||
$packet->setPayload($this->message->getPayload());
|
||||
$packet->setRetained($this->message->isRetained());
|
||||
$packet->setDuplicate($this->message->isDuplicate());
|
||||
$packet->setQosLevel($this->message->getQosLevel());
|
||||
|
||||
if ($this->message->getQosLevel() === 0) {
|
||||
$this->succeed($this->message);
|
||||
} else {
|
||||
$packet->setIdentifier($this->identifier);
|
||||
}
|
||||
|
||||
return $packet;
|
||||
}
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
if ($this->message->getQosLevel() === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$packetType = $packet->getPacketType();
|
||||
|
||||
if ($packetType === Packet::TYPE_PUBACK && $this->message->getQosLevel() === 1) {
|
||||
/* @var PublishAckPacket $packet */
|
||||
return $packet->getIdentifier() === $this->identifier;
|
||||
} elseif ($this->message->getQosLevel() === 2) {
|
||||
if ($packetType === Packet::TYPE_PUBREC) {
|
||||
/* @var PublishReceivedPacket $packet */
|
||||
return $packet->getIdentifier() === $this->identifier;
|
||||
} elseif ($this->receivedPubRec && $packetType === Packet::TYPE_PUBCOMP) {
|
||||
/* @var PublishCompletePacket $packet */
|
||||
return $packet->getIdentifier() === $this->identifier;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
$packetType = $packet->getPacketType();
|
||||
|
||||
if ($packetType === Packet::TYPE_PUBACK || $packetType === Packet::TYPE_PUBCOMP) {
|
||||
$this->succeed($this->message);
|
||||
} elseif ($packetType === Packet::TYPE_PUBREC) {
|
||||
$this->receivedPubRec = true;
|
||||
|
||||
$response = new PublishReleasePacket();
|
||||
$response->setIdentifier($this->identifier);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
vendor/binsoul/net-mqtt/src/Flow/OutgoingSubscribeFlow.php
vendored
Executable file
82
vendor/binsoul/net-mqtt/src/Flow/OutgoingSubscribeFlow.php
vendored
Executable file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use BinSoul\Net\Mqtt\Packet\SubscribeRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\SubscribeResponsePacket;
|
||||
use BinSoul\Net\Mqtt\Subscription;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an outgoing SUBSCRIBE packet.
|
||||
*/
|
||||
class OutgoingSubscribeFlow extends AbstractFlow
|
||||
{
|
||||
/** @var int */
|
||||
private $identifier;
|
||||
/** @var Subscription[] */
|
||||
private $subscriptions;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param Subscription[] $subscriptions
|
||||
* @param IdentifierGenerator $generator
|
||||
*/
|
||||
public function __construct(array $subscriptions, IdentifierGenerator $generator)
|
||||
{
|
||||
$this->subscriptions = array_values($subscriptions);
|
||||
$this->identifier = $generator->generatePacketID();
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return 'subscribe';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$packet = new SubscribeRequestPacket();
|
||||
$packet->setTopic($this->subscriptions[0]->getFilter());
|
||||
$packet->setQosLevel($this->subscriptions[0]->getQosLevel());
|
||||
$packet->setIdentifier($this->identifier);
|
||||
|
||||
return $packet;
|
||||
}
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
if ($packet->getPacketType() !== Packet::TYPE_SUBACK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* @var SubscribeResponsePacket $packet */
|
||||
return $packet->getIdentifier() === $this->identifier;
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
/* @var SubscribeResponsePacket $packet */
|
||||
$returnCodes = $packet->getReturnCodes();
|
||||
if (count($returnCodes) !== count($this->subscriptions)) {
|
||||
throw new \LogicException(
|
||||
sprintf(
|
||||
'SUBACK: Expected %d return codes but got %d.',
|
||||
count($this->subscriptions),
|
||||
count($returnCodes)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($returnCodes as $index => $code) {
|
||||
if ($packet->isError($code)) {
|
||||
$this->fail(sprintf('Failed to subscribe to "%s".', $this->subscriptions[$index]->getFilter()));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->succeed($this->subscriptions[0]);
|
||||
}
|
||||
}
|
||||
61
vendor/binsoul/net-mqtt/src/Flow/OutgoingUnsubscribeFlow.php
vendored
Executable file
61
vendor/binsoul/net-mqtt/src/Flow/OutgoingUnsubscribeFlow.php
vendored
Executable file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Flow;
|
||||
|
||||
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
use BinSoul\Net\Mqtt\Packet\UnsubscribeRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\UnsubscribeResponsePacket;
|
||||
use BinSoul\Net\Mqtt\Subscription;
|
||||
|
||||
/**
|
||||
* Represents a flow starting with an outgoing UNSUBSCRIBE packet.
|
||||
*/
|
||||
class OutgoingUnsubscribeFlow extends AbstractFlow
|
||||
{
|
||||
/** @var int */
|
||||
private $identifier;
|
||||
/** @var Subscription[] */
|
||||
private $subscriptions;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param Subscription[] $subscriptions
|
||||
* @param IdentifierGenerator $generator
|
||||
*/
|
||||
public function __construct(array $subscriptions, IdentifierGenerator $generator)
|
||||
{
|
||||
$this->subscriptions = array_values($subscriptions);
|
||||
$this->identifier = $generator->generatePacketID();
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return 'unsubscribe';
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$packet = new UnsubscribeRequestPacket();
|
||||
$packet->setTopic($this->subscriptions[0]->getFilter());
|
||||
$packet->setIdentifier($this->identifier);
|
||||
|
||||
return $packet;
|
||||
}
|
||||
|
||||
public function accept(Packet $packet)
|
||||
{
|
||||
if ($packet->getPacketType() !== Packet::TYPE_UNSUBACK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* @var UnsubscribeResponsePacket $packet */
|
||||
return $packet->getIdentifier() === $this->identifier;
|
||||
}
|
||||
|
||||
public function next(Packet $packet)
|
||||
{
|
||||
$this->succeed($this->subscriptions[0]);
|
||||
}
|
||||
}
|
||||
23
vendor/binsoul/net-mqtt/src/IdentifierGenerator.php
vendored
Executable file
23
vendor/binsoul/net-mqtt/src/IdentifierGenerator.php
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Generates identifiers.
|
||||
*/
|
||||
interface IdentifierGenerator
|
||||
{
|
||||
/**
|
||||
* Generates a packet identifier between 1 and 0xFFFF.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function generatePacketID();
|
||||
|
||||
/**
|
||||
* Generates a client identifier of up to 23 bytes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateClientID();
|
||||
}
|
||||
99
vendor/binsoul/net-mqtt/src/Message.php
vendored
Executable file
99
vendor/binsoul/net-mqtt/src/Message.php
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Represents a message.
|
||||
*/
|
||||
interface Message
|
||||
{
|
||||
/**
|
||||
* Returns the topic.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTopic();
|
||||
|
||||
/**
|
||||
* Returns the payload.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPayload();
|
||||
|
||||
/**
|
||||
* Returns the quality of service level.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getQosLevel();
|
||||
|
||||
/**
|
||||
* Indicates if the message is a duplicate.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDuplicate();
|
||||
|
||||
/**
|
||||
* Indicates if the message is retained.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRetained();
|
||||
|
||||
/**
|
||||
* Returns a new message with the given topic.
|
||||
*
|
||||
* @param string $topic
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withTopic($topic);
|
||||
|
||||
/**
|
||||
* Returns a new message with the given payload.
|
||||
*
|
||||
* @param string $payload
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withPayload($payload);
|
||||
|
||||
/**
|
||||
* Returns a new message with the given quality of service level.
|
||||
*
|
||||
* @param int $level
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withQosLevel($level);
|
||||
|
||||
/**
|
||||
* Returns a new message flagged as retained.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function retain();
|
||||
|
||||
/**
|
||||
* Returns a new message flagged as not retained.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function release();
|
||||
|
||||
/**
|
||||
* Returns a new message flagged as duplicate.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function duplicate();
|
||||
|
||||
/**
|
||||
* Returns a new message flagged as original.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function original();
|
||||
}
|
||||
52
vendor/binsoul/net-mqtt/src/Packet.php
vendored
Executable file
52
vendor/binsoul/net-mqtt/src/Packet.php
vendored
Executable file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Represent a packet of the MQTT protocol.
|
||||
*/
|
||||
interface Packet
|
||||
{
|
||||
const TYPE_CONNECT = 1;
|
||||
const TYPE_CONNACK = 2;
|
||||
const TYPE_PUBLISH = 3;
|
||||
const TYPE_PUBACK = 4;
|
||||
const TYPE_PUBREC = 5;
|
||||
const TYPE_PUBREL = 6;
|
||||
const TYPE_PUBCOMP = 7;
|
||||
const TYPE_SUBSCRIBE = 8;
|
||||
const TYPE_SUBACK = 9;
|
||||
const TYPE_UNSUBSCRIBE = 10;
|
||||
const TYPE_UNSUBACK = 11;
|
||||
const TYPE_PINGREQ = 12;
|
||||
const TYPE_PINGRESP = 13;
|
||||
const TYPE_DISCONNECT = 14;
|
||||
|
||||
/**
|
||||
* Returns the type of the packet.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPacketType();
|
||||
|
||||
/**
|
||||
* Reads the packet from the given stream.
|
||||
*
|
||||
* @param PacketStream $stream
|
||||
*/
|
||||
public function read(PacketStream $stream);
|
||||
|
||||
/**
|
||||
* Writes the packet to the given stream.
|
||||
*
|
||||
* @param PacketStream $stream
|
||||
*/
|
||||
public function write(PacketStream $stream);
|
||||
|
||||
/**
|
||||
* Returns the serialized form of the packet.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
}
|
||||
279
vendor/binsoul/net-mqtt/src/Packet/BasePacket.php
vendored
Executable file
279
vendor/binsoul/net-mqtt/src/Packet/BasePacket.php
vendored
Executable file
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the base class for all packets.
|
||||
*/
|
||||
abstract class BasePacket implements Packet
|
||||
{
|
||||
/**
|
||||
* Type of the packet. See {@see Packet}.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $packetType = 0;
|
||||
/**
|
||||
* Flags of the packet.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $packetFlags = 0;
|
||||
|
||||
/**
|
||||
* Number of bytes of a variable length packet.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $remainingPacketLength = 0;
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$output = new PacketStream();
|
||||
$this->write($output);
|
||||
|
||||
return $output->getData();
|
||||
}
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
$byte = $stream->readByte();
|
||||
|
||||
if ($byte >> 4 !== static::$packetType) {
|
||||
throw new MalformedPacketException(
|
||||
sprintf(
|
||||
'Expected packet type %02x but got %02x.',
|
||||
$byte >> 4,
|
||||
static::$packetType
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->packetFlags = $byte & 0x0F;
|
||||
$this->readRemainingLength($stream);
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
$stream->writeByte(((static::$packetType & 0x0F) << 4) + ($this->packetFlags & 0x0F));
|
||||
$this->writeRemainingLength($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the remaining length from the given stream.
|
||||
*
|
||||
* @param PacketStream $stream
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
*/
|
||||
private function readRemainingLength(PacketStream $stream)
|
||||
{
|
||||
$this->remainingPacketLength = 0;
|
||||
$multiplier = 1;
|
||||
|
||||
do {
|
||||
$encodedByte = $stream->readByte();
|
||||
|
||||
$this->remainingPacketLength += ($encodedByte & 127) * $multiplier;
|
||||
$multiplier *= 128;
|
||||
|
||||
if ($multiplier > 128 * 128 * 128 * 128) {
|
||||
throw new MalformedPacketException('Malformed remaining length.');
|
||||
}
|
||||
} while (($encodedByte & 128) !== 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the remaining length to the given stream.
|
||||
*
|
||||
* @param PacketStream $stream
|
||||
*/
|
||||
private function writeRemainingLength(PacketStream $stream)
|
||||
{
|
||||
$x = $this->remainingPacketLength;
|
||||
do {
|
||||
$encodedByte = $x % 128;
|
||||
$x = (int) ($x / 128);
|
||||
if ($x > 0) {
|
||||
$encodedByte |= 128;
|
||||
}
|
||||
|
||||
$stream->writeByte($encodedByte);
|
||||
} while ($x > 0);
|
||||
}
|
||||
|
||||
public function getPacketType()
|
||||
{
|
||||
return static::$packetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet flags.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPacketFlags()
|
||||
{
|
||||
return $this->packetFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remaining length.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRemainingPacketLength()
|
||||
{
|
||||
return $this->remainingPacketLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the packet flags have a specific value.
|
||||
*
|
||||
* @param int $value
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function assertPacketFlags($value, $fromPacket = true)
|
||||
{
|
||||
if ($this->packetFlags !== $value) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'Expected flags %02x but got %02x.',
|
||||
$value,
|
||||
$this->packetFlags
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the remaining length is greater than zero and has a specific value.
|
||||
*
|
||||
* @param int|null $value value to test or null if any value greater than zero is valid
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function assertRemainingPacketLength($value = null, $fromPacket = true)
|
||||
{
|
||||
if ($value === null && $this->remainingPacketLength === 0) {
|
||||
$this->throwException('Expected payload but remaining packet length is zero.', $fromPacket);
|
||||
}
|
||||
|
||||
if ($value !== null && $this->remainingPacketLength !== $value) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'Expected remaining packet length of %d bytes but got %d.',
|
||||
$value,
|
||||
$this->remainingPacketLength
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given string is a well-formed MQTT string.
|
||||
*
|
||||
* @param string $value
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function assertValidStringLength($value, $fromPacket = true)
|
||||
{
|
||||
if (strlen($value) > 0xFFFF) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'The string "%s" is longer than 65535 byte.',
|
||||
substr($value, 0, 50)
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given string is a well-formed MQTT string.
|
||||
*
|
||||
* @param string $value
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function assertValidString($value, $fromPacket = true)
|
||||
{
|
||||
$this->assertValidStringLength($value, $fromPacket);
|
||||
|
||||
if (!mb_check_encoding($value, 'UTF-8')) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'The string "%s" is not well-formed UTF-8.',
|
||||
substr($value, 0, 50)
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
|
||||
if (preg_match('/[\xD8-\xDF][\x00-\xFF]|\x00\x00/x', $value)) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'The string "%s" contains invalid characters.',
|
||||
substr($value, 0, 50)
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given quality of service level is valid.
|
||||
*
|
||||
* @param int $level
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function assertValidQosLevel($level, $fromPacket = true)
|
||||
{
|
||||
if ($level < 0 || $level > 2) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'Expected a quality of service level between 0 and 2 but got %d.',
|
||||
$level
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a MalformedPacketException for packet validation and an InvalidArgumentException otherwise.
|
||||
*
|
||||
* @param string $message
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function throwException($message, $fromPacket)
|
||||
{
|
||||
if ($fromPacket) {
|
||||
throw new MalformedPacketException($message);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException($message);
|
||||
}
|
||||
}
|
||||
405
vendor/binsoul/net-mqtt/src/Packet/ConnectRequestPacket.php
vendored
Executable file
405
vendor/binsoul/net-mqtt/src/Packet/ConnectRequestPacket.php
vendored
Executable file
@@ -0,0 +1,405 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the CONNECT packet.
|
||||
*/
|
||||
class ConnectRequestPacket extends BasePacket
|
||||
{
|
||||
/** @var int */
|
||||
private $protocolLevel = 4;
|
||||
/** @var string */
|
||||
private $protocolName = 'MQTT';
|
||||
/** @var int */
|
||||
private $flags = 2;
|
||||
/** @var string */
|
||||
protected $clientID = '';
|
||||
/** @var int */
|
||||
private $keepAlive = 60;
|
||||
/** @var string */
|
||||
private $willTopic = '';
|
||||
/** @var string */
|
||||
private $willMessage = '';
|
||||
/** @var string */
|
||||
private $username = '';
|
||||
/** @var string */
|
||||
private $password = '';
|
||||
|
||||
protected static $packetType = Packet::TYPE_CONNECT;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
$this->assertPacketFlags(0);
|
||||
$this->assertRemainingPacketLength();
|
||||
|
||||
$this->protocolName = $stream->readString();
|
||||
$this->protocolLevel = $stream->readByte();
|
||||
$this->flags = $stream->readByte();
|
||||
$this->keepAlive = $stream->readWord();
|
||||
$this->clientID = $stream->readString();
|
||||
|
||||
if ($this->hasWill()) {
|
||||
$this->willTopic = $stream->readString();
|
||||
$this->willMessage = $stream->readString();
|
||||
}
|
||||
|
||||
if ($this->hasUsername()) {
|
||||
$this->username = $stream->readString();
|
||||
}
|
||||
|
||||
if ($this->hasPassword()) {
|
||||
$this->password = $stream->readString();
|
||||
}
|
||||
|
||||
$this->assertValidWill();
|
||||
$this->assertValidString($this->clientID);
|
||||
$this->assertValidString($this->willTopic);
|
||||
$this->assertValidString($this->username);
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
if ($this->clientID === '') {
|
||||
$this->clientID = 'BinSoul'.mt_rand(100000, 999999);
|
||||
}
|
||||
|
||||
$data = new PacketStream();
|
||||
|
||||
$data->writeString($this->protocolName);
|
||||
$data->writeByte($this->protocolLevel);
|
||||
$data->writeByte($this->flags);
|
||||
$data->writeWord($this->keepAlive);
|
||||
$data->writeString($this->clientID);
|
||||
|
||||
if ($this->hasWill()) {
|
||||
$data->writeString($this->willTopic);
|
||||
$data->writeString($this->willMessage);
|
||||
}
|
||||
|
||||
if ($this->hasUsername()) {
|
||||
$data->writeString($this->username);
|
||||
}
|
||||
|
||||
if ($this->hasPassword()) {
|
||||
$data->writeString($this->password);
|
||||
}
|
||||
|
||||
$this->remainingPacketLength = $data->length();
|
||||
|
||||
parent::write($stream);
|
||||
$stream->write($data->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol level.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getProtocolLevel()
|
||||
{
|
||||
return $this->protocolLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the protocol level.
|
||||
*
|
||||
* @param int $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setProtocolLevel($value)
|
||||
{
|
||||
if ($value < 3 || $value > 4) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown protocol level %d.', $value));
|
||||
}
|
||||
|
||||
$this->protocolLevel = $value;
|
||||
if ($this->protocolLevel === 3) {
|
||||
$this->protocolName = 'MQIsdp';
|
||||
} elseif ($this->protocolLevel === 4) {
|
||||
$this->protocolName = 'MQTT';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClientID()
|
||||
{
|
||||
return $this->clientID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client id.
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function setClientID($value)
|
||||
{
|
||||
$this->clientID = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keep alive time in seconds.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getKeepAlive()
|
||||
{
|
||||
return $this->keepAlive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keep alive time in seconds.
|
||||
*
|
||||
* @param int $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setKeepAlive($value)
|
||||
{
|
||||
if ($value > 65535) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Expected a keep alive time lower than 65535 but got %d.',
|
||||
$value
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->keepAlive = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the clean session flag is set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCleanSession()
|
||||
{
|
||||
return ($this->flags & 2) === 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the clean session flag.
|
||||
*
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setCleanSession($value)
|
||||
{
|
||||
if ($value) {
|
||||
$this->flags |= 2;
|
||||
} else {
|
||||
$this->flags &= ~2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a will is set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasWill()
|
||||
{
|
||||
return ($this->flags & 4) === 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the desired quality of service level of the will.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getWillQosLevel()
|
||||
{
|
||||
return ($this->flags & 24) >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the will should be retained.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isWillRetained()
|
||||
{
|
||||
return ($this->flags & 32) === 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the will topic.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getWillTopic()
|
||||
{
|
||||
return $this->willTopic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the will message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getWillMessage()
|
||||
{
|
||||
return $this->willMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the will.
|
||||
*
|
||||
* @param string $topic
|
||||
* @param string $message
|
||||
* @param int $qosLevel
|
||||
* @param bool $isRetained
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setWill($topic, $message, $qosLevel = 0, $isRetained = false)
|
||||
{
|
||||
$this->assertValidString($topic, false);
|
||||
if ($topic === '') {
|
||||
throw new \InvalidArgumentException('The topic must not be empty.');
|
||||
}
|
||||
|
||||
$this->assertValidStringLength($message, false);
|
||||
if ($message === '') {
|
||||
throw new \InvalidArgumentException('The message must not be empty.');
|
||||
}
|
||||
|
||||
$this->assertValidQosLevel($qosLevel, false);
|
||||
|
||||
$this->willTopic = $topic;
|
||||
$this->willMessage = $message;
|
||||
|
||||
$this->flags |= 4;
|
||||
$this->flags |= ($qosLevel << 3);
|
||||
|
||||
if ($isRetained) {
|
||||
$this->flags |= 32;
|
||||
} else {
|
||||
$this->flags &= ~32;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the will.
|
||||
*/
|
||||
public function removeWill()
|
||||
{
|
||||
$this->flags &= ~60;
|
||||
$this->willTopic = '';
|
||||
$this->willMessage = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a username is set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasUsername()
|
||||
{
|
||||
return $this->flags & 64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setUsername($value)
|
||||
{
|
||||
$this->assertValidString($value, false);
|
||||
|
||||
$this->username = $value;
|
||||
if ($this->username !== '') {
|
||||
$this->flags |= 64;
|
||||
} else {
|
||||
$this->flags &= ~64;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a password is set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPassword()
|
||||
{
|
||||
return $this->flags & 128;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setPassword($value)
|
||||
{
|
||||
$this->assertValidStringLength($value, false);
|
||||
|
||||
$this->password = $value;
|
||||
if ($this->password !== '') {
|
||||
$this->flags |= 128;
|
||||
} else {
|
||||
$this->flags &= ~128;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all will flags and quality of service are correct.
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
*/
|
||||
private function assertValidWill()
|
||||
{
|
||||
if ($this->hasWill()) {
|
||||
$this->assertValidQosLevel($this->getWillQosLevel(), true);
|
||||
} else {
|
||||
if ($this->getWillQosLevel() > 0) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'Expected a will quality of service level of zero but got %d.',
|
||||
$this->getWillQosLevel()
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->isWillRetained()) {
|
||||
$this->throwException('There is not will but the will retain flag is set.', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
111
vendor/binsoul/net-mqtt/src/Packet/ConnectResponsePacket.php
vendored
Executable file
111
vendor/binsoul/net-mqtt/src/Packet/ConnectResponsePacket.php
vendored
Executable file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the CONNACK packet.
|
||||
*/
|
||||
class ConnectResponsePacket extends BasePacket
|
||||
{
|
||||
/** @var string[][] */
|
||||
private static $returnCodes = [
|
||||
0 => [
|
||||
'Connection accepted',
|
||||
'',
|
||||
],
|
||||
1 => [
|
||||
'Unacceptable protocol version',
|
||||
'The Server does not support the level of the MQTT protocol requested by the client.',
|
||||
],
|
||||
2 => [
|
||||
'Identifier rejected',
|
||||
'The client identifier is correct UTF-8 but not allowed by the server.',
|
||||
],
|
||||
3 => [
|
||||
'Server unavailable',
|
||||
'The network connection has been made but the MQTT service is unavailable',
|
||||
],
|
||||
4 => [
|
||||
'Bad user name or password',
|
||||
'The data in the user name or password is malformed.',
|
||||
],
|
||||
5 => [
|
||||
'Not authorized',
|
||||
'The client is not authorized to connect.',
|
||||
],
|
||||
];
|
||||
|
||||
/** @var int */
|
||||
private $flags = 0;
|
||||
/** @var int */
|
||||
private $returnCode;
|
||||
|
||||
protected static $packetType = Packet::TYPE_CONNACK;
|
||||
protected $remainingPacketLength = 2;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
$this->assertPacketFlags(0);
|
||||
$this->assertRemainingPacketLength(2);
|
||||
|
||||
$this->flags = $stream->readByte();
|
||||
$this->returnCode = $stream->readByte();
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
$this->remainingPacketLength = 2;
|
||||
parent::write($stream);
|
||||
|
||||
$stream->writeByte($this->flags);
|
||||
$stream->writeByte($this->returnCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return code.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getReturnCode()
|
||||
{
|
||||
return $this->returnCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the connection was successful.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuccess()
|
||||
{
|
||||
return $this->returnCode === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the connection failed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isError()
|
||||
{
|
||||
return $this->returnCode > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the returned error code.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getErrorName()
|
||||
{
|
||||
if (isset(self::$returnCodes[$this->returnCode])) {
|
||||
return self::$returnCodes[$this->returnCode][0];
|
||||
}
|
||||
|
||||
return 'Error '.$this->returnCode;
|
||||
}
|
||||
}
|
||||
22
vendor/binsoul/net-mqtt/src/Packet/DisconnectRequestPacket.php
vendored
Executable file
22
vendor/binsoul/net-mqtt/src/Packet/DisconnectRequestPacket.php
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the DISCONNECT packet.
|
||||
*/
|
||||
class DisconnectRequestPacket extends BasePacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_DISCONNECT;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
|
||||
$this->assertPacketFlags(0);
|
||||
$this->assertRemainingPacketLength(0);
|
||||
}
|
||||
}
|
||||
62
vendor/binsoul/net-mqtt/src/Packet/IdentifiablePacket.php
vendored
Executable file
62
vendor/binsoul/net-mqtt/src/Packet/IdentifiablePacket.php
vendored
Executable file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Provides methods for packets with an identifier.
|
||||
*/
|
||||
trait IdentifiablePacket
|
||||
{
|
||||
/** @var int */
|
||||
private static $nextIdentifier = 0;
|
||||
/** @var int|null */
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* Returns the identifier or generates a new one.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function generateIdentifier()
|
||||
{
|
||||
if ($this->identifier === null) {
|
||||
++self::$nextIdentifier;
|
||||
self::$nextIdentifier &= 0xFFFF;
|
||||
|
||||
$this->identifier = self::$nextIdentifier;
|
||||
}
|
||||
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier.
|
||||
*
|
||||
* @param int|null $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setIdentifier($value)
|
||||
{
|
||||
if ($value !== null && ($value < 0 || $value > 0xFFFF)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Expected an identifier between 0x0000 and 0xFFFF but got %x',
|
||||
$value
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->identifier = $value;
|
||||
}
|
||||
}
|
||||
42
vendor/binsoul/net-mqtt/src/Packet/IdentifierOnlyPacket.php
vendored
Executable file
42
vendor/binsoul/net-mqtt/src/Packet/IdentifierOnlyPacket.php
vendored
Executable file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
|
||||
/**
|
||||
* Provides a base class for PUB* packets.
|
||||
*/
|
||||
abstract class IdentifierOnlyPacket extends BasePacket
|
||||
{
|
||||
use IdentifiablePacket;
|
||||
|
||||
protected $remainingPacketLength = 2;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
$this->assertPacketFlags($this->getExpectedPacketFlags());
|
||||
$this->assertRemainingPacketLength(2);
|
||||
|
||||
$this->identifier = $stream->readWord();
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
$this->remainingPacketLength = 2;
|
||||
parent::write($stream);
|
||||
|
||||
$stream->writeWord($this->generateIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expected packet flags.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getExpectedPacketFlags()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
22
vendor/binsoul/net-mqtt/src/Packet/PingRequestPacket.php
vendored
Executable file
22
vendor/binsoul/net-mqtt/src/Packet/PingRequestPacket.php
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the PINGREQ packet.
|
||||
*/
|
||||
class PingRequestPacket extends BasePacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_PINGREQ;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
|
||||
$this->assertPacketFlags(0);
|
||||
$this->assertRemainingPacketLength(0);
|
||||
}
|
||||
}
|
||||
22
vendor/binsoul/net-mqtt/src/Packet/PingResponsePacket.php
vendored
Executable file
22
vendor/binsoul/net-mqtt/src/Packet/PingResponsePacket.php
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the PINGRESP packet.
|
||||
*/
|
||||
class PingResponsePacket extends BasePacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_PINGRESP;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
|
||||
$this->assertPacketFlags(0);
|
||||
$this->assertRemainingPacketLength(0);
|
||||
}
|
||||
}
|
||||
13
vendor/binsoul/net-mqtt/src/Packet/PublishAckPacket.php
vendored
Executable file
13
vendor/binsoul/net-mqtt/src/Packet/PublishAckPacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the PUBACK packet.
|
||||
*/
|
||||
class PublishAckPacket extends IdentifierOnlyPacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_PUBACK;
|
||||
}
|
||||
13
vendor/binsoul/net-mqtt/src/Packet/PublishCompletePacket.php
vendored
Executable file
13
vendor/binsoul/net-mqtt/src/Packet/PublishCompletePacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the PUBCOMP packet.
|
||||
*/
|
||||
class PublishCompletePacket extends IdentifierOnlyPacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_PUBCOMP;
|
||||
}
|
||||
13
vendor/binsoul/net-mqtt/src/Packet/PublishReceivedPacket.php
vendored
Executable file
13
vendor/binsoul/net-mqtt/src/Packet/PublishReceivedPacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the PUBREC packet.
|
||||
*/
|
||||
class PublishReceivedPacket extends IdentifierOnlyPacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_PUBREC;
|
||||
}
|
||||
19
vendor/binsoul/net-mqtt/src/Packet/PublishReleasePacket.php
vendored
Executable file
19
vendor/binsoul/net-mqtt/src/Packet/PublishReleasePacket.php
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the PUBREL packet.
|
||||
*/
|
||||
class PublishReleasePacket extends IdentifierOnlyPacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_PUBREL;
|
||||
protected $packetFlags = 2;
|
||||
|
||||
protected function getExpectedPacketFlags()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
176
vendor/binsoul/net-mqtt/src/Packet/PublishRequestPacket.php
vendored
Executable file
176
vendor/binsoul/net-mqtt/src/Packet/PublishRequestPacket.php
vendored
Executable file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the PUBLISH packet.
|
||||
*/
|
||||
class PublishRequestPacket extends BasePacket
|
||||
{
|
||||
use IdentifiablePacket;
|
||||
|
||||
/** @var string */
|
||||
private $topic;
|
||||
/** @var string */
|
||||
private $payload;
|
||||
|
||||
protected static $packetType = Packet::TYPE_PUBLISH;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
$this->assertRemainingPacketLength();
|
||||
|
||||
$originalPosition = $stream->getPosition();
|
||||
$this->topic = $stream->readString();
|
||||
$this->identifier = null;
|
||||
if ($this->getQosLevel() > 0) {
|
||||
$this->identifier = $stream->readWord();
|
||||
}
|
||||
|
||||
$payloadLength = $this->remainingPacketLength - ($stream->getPosition() - $originalPosition);
|
||||
$this->payload = $stream->read($payloadLength);
|
||||
|
||||
$this->assertValidQosLevel($this->getQosLevel());
|
||||
$this->assertValidString($this->topic);
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
$data = new PacketStream();
|
||||
|
||||
$data->writeString($this->topic);
|
||||
if ($this->getQosLevel() > 0) {
|
||||
$data->writeWord($this->generateIdentifier());
|
||||
}
|
||||
|
||||
$data->write($this->payload);
|
||||
|
||||
$this->remainingPacketLength = $data->length();
|
||||
|
||||
parent::write($stream);
|
||||
$stream->write($data->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the topic.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTopic()
|
||||
{
|
||||
return $this->topic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the topic.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setTopic($value)
|
||||
{
|
||||
$this->assertValidString($value, false);
|
||||
if ($value === '') {
|
||||
throw new \InvalidArgumentException('The topic must not be empty.');
|
||||
}
|
||||
|
||||
$this->topic = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payload.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPayload()
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the payload.
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function setPayload($value)
|
||||
{
|
||||
$this->payload = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the packet is a duplicate.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDuplicate()
|
||||
{
|
||||
return ($this->packetFlags & 8) === 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the packet as duplicate.
|
||||
*
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setDuplicate($value)
|
||||
{
|
||||
if ($value) {
|
||||
$this->packetFlags |= 8;
|
||||
} else {
|
||||
$this->packetFlags &= ~8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the packet is retained.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRetained()
|
||||
{
|
||||
return ($this->packetFlags & 1) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the packet as retained.
|
||||
*
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setRetained($value)
|
||||
{
|
||||
if ($value) {
|
||||
$this->packetFlags |= 1;
|
||||
} else {
|
||||
$this->packetFlags &= ~1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quality of service level.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getQosLevel()
|
||||
{
|
||||
return ($this->packetFlags & 6) >> 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quality of service level.
|
||||
*
|
||||
* @param int $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setQosLevel($value)
|
||||
{
|
||||
$this->assertValidQosLevel($value, false);
|
||||
|
||||
$this->packetFlags |= ($value & 3) << 1;
|
||||
}
|
||||
}
|
||||
66
vendor/binsoul/net-mqtt/src/Packet/StrictConnectRequestPacket.php
vendored
Executable file
66
vendor/binsoul/net-mqtt/src/Packet/StrictConnectRequestPacket.php
vendored
Executable file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
|
||||
/**
|
||||
* Represents the CONNECT packet with strict rules for client ids.
|
||||
*/
|
||||
class StrictConnectRequestPacket extends ConnectRequestPacket
|
||||
{
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
|
||||
$this->assertValidClientID($this->clientID, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client id.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setClientID($value)
|
||||
{
|
||||
$this->assertValidClientID($value, false);
|
||||
|
||||
$this->clientID = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a client id is shorter than 24 bytes and only contains characters 0-9, a-z or A-Z.
|
||||
*
|
||||
* @param string $value
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function assertValidClientID($value, $fromPacket)
|
||||
{
|
||||
|
||||
if (strlen($value) > 23) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'Expected client id shorter than 24 bytes but got "%s".',
|
||||
$value
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
|
||||
if ($value !== '' && !ctype_alnum($value)) {
|
||||
$this->throwException(
|
||||
sprintf(
|
||||
'Expected a client id containing characters 0-9, a-z or A-Z but got "%s".',
|
||||
$value
|
||||
),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
101
vendor/binsoul/net-mqtt/src/Packet/SubscribeRequestPacket.php
vendored
Executable file
101
vendor/binsoul/net-mqtt/src/Packet/SubscribeRequestPacket.php
vendored
Executable file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the SUBSCRIBE packet.
|
||||
*/
|
||||
class SubscribeRequestPacket extends BasePacket
|
||||
{
|
||||
use IdentifiablePacket;
|
||||
|
||||
/** @var string */
|
||||
private $topic;
|
||||
/** @var int */
|
||||
private $qosLevel;
|
||||
|
||||
protected static $packetType = Packet::TYPE_SUBSCRIBE;
|
||||
protected $packetFlags = 2;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
$this->assertPacketFlags(2);
|
||||
$this->assertRemainingPacketLength();
|
||||
|
||||
$this->identifier = $stream->readWord();
|
||||
$this->topic = $stream->readString();
|
||||
$this->qosLevel = $stream->readByte();
|
||||
|
||||
$this->assertValidQosLevel($this->qosLevel);
|
||||
$this->assertValidString($this->topic);
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
$data = new PacketStream();
|
||||
|
||||
$data->writeWord($this->generateIdentifier());
|
||||
$data->writeString($this->topic);
|
||||
$data->writeByte($this->qosLevel);
|
||||
|
||||
$this->remainingPacketLength = $data->length();
|
||||
|
||||
parent::write($stream);
|
||||
$stream->write($data->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the topic.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTopic()
|
||||
{
|
||||
return $this->topic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the topic.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setTopic($value)
|
||||
{
|
||||
$this->assertValidString($value, false);
|
||||
if ($value === '') {
|
||||
throw new \InvalidArgumentException('The topic must not be empty.');
|
||||
}
|
||||
|
||||
$this->topic = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quality of service level.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getQosLevel()
|
||||
{
|
||||
return $this->qosLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quality of service level.
|
||||
*
|
||||
* @param int $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setQosLevel($value)
|
||||
{
|
||||
$this->assertValidQosLevel($value, false);
|
||||
|
||||
$this->qosLevel = $value;
|
||||
}
|
||||
}
|
||||
132
vendor/binsoul/net-mqtt/src/Packet/SubscribeResponsePacket.php
vendored
Executable file
132
vendor/binsoul/net-mqtt/src/Packet/SubscribeResponsePacket.php
vendored
Executable file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the SUBACK packet.
|
||||
*/
|
||||
class SubscribeResponsePacket extends BasePacket
|
||||
{
|
||||
use IdentifiablePacket;
|
||||
|
||||
private static $qosLevels = [
|
||||
0 => ['Maximum QoS 0'],
|
||||
1 => ['Maximum QoS 1'],
|
||||
2 => ['Maximum QoS 2'],
|
||||
128 => ['Failure'],
|
||||
];
|
||||
|
||||
/** @var int[] */
|
||||
private $returnCodes;
|
||||
|
||||
protected static $packetType = Packet::TYPE_SUBACK;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
$this->assertPacketFlags(0);
|
||||
$this->assertRemainingPacketLength();
|
||||
|
||||
$this->identifier = $stream->readWord();
|
||||
|
||||
$returnCodeLength = $this->remainingPacketLength - 2;
|
||||
for ($n = 0; $n < $returnCodeLength; ++$n) {
|
||||
$returnCode = $stream->readByte();
|
||||
$this->assertValidReturnCode($returnCode);
|
||||
|
||||
$this->returnCodes[] = $returnCode;
|
||||
}
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
$data = new PacketStream();
|
||||
|
||||
$data->writeWord($this->generateIdentifier());
|
||||
foreach ($this->returnCodes as $returnCode) {
|
||||
$data->writeByte($returnCode);
|
||||
}
|
||||
|
||||
$this->remainingPacketLength = $data->length();
|
||||
|
||||
parent::write($stream);
|
||||
$stream->write($data->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the given return code is an error.
|
||||
*
|
||||
* @param int $returnCode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isError($returnCode)
|
||||
{
|
||||
return $returnCode === 128;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the given return code is an error.
|
||||
*
|
||||
* @param int $returnCode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getReturnCodeName($returnCode)
|
||||
{
|
||||
if (isset(self::$qosLevels[$returnCode])) {
|
||||
return self::$qosLevels[$returnCode][0];
|
||||
}
|
||||
|
||||
return 'Unknown '.$returnCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return codes.
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function getReturnCodes()
|
||||
{
|
||||
return $this->returnCodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the return codes.
|
||||
*
|
||||
* @param int[] $value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setReturnCodes(array $value)
|
||||
{
|
||||
foreach ($value as $returnCode) {
|
||||
$this->assertValidReturnCode($returnCode, false);
|
||||
}
|
||||
|
||||
$this->returnCodes = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a return code is valid.
|
||||
*
|
||||
* @param int $returnCode
|
||||
* @param bool $fromPacket
|
||||
*
|
||||
* @throws MalformedPacketException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function assertValidReturnCode($returnCode, $fromPacket = true)
|
||||
{
|
||||
if (!in_array($returnCode, [0, 1, 2, 128])) {
|
||||
$this->throwException(
|
||||
sprintf('Malformed return code %02x.', $returnCode),
|
||||
$fromPacket
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
vendor/binsoul/net-mqtt/src/Packet/UnsubscribeRequestPacket.php
vendored
Executable file
68
vendor/binsoul/net-mqtt/src/Packet/UnsubscribeRequestPacket.php
vendored
Executable file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\PacketStream;
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the UNSUBSCRIBE packet.
|
||||
*/
|
||||
class UnsubscribeRequestPacket extends BasePacket
|
||||
{
|
||||
use IdentifiablePacket;
|
||||
|
||||
/** @var string */
|
||||
private $topic;
|
||||
|
||||
protected static $packetType = Packet::TYPE_UNSUBSCRIBE;
|
||||
protected $packetFlags = 2;
|
||||
|
||||
public function read(PacketStream $stream)
|
||||
{
|
||||
parent::read($stream);
|
||||
|
||||
$this->assertPacketFlags(2);
|
||||
$this->assertRemainingPacketLength();
|
||||
|
||||
$originalPosition = $stream->getPosition();
|
||||
|
||||
do {
|
||||
$this->identifier = $stream->readWord();
|
||||
$this->topic = $stream->readString();
|
||||
} while (($stream->getPosition() - $originalPosition) <= $this->remainingPacketLength);
|
||||
}
|
||||
|
||||
public function write(PacketStream $stream)
|
||||
{
|
||||
$data = new PacketStream();
|
||||
|
||||
$data->writeWord($this->generateIdentifier());
|
||||
$data->writeString($this->topic);
|
||||
|
||||
$this->remainingPacketLength = $data->length();
|
||||
|
||||
parent::write($stream);
|
||||
$stream->write($data->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the topic.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTopic()
|
||||
{
|
||||
return $this->topic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the topic.
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function setTopic($value)
|
||||
{
|
||||
$this->topic = $value;
|
||||
}
|
||||
}
|
||||
13
vendor/binsoul/net-mqtt/src/Packet/UnsubscribeResponsePacket.php
vendored
Executable file
13
vendor/binsoul/net-mqtt/src/Packet/UnsubscribeResponsePacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
use BinSoul\Net\Mqtt\Packet;
|
||||
|
||||
/**
|
||||
* Represents the UNSUBACK packet.
|
||||
*/
|
||||
class UnsubscribeResponsePacket extends IdentifierOnlyPacket
|
||||
{
|
||||
protected static $packetType = Packet::TYPE_UNSUBACK;
|
||||
}
|
||||
67
vendor/binsoul/net-mqtt/src/PacketFactory.php
vendored
Executable file
67
vendor/binsoul/net-mqtt/src/PacketFactory.php
vendored
Executable file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
use BinSoul\Net\Mqtt\Exception\UnknownPacketTypeException;
|
||||
use BinSoul\Net\Mqtt\Packet\ConnectRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\ConnectResponsePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\DisconnectRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PingRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PingResponsePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishAckPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishCompletePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishReceivedPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\PublishReleasePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\SubscribeRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\SubscribeResponsePacket;
|
||||
use BinSoul\Net\Mqtt\Packet\UnsubscribeRequestPacket;
|
||||
use BinSoul\Net\Mqtt\Packet\UnsubscribeResponsePacket;
|
||||
|
||||
/**
|
||||
* Builds instances of the {@see Packet} interface.
|
||||
*/
|
||||
class PacketFactory
|
||||
{
|
||||
/**
|
||||
* Map of packet types to packet classes.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private static $mapping = [
|
||||
Packet::TYPE_CONNECT => ConnectRequestPacket::class,
|
||||
Packet::TYPE_CONNACK => ConnectResponsePacket::class,
|
||||
Packet::TYPE_PUBLISH => PublishRequestPacket::class,
|
||||
Packet::TYPE_PUBACK => PublishAckPacket::class,
|
||||
Packet::TYPE_PUBREC => PublishReceivedPacket::class,
|
||||
Packet::TYPE_PUBREL => PublishReleasePacket::class,
|
||||
Packet::TYPE_PUBCOMP => PublishCompletePacket::class,
|
||||
Packet::TYPE_SUBSCRIBE => SubscribeRequestPacket::class,
|
||||
Packet::TYPE_SUBACK => SubscribeResponsePacket::class,
|
||||
Packet::TYPE_UNSUBSCRIBE => UnsubscribeRequestPacket::class,
|
||||
Packet::TYPE_UNSUBACK => UnsubscribeResponsePacket::class,
|
||||
Packet::TYPE_PINGREQ => PingRequestPacket::class,
|
||||
Packet::TYPE_PINGRESP => PingResponsePacket::class,
|
||||
Packet::TYPE_DISCONNECT => DisconnectRequestPacket::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Builds a packet object for the given type.
|
||||
*
|
||||
* @param int $type
|
||||
*
|
||||
* @throws UnknownPacketTypeException
|
||||
*
|
||||
* @return Packet
|
||||
*/
|
||||
public function build($type)
|
||||
{
|
||||
if (!isset(self::$mapping[$type])) {
|
||||
throw new UnknownPacketTypeException(sprintf('Unknown packet type %d.', $type));
|
||||
}
|
||||
|
||||
$class = self::$mapping[$type];
|
||||
|
||||
return new $class();
|
||||
}
|
||||
}
|
||||
216
vendor/binsoul/net-mqtt/src/PacketStream.php
vendored
Executable file
216
vendor/binsoul/net-mqtt/src/PacketStream.php
vendored
Executable file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
use BinSoul\Net\Mqtt\Exception\EndOfStreamException;
|
||||
|
||||
/**
|
||||
* Provides methods to operate on a stream of bytes.
|
||||
*/
|
||||
class PacketStream
|
||||
{
|
||||
/** @var string */
|
||||
private $data;
|
||||
/** @var int */
|
||||
private $position;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param string $data initial data of the stream
|
||||
*/
|
||||
public function __construct($data = '')
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the desired number of bytes.
|
||||
*
|
||||
* @param int $count
|
||||
*
|
||||
* @throws EndOfStreamException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function read($count)
|
||||
{
|
||||
$contentLength = strlen($this->data);
|
||||
if ($this->position > $contentLength || $count > $contentLength - $this->position) {
|
||||
throw new EndOfStreamException(
|
||||
sprintf(
|
||||
'End of stream reached when trying to read %d bytes. content length=%d, position=%d',
|
||||
$count,
|
||||
$contentLength,
|
||||
$this->position
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$chunk = substr($this->data, $this->position, $count);
|
||||
if ($chunk === false) {
|
||||
$chunk = '';
|
||||
}
|
||||
|
||||
$readBytes = strlen($chunk);
|
||||
$this->position += $readBytes;
|
||||
|
||||
return $chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single byte.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function readByte()
|
||||
{
|
||||
return ord($this->read(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single word.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function readWord()
|
||||
{
|
||||
return ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a length prefixed string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function readString()
|
||||
{
|
||||
$length = $this->readWord();
|
||||
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given value.
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function write($value)
|
||||
{
|
||||
$this->data .= $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a single byte.
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function writeByte($value)
|
||||
{
|
||||
$this->write(chr($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a single word.
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function writeWord($value)
|
||||
{
|
||||
$this->write(chr(($value & 0xFFFF) >> 8));
|
||||
$this->write(chr($value & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a length prefixed string.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function writeString($string)
|
||||
{
|
||||
$this->writeWord(strlen($string));
|
||||
$this->write($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the stream.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function length()
|
||||
{
|
||||
return strlen($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes until the end of the stream.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRemainingBytes()
|
||||
{
|
||||
return $this->length() - $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the whole content of the stream.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the internal position of the stream relative to the current position.
|
||||
*
|
||||
* @param int $offset
|
||||
*/
|
||||
public function seek($offset)
|
||||
{
|
||||
$this->position += $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internal position of the stream.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPosition()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal position of the stream.
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function setPosition($value)
|
||||
{
|
||||
$this->position = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all bytes from the beginning to the current position.
|
||||
*/
|
||||
public function cut()
|
||||
{
|
||||
$this->data = substr($this->data, $this->position);
|
||||
if ($this->data === false) {
|
||||
$this->data = '';
|
||||
}
|
||||
|
||||
$this->position = 0;
|
||||
}
|
||||
}
|
||||
90
vendor/binsoul/net-mqtt/src/StreamParser.php
vendored
Executable file
90
vendor/binsoul/net-mqtt/src/StreamParser.php
vendored
Executable file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
use BinSoul\Net\Mqtt\Exception\EndOfStreamException;
|
||||
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||
use BinSoul\Net\Mqtt\Exception\UnknownPacketTypeException;
|
||||
|
||||
/**
|
||||
* Provides methods to parse a stream of bytes into packets.
|
||||
*/
|
||||
class StreamParser
|
||||
{
|
||||
/** @var PacketStream */
|
||||
private $buffer;
|
||||
/** @var PacketFactory */
|
||||
private $factory;
|
||||
/** @var callable */
|
||||
private $errorCallback;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->buffer = new PacketStream();
|
||||
$this->factory = new PacketFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an error callback.
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function onError($callback)
|
||||
{
|
||||
$this->errorCallback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given data to the internal buffer and parses it.
|
||||
*
|
||||
* @param string $data
|
||||
*
|
||||
* @return Packet[]
|
||||
*/
|
||||
public function push($data)
|
||||
{
|
||||
$this->buffer->write($data);
|
||||
|
||||
$result = [];
|
||||
while ($this->buffer->getRemainingBytes() > 0) {
|
||||
$type = $this->buffer->readByte() >> 4;
|
||||
try {
|
||||
$packet = $this->factory->build($type);
|
||||
} catch (UnknownPacketTypeException $e) {
|
||||
$this->handleError($e);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->buffer->seek(-1);
|
||||
$position = $this->buffer->getPosition();
|
||||
try {
|
||||
$packet->read($this->buffer);
|
||||
$result[] = $packet;
|
||||
$this->buffer->cut();
|
||||
} catch (EndOfStreamException $e) {
|
||||
$this->buffer->setPosition($position);
|
||||
break;
|
||||
} catch (MalformedPacketException $e) {
|
||||
$this->handleError($e);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the registered error callback.
|
||||
*
|
||||
* @param \Throwable $exception
|
||||
*/
|
||||
private function handleError($exception)
|
||||
{
|
||||
if ($this->errorCallback !== null) {
|
||||
$callback = $this->errorCallback;
|
||||
$callback($exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
vendor/binsoul/net-mqtt/src/Subscription.php
vendored
Executable file
41
vendor/binsoul/net-mqtt/src/Subscription.php
vendored
Executable file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Represents a subscription.
|
||||
*/
|
||||
interface Subscription
|
||||
{
|
||||
/**
|
||||
* Returns the topic filter.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFilter();
|
||||
|
||||
/**
|
||||
* Returns the quality of service level.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getQosLevel();
|
||||
|
||||
/**
|
||||
* Returns a new subscription with the given topic filter.
|
||||
*
|
||||
* @param string $filter
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withFilter($filter);
|
||||
|
||||
/**
|
||||
* Returns a new subscription with the given quality of service level.
|
||||
*
|
||||
* @param int $level
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function withQosLevel($level);
|
||||
}
|
||||
53
vendor/binsoul/net-mqtt/src/TopicMatcher.php
vendored
Executable file
53
vendor/binsoul/net-mqtt/src/TopicMatcher.php
vendored
Executable file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace BinSoul\Net\Mqtt;
|
||||
|
||||
/**
|
||||
* Matches a topic filter with an actual topic.
|
||||
*
|
||||
* @author Alin Eugen Deac <ade@vestergaardcompany.com>
|
||||
*/
|
||||
class TopicMatcher
|
||||
{
|
||||
/**
|
||||
* Check if the given topic matches the filter.
|
||||
*
|
||||
* @param string $filter e.g. A/B/+, A/B/#
|
||||
* @param string $topic e.g. A/B/C, A/B/foo/bar/baz
|
||||
*
|
||||
* @return bool true if topic matches the pattern
|
||||
*/
|
||||
public function matches($filter, $topic)
|
||||
{
|
||||
// Created by Steffen (https://github.com/kernelguy)
|
||||
$tokens = explode('/', $filter);
|
||||
$parts = [];
|
||||
for ($i = 0, $count = count($tokens); $i < $count; ++$i) {
|
||||
$token = $tokens[$i];
|
||||
switch ($token) {
|
||||
case '+':
|
||||
$parts[] = '[^/#\+]*';
|
||||
|
||||
break;
|
||||
case '#':
|
||||
if ($i === 0) {
|
||||
$parts[] = '[^\+\$]*';
|
||||
} else {
|
||||
$parts[] = '[^\+]*';
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
$parts[] = str_replace('+', '\+', $token);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$regex = implode('/', $parts);
|
||||
$regex = str_replace('$', '\$', $regex);
|
||||
$regex = ';^'.$regex.'$;';
|
||||
|
||||
return preg_match($regex, $topic) === 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user