set up tests
This commit is contained in:
parent
64b0fa8382
commit
51f84e3c40
|
|
@ -43,8 +43,11 @@ jobs:
|
||||||
composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
|
composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
|
||||||
|
|
||||||
- name: Execute tests
|
- name: Execute tests
|
||||||
run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml
|
run: |
|
||||||
|
REPLICATION_DRIVER=local phpunit --coverage-text --coverage-clover=coverage_local.xml
|
||||||
|
REPLICATION_DRIVER=redis phpunit --coverage-text --coverage-clover=coverage_redis.xml
|
||||||
|
|
||||||
- uses: codecov/codecov-action@v1
|
- uses: codecov/codecov-action@v1
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: false
|
fail_ci_if_error: false
|
||||||
|
file: '*.xml'
|
||||||
|
|
|
||||||
|
|
@ -143,23 +143,21 @@ return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Broadcasting Replication
|
| Broadcasting Replication PubSub
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| You can enable replication to publish and subscribe to
|
| You can enable replication to publish and subscribe to
|
||||||
| messages across the driver.
|
| messages across the driver.
|
||||||
|
|
|
||||||
| By default, it is disabled, but you can configure it to use drivers
|
| By default, it is set to 'local', but you can configure it to use drivers
|
||||||
| like Redis to ensure connection between multiple instances of
|
| like Redis to ensure connection between multiple instances of
|
||||||
| WebSocket servers.
|
| WebSocket servers. Just set the driver to 'redis' to enable the PubSub using Redis.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'replication' => [
|
'replication' => [
|
||||||
|
|
||||||
'enabled' => false,
|
'driver' => 'local',
|
||||||
|
|
||||||
'driver' => 'redis',
|
|
||||||
|
|
||||||
'redis' => [
|
'redis' => [
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,9 @@ class StartWebSocketServer extends Command
|
||||||
|
|
||||||
protected function configurePubSubReplication()
|
protected function configurePubSubReplication()
|
||||||
{
|
{
|
||||||
$this->laravel->get(ReplicationInterface::class)->boot($this->loop);
|
$this->laravel
|
||||||
|
->get(ReplicationInterface::class)
|
||||||
|
->boot($this->loop);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
class FetchChannelsController extends Controller
|
class FetchChannelsController extends Controller
|
||||||
{
|
{
|
||||||
/** @var ReplicationInterface */
|
/** @var ReplicationInterface */
|
||||||
protected $replication;
|
protected $pubsub;
|
||||||
|
|
||||||
public function __construct(ChannelManager $channelManager, ReplicationInterface $replication)
|
public function __construct(ChannelManager $channelManager, ReplicationInterface $pubsub)
|
||||||
{
|
{
|
||||||
parent::__construct($channelManager);
|
parent::__construct($channelManager);
|
||||||
|
|
||||||
$this->replication = $replication;
|
$this->pubsub = $pubsub;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(Request $request)
|
public function __invoke(Request $request)
|
||||||
|
|
@ -51,7 +51,7 @@ class FetchChannelsController extends Controller
|
||||||
|
|
||||||
// We ask the replication backend to get us the member count per channel.
|
// We ask the replication backend to get us the member count per channel.
|
||||||
// We get $counts back as a key-value array of channel names and their member count.
|
// We get $counts back as a key-value array of channel names and their member count.
|
||||||
return $this->replication
|
return $this->pubsub
|
||||||
->channelMemberCounts($request->appId, $channelNames)
|
->channelMemberCounts($request->appId, $channelNames)
|
||||||
->then(function (array $counts) use ($channels, $attributes) {
|
->then(function (array $counts) use ($channels, $attributes) {
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ class LocalClient implements ReplicationInterface
|
||||||
*/
|
*/
|
||||||
public function publish(string $appId, string $channel, stdClass $payload): bool
|
public function publish(string $appId, string $channel, stdClass $payload): bool
|
||||||
{
|
{
|
||||||
// Nothing to do, nobody to publish to
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,20 +257,24 @@ class RedisClient implements ReplicationInterface
|
||||||
*/
|
*/
|
||||||
protected function getConnectionUri()
|
protected function getConnectionUri()
|
||||||
{
|
{
|
||||||
$name = config('websockets.replication.connection') ?? 'default';
|
$name = config('websockets.replication.redis.connection') ?? 'default';
|
||||||
$config = config("database.redis.$name");
|
$config = config('database.redis')[$name];
|
||||||
|
|
||||||
$host = $config['host'];
|
$host = $config['host'];
|
||||||
$port = $config['port'] ? (':'.$config['port']) : ':6379';
|
$port = $config['port'] ?: 6379;
|
||||||
|
|
||||||
$query = [];
|
$query = [];
|
||||||
|
|
||||||
if ($config['password']) {
|
if ($config['password']) {
|
||||||
$query['password'] = $config['password'];
|
$query['password'] = $config['password'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['database']) {
|
if ($config['database']) {
|
||||||
$query['database'] = $config['database'];
|
$query['database'] = $config['database'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = http_build_query($query);
|
$query = http_build_query($query);
|
||||||
|
|
||||||
return "redis://$host$port".($query ? '?'.$query : '');
|
return "redis://{$host}:{$port}".($query ? "?{$query}" : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class Channel
|
||||||
protected $channelName;
|
protected $channelName;
|
||||||
|
|
||||||
/** @var ReplicationInterface */
|
/** @var ReplicationInterface */
|
||||||
protected $replication;
|
protected $pubsub;
|
||||||
|
|
||||||
/** @var \Ratchet\ConnectionInterface[] */
|
/** @var \Ratchet\ConnectionInterface[] */
|
||||||
protected $subscribedConnections = [];
|
protected $subscribedConnections = [];
|
||||||
|
|
@ -23,7 +23,7 @@ class Channel
|
||||||
public function __construct(string $channelName)
|
public function __construct(string $channelName)
|
||||||
{
|
{
|
||||||
$this->channelName = $channelName;
|
$this->channelName = $channelName;
|
||||||
$this->replication = app(ReplicationInterface::class);
|
$this->pubsub = app(ReplicationInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getChannelName(): string
|
public function getChannelName(): string
|
||||||
|
|
@ -68,7 +68,7 @@ class Channel
|
||||||
$this->saveConnection($connection);
|
$this->saveConnection($connection);
|
||||||
|
|
||||||
// Subscribe to broadcasted messages from the pub/sub backend
|
// Subscribe to broadcasted messages from the pub/sub backend
|
||||||
$this->replication->subscribe($connection->app->id, $this->channelName);
|
$this->pubsub->subscribe($connection->app->id, $this->channelName);
|
||||||
|
|
||||||
$connection->send(json_encode([
|
$connection->send(json_encode([
|
||||||
'event' => 'pusher_internal:subscription_succeeded',
|
'event' => 'pusher_internal:subscription_succeeded',
|
||||||
|
|
@ -81,7 +81,7 @@ class Channel
|
||||||
unset($this->subscribedConnections[$connection->socketId]);
|
unset($this->subscribedConnections[$connection->socketId]);
|
||||||
|
|
||||||
// Unsubscribe from the pub/sub backend
|
// Unsubscribe from the pub/sub backend
|
||||||
$this->replication->unsubscribe($connection->app->id, $this->channelName);
|
$this->pubsub->unsubscribe($connection->app->id, $this->channelName);
|
||||||
|
|
||||||
if (! $this->hasConnections()) {
|
if (! $this->hasConnections()) {
|
||||||
DashboardLogger::vacated($connection, $this->channelName);
|
DashboardLogger::vacated($connection, $this->channelName);
|
||||||
|
|
@ -120,7 +120,7 @@ class Channel
|
||||||
// in this case. If this came from TriggerEventController, then we still want
|
// in this case. If this came from TriggerEventController, then we still want
|
||||||
// to publish to get the message out to other server instances.
|
// to publish to get the message out to other server instances.
|
||||||
if ($publish) {
|
if ($publish) {
|
||||||
$this->replication->publish($appId, $this->channelName, $payload);
|
$this->pubsub->publish($appId, $this->channelName, $payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performance optimization, if we don't have a socket ID,
|
// Performance optimization, if we don't have a socket ID,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class PresenceChannel extends Channel
|
||||||
public function getUsers(string $appId)
|
public function getUsers(string $appId)
|
||||||
{
|
{
|
||||||
// Get the members list from the replication backend
|
// Get the members list from the replication backend
|
||||||
return $this->replication
|
return $this->pubsub
|
||||||
->channelMembers($appId, $this->channelName);
|
->channelMembers($appId, $this->channelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ class PresenceChannel extends Channel
|
||||||
$this->users[$connection->socketId] = $channelData;
|
$this->users[$connection->socketId] = $channelData;
|
||||||
|
|
||||||
// Add the connection as a member of the channel
|
// Add the connection as a member of the channel
|
||||||
$this->replication
|
$this->pubsub
|
||||||
->joinChannel(
|
->joinChannel(
|
||||||
$connection->app->id,
|
$connection->app->id,
|
||||||
$this->channelName,
|
$this->channelName,
|
||||||
|
|
@ -59,7 +59,7 @@ class PresenceChannel extends Channel
|
||||||
|
|
||||||
// We need to pull the channel data from the replication backend,
|
// We need to pull the channel data from the replication backend,
|
||||||
// otherwise we won't be sending the full details of the channel
|
// otherwise we won't be sending the full details of the channel
|
||||||
$this->replication
|
$this->pubsub
|
||||||
->channelMembers($connection->app->id, $this->channelName)
|
->channelMembers($connection->app->id, $this->channelName)
|
||||||
->then(function ($users) use ($connection) {
|
->then(function ($users) use ($connection) {
|
||||||
// Send the success event
|
// Send the success event
|
||||||
|
|
@ -86,7 +86,7 @@ class PresenceChannel extends Channel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the connection as a member of the channel
|
// Remove the connection as a member of the channel
|
||||||
$this->replication
|
$this->pubsub
|
||||||
->leaveChannel(
|
->leaveChannel(
|
||||||
$connection->app->id,
|
$connection->app->id,
|
||||||
$this->channelName,
|
$this->channelName,
|
||||||
|
|
@ -110,7 +110,7 @@ class PresenceChannel extends Channel
|
||||||
*/
|
*/
|
||||||
public function toArray(string $appId = null)
|
public function toArray(string $appId = null)
|
||||||
{
|
{
|
||||||
return $this->replication
|
return $this->pubsub
|
||||||
->channelMembers($appId, $this->channelName)
|
->channelMembers($appId, $this->channelName)
|
||||||
->then(function ($users) {
|
->then(function ($users) {
|
||||||
return array_merge(parent::toArray(), [
|
return array_merge(parent::toArray(), [
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Pusher\Pusher;
|
use Pusher\Pusher;
|
||||||
|
use React\EventLoop\Factory as LoopFactory;
|
||||||
|
|
||||||
class WebSocketsServiceProvider extends ServiceProvider
|
class WebSocketsServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
|
|
@ -56,19 +57,19 @@ class WebSocketsServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
protected function configurePubSub()
|
protected function configurePubSub()
|
||||||
{
|
{
|
||||||
if (config('websockets.replication.enabled') !== true || config('websockets.replication.driver') !== 'redis') {
|
if (config('websockets.replication.driver') === 'local') {
|
||||||
$this->app->singleton(ReplicationInterface::class, function () {
|
$this->app->singleton(ReplicationInterface::class, function () {
|
||||||
return new LocalClient();
|
return new LocalClient;
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->app->singleton(ReplicationInterface::class, function () {
|
if (config('websockets.replication.driver') === 'redis') {
|
||||||
return (new RedisClient())->boot($this->loop);
|
$this->app->singleton(ReplicationInterface::class, function () {
|
||||||
});
|
return (new RedisClient)->boot($this->loop ?? LoopFactory::create());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$this->app->get(BroadcastManager::class)->extend('redis-pusher', function ($app, array $config) {
|
$this->app->get(BroadcastManager::class)->extend('websockets', function ($app, array $config) {
|
||||||
$pusher = new Pusher(
|
$pusher = new Pusher(
|
||||||
$config['key'], $config['secret'],
|
$config['key'], $config['secret'],
|
||||||
$config['app_id'], $config['options'] ?? []
|
$config['app_id'], $config['options'] ?? []
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,18 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$app['config']->set('database.redis.default', [
|
||||||
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
|
'password' => env('REDIS_PASSWORD', null),
|
||||||
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
|
'database' => env('REDIS_DB', '0'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$app['config']->set(
|
||||||
|
'websockets.replication.driver',
|
||||||
|
getenv('REPLICATION_DRIVER') ?: 'local'
|
||||||
|
);
|
||||||
|
|
||||||
include_once __DIR__.'/../database/migrations/create_websockets_statistics_entries_table.php.stub';
|
include_once __DIR__.'/../database/migrations/create_websockets_statistics_entries_table.php.stub';
|
||||||
|
|
||||||
(new \CreateWebSocketsStatisticsEntriesTable())->up();
|
(new \CreateWebSocketsStatisticsEntriesTable())->up();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue