This commit is contained in:
2022-10-23 01:39:27 +02:00
parent 8c17aab483
commit 1929b84685
4130 changed files with 479334 additions and 0 deletions

View 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
View 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

View 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"
}
}
}

View 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;
}
}

View 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 = [];
}
}