Add the ability to limit the maximum concurrent connections per appli… (#143)
* Add the ability to limit the maximum concurrent connections per application Co-Authored-By: AlShahawi <alshahawi@outlook.com>
This commit is contained in:
parent
556f4338e8
commit
aecbfeebe7
|
|
@ -8,6 +8,9 @@ return [
|
|||
* This package comes with multi tenancy out of the box. Here you can
|
||||
* configure the different apps that can use the webSockets server.
|
||||
*
|
||||
* Optionally you specify capacity so you can limit the maximum
|
||||
* concurrent connections for a specific app.
|
||||
*
|
||||
* Optionally you can disable client events so clients cannot send
|
||||
* messages to each other via the webSockets.
|
||||
*/
|
||||
|
|
@ -17,6 +20,7 @@ return [
|
|||
'name' => env('APP_NAME'),
|
||||
'key' => env('PUSHER_APP_KEY'),
|
||||
'secret' => env('PUSHER_APP_SECRET'),
|
||||
'capacity' => null,
|
||||
'enable_client_messages' => false,
|
||||
'enable_statistics' => true,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ class App
|
|||
/** @var string|null */
|
||||
public $host;
|
||||
|
||||
/** @var int|null */
|
||||
public $capacity = null;
|
||||
|
||||
/** @var bool */
|
||||
public $clientMessagesEnabled = false;
|
||||
|
||||
|
|
@ -80,6 +83,13 @@ class App
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setCapacity(?int $capacity)
|
||||
{
|
||||
$this->capacity = $capacity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function enableStatistics(bool $enabled = true)
|
||||
{
|
||||
$this->statisticsEnabled = $enabled;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ class ConfigAppProvider implements AppProvider
|
|||
|
||||
$app
|
||||
->enableClientMessages($appAttributes['enable_client_messages'])
|
||||
->enableStatistics($appAttributes['enable_statistics']);
|
||||
->enableStatistics($appAttributes['enable_statistics'])
|
||||
->setCapacity($appAttributes['capacity'] ?? null);
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace BeyondCode\LaravelWebSockets\WebSockets\Exceptions;
|
||||
|
||||
class ConnectionsOverCapacity extends WebSocketException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'Over capacity';
|
||||
|
||||
// @See https://pusher.com/docs/pusher_protocol#error-codes
|
||||
// Indicates an error resulting in the connection
|
||||
// being closed by Pusher, and that the client may reconnect after 1s or more.
|
||||
$this->code = 4100;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
|
|||
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\UnknownAppKey;
|
||||
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\WebSocketException;
|
||||
use BeyondCode\LaravelWebSockets\WebSockets\Messages\PusherMessageFactory;
|
||||
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\ConnectionsOverCapacity;
|
||||
|
||||
class WebSocketHandler implements MessageComponentInterface
|
||||
{
|
||||
|
|
@ -29,6 +30,7 @@ class WebSocketHandler implements MessageComponentInterface
|
|||
{
|
||||
$this
|
||||
->verifyAppKey($connection)
|
||||
->limitConcurrentConnections($connection)
|
||||
->generateSocketId($connection)
|
||||
->establishConnection($connection);
|
||||
}
|
||||
|
|
@ -73,6 +75,18 @@ class WebSocketHandler implements MessageComponentInterface
|
|||
return $this;
|
||||
}
|
||||
|
||||
protected function limitConcurrentConnections(ConnectionInterface $connection)
|
||||
{
|
||||
if (! is_null($capacity = $connection->app->capacity)) {
|
||||
$connectionsCount = $this->channelManager->getConnectionCount($connection->app->id);
|
||||
if ($connectionsCount >= $capacity) {
|
||||
throw new ConnectionsOverCapacity();
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function generateSocketId(ConnectionInterface $connection)
|
||||
{
|
||||
$socketId = sprintf('%d.%d', random_int(1, 1000000000), random_int(1, 1000000000));
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace BeyondCode\LaravelWebSockets\Tests;
|
|||
use BeyondCode\LaravelWebSockets\Apps\App;
|
||||
use BeyondCode\LaravelWebSockets\Tests\Mocks\Message;
|
||||
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\UnknownAppKey;
|
||||
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\ConnectionsOverCapacity;
|
||||
|
||||
class ConnectionTest extends TestCase
|
||||
{
|
||||
|
|
@ -26,6 +27,17 @@ class ConnectionTest extends TestCase
|
|||
$connection->assertSentEvent('pusher:connection_established');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function app_can_not_exceed_maximum_capacity()
|
||||
{
|
||||
$this->app['config']->set('websockets.apps.0.capacity', 2);
|
||||
|
||||
$this->getConnectedWebSocketConnection(['test-channel']);
|
||||
$this->getConnectedWebSocketConnection(['test-channel']);
|
||||
$this->expectException(ConnectionsOverCapacity::class);
|
||||
$this->getConnectedWebSocketConnection(['test-channel']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function successful_connections_have_the_app_attached()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
|||
'id' => 1234,
|
||||
'key' => 'TestKey',
|
||||
'secret' => 'TestSecret',
|
||||
'capacity' => null,
|
||||
'enable_client_messages' => false,
|
||||
'enable_statistics' => true,
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue