diff --git a/.codecov.yml b/.codecov.yml
new file mode 100644
index 0000000000..33dbc6bf33
--- /dev/null
+++ b/.codecov.yml
@@ -0,0 +1,18 @@
+codecov:
+ notify:
+ require_ci_to_pass: yes
+
+coverage:
+ precision: 2
+ round: down
+ range: "70...100"
+
+status:
+ project: yes
+ patch: yes
+ changes: no
+
+comment:
+ layout: "reach, diff, flags, files, footer"
+ behavior: default
+ require_changes: no
diff --git a/.editorconfig b/.editorconfig
index cd8eb86efa..9718070fd3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,5 +11,8 @@ end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
+[*.{blade.php,yml,yaml}]
+indent_size = 2
+
[*.md]
trim_trailing_whitespace = false
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..9a6dfff364
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,79 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - '*'
+ tags:
+ - '*'
+ pull_request:
+ branches:
+ - '*'
+
+jobs:
+ build:
+ if: "!contains(github.event.head_commit.message, 'skip ci')"
+
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ php:
+ - '7.3'
+ - '7.4'
+ laravel:
+ - 6.*
+ - 7.*
+ - 8.*
+ prefer:
+ - 'prefer-lowest'
+ - 'prefer-stable'
+ include:
+ - laravel: '6.*'
+ testbench: '4.*'
+ - laravel: '7.*'
+ testbench: '5.*'
+ - laravel: '8.*'
+ testbench: '6.*'
+
+ name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} --${{ matrix.prefer }}
+
+ steps:
+ - uses: actions/checkout@v1
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
+ coverage: pcov
+
+ - name: Setup Redis
+ uses: supercharge/redis-github-action@1.1.0
+ with:
+ redis-version: 6
+
+ - uses: actions/cache@v1
+ name: Cache dependencies
+ with:
+ path: ~/.composer/cache/files
+ key: composer-php-${{ matrix.php }}-${{ matrix.laravel }}-${{ matrix.prefer }}-${{ hashFiles('composer.json') }}
+
+ - name: Install dependencies
+ run: |
+ composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench-browser-kit:${{ matrix.testbench }}" "orchestra/database:${{ matrix.testbench }}" --no-interaction --no-update
+ composer update --${{ matrix.prefer }} --prefer-dist --no-interaction --no-suggest
+
+ - name: Run tests for Local
+ run: |
+ REPLICATION_MODE=local vendor/bin/phpunit --coverage-text --coverage-clover=coverage_local.xml
+
+ - name: Run tests for Redis
+ run: |
+ REPLICATION_MODE=redis vendor/bin/phpunit --coverage-text --coverage-clover=coverage_redis.xml
+
+ - uses: codecov/codecov-action@v1
+ with:
+ fail_ci_if_error: false
+ file: '*.xml'
+ token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
deleted file mode 100644
index dce4f69827..0000000000
--- a/.github/workflows/run-tests.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-name: run-tests
-
-on: [push, pull_request]
-
-jobs:
- test:
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [ubuntu-latest, windows-latest]
- php: [7.4, 7.3, 7.2]
- laravel: [6.*, 7.*, 8.*]
- dependency-version: [prefer-lowest, prefer-stable]
- include:
- - laravel: 8.*
- testbench: 6.*
- - laravel: 7.*
- testbench: 5.*
- - laravel: 6.*
- testbench: 4.*
- exclude:
- - php: 7.2
- laravel: 8.*
-
- name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }}
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v1
-
- - name: Cache dependencies
- uses: actions/cache@v1
- with:
- path: ~/.composer/cache/files
- key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php }}
- extensions: curl, dom, libxml, mbstring, pdo, sqlite, pdo_sqlite, zip
- coverage: pcov
-
- - name: Install dependencies
- run: |
- composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
- composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
-
- - name: Execute tests
- run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml
-
- - uses: codecov/codecov-action@v1
- with:
- fail_ci_if_error: false
diff --git a/.gitignore b/.gitignore
index 461ba139fd..65e1146246 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,9 @@
+/vendor
+/.idea
build
-composer.lock
-vendor
+.phpunit.result.cache
coverage
-.phpunit.result.cache
\ No newline at end of file
+composer.phar
+composer.lock
+.DS_Store
+database.sqlite
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
index df16b68b52..76733d0c94 100644
--- a/.scrutinizer.yml
+++ b/.scrutinizer.yml
@@ -1,19 +1,19 @@
filter:
- excluded_paths: [tests/*]
+ excluded_paths: [tests/*]
checks:
- php:
- remove_extra_empty_lines: true
- remove_php_closing_tag: true
- remove_trailing_whitespace: true
- fix_use_statements:
- remove_unused: true
- preserve_multiple: false
- preserve_blanklines: true
- order_alphabetically: true
- fix_php_opening_tag: true
- fix_linefeed: true
- fix_line_ending: true
- fix_identation_4spaces: true
- fix_doc_comments: true
+ php:
+ remove_extra_empty_lines: true
+ remove_php_closing_tag: true
+ remove_trailing_whitespace: true
+ fix_use_statements:
+ remove_unused: true
+ preserve_multiple: false
+ preserve_blanklines: true
+ order_alphabetically: true
+ fix_php_opening_tag: true
+ fix_linefeed: true
+ fix_line_ending: true
+ fix_identation_4spaces: true
+ fix_doc_comments: true
diff --git a/.styleci.yml b/.styleci.yml
index f4d3cbc61b..c3bb259c55 100644
--- a/.styleci.yml
+++ b/.styleci.yml
@@ -1,4 +1 @@
-preset: laravel
-
-disabled:
- - single_class_element_per_statement
+preset: laravel
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index a3341a87c7..0000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Changelog
-
-All notable changes to `laravel-websockets` will be documented in this file
-
-## 1.4.0 - 2020-03-03
-
-- add support for Laravel 7
-
-## 1.0.2 - 2018-12-06
-
-- Fix issue with wrong namespaces
-
-## 1.0.1 - 2018-12-04
-
-- Remove VueJS debug mode on dashboard
-- Allow setting app hosts to use when connecting via the dashboard
-- Added debug mode when starting the WebSocket server
-
-## 1.0.0 - 2018-12-04
-
-- initial release
diff --git a/LICENSE.md b/LICENSE
similarity index 100%
rename from LICENSE.md
rename to LICENSE
diff --git a/composer.json b/composer.json
index 578e96447d..0038b4c338 100644
--- a/composer.json
+++ b/composer.json
@@ -1,12 +1,14 @@
{
"name": "beyondcode/laravel-websockets",
- "description": "An easy to use WebSocket server",
+ "description": "An easy to launch a Pusher-compatible WebSockets server for Laravel.",
"keywords": [
"beyondcode",
- "laravel-websockets"
+ "laravel-websockets",
+ "laravel",
+ "php"
],
- "homepage": "https://github.com/beyondcode/laravel-websockets",
"license": "MIT",
+ "homepage": "https://github.com/beyondcode/laravel-websockets",
"authors": [
{
"name": "Marcel Pociot",
@@ -19,48 +21,58 @@
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
+ },
+ {
+ "name": "Alex Renoki",
+ "homepage": "https://github.com/rennokki",
+ "role": "Developer"
}
],
"require": {
- "php": "^7.2",
- "ext-json": "*",
"cboden/ratchet": "^0.4.1",
+ "clue/redis-react": "^2.3",
+ "doctrine/dbal": "^2.9",
+ "evenement/evenement": "^2.0|^3.0",
"facade/ignition-contracts": "^1.0",
"guzzlehttp/psr7": "^1.5",
- "illuminate/broadcasting": "^6.0|^7.0|^8.0",
- "illuminate/console": "^6.0|^7.0|^8.0",
- "illuminate/http": "^6.0|^7.0|^8.0",
- "illuminate/routing": "^6.0|^7.0|^8.0",
- "illuminate/support": "^6.0|^7.0|^8.0",
- "pusher/pusher-php-server": "^3.0|^4.0",
- "react/dns": "^1.1",
- "react/http": "^1.1",
+ "illuminate/broadcasting": "^6.3|^7.0|^8.0",
+ "illuminate/console": "^6.3|7.0|^8.0",
+ "illuminate/http": "^6.3|^7.0|^8.0",
+ "illuminate/queue": "^6.3|^7.0|^8.0",
+ "illuminate/routing": "^6.3|^7.0|^8.0",
+ "illuminate/support": "^6.3|^7.0|^8.0",
+ "pusher/pusher-php-server": "^4.0",
+ "react/promise": "^2.0",
"symfony/http-kernel": "^4.0|^5.0",
"symfony/psr-http-message-bridge": "^1.1|^2.0"
},
"require-dev": {
- "mockery/mockery": "^1.3",
- "orchestra/testbench": "^4.0|^5.0|^6.0",
+ "clue/block-react": "^1.4",
+ "laravel/legacy-factories": "^1.1",
+ "orchestra/testbench-browser-kit": "^4.0|^5.0|^6.0",
+ "orchestra/database": "^4.0|^5.0|^6.0",
"phpunit/phpunit": "^8.0|^9.0"
},
+ "suggest": {
+ "ext-pcntl": "Running the server needs pcntl to listen to command signals and soft-shutdown."
+ },
"autoload": {
"psr-4": {
- "BeyondCode\\LaravelWebSockets\\": "src"
+ "BeyondCode\\LaravelWebSockets\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
- "BeyondCode\\LaravelWebSockets\\Tests\\": "tests"
+ "BeyondCode\\LaravelWebSockets\\Test\\": "tests"
}
},
"scripts": {
- "test": "vendor/bin/phpunit",
- "test-coverage": "vendor/bin/phpunit --coverage-html coverage"
-
+ "test": "vendor/bin/phpunit"
},
"config": {
"sort-packages": true
},
+ "minimum-stability": "dev",
"extra": {
"laravel": {
"providers": [
diff --git a/config/websockets.php b/config/websockets.php
index 45415d76c5..681bb6bdc1 100644
--- a/config/websockets.php
+++ b/config/websockets.php
@@ -1,141 +1,299 @@
[
+
'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
+
+ 'domain' => env('LARAVEL_WEBSOCKETS_DOMAIN'),
+
+ 'path' => env('LARAVEL_WEBSOCKETS_PATH', 'laravel-websockets'),
+
+ 'middleware' => [
+ 'web',
+ \BeyondCode\LaravelWebSockets\Dashboard\Http\Middleware\Authorize::class,
+ ],
+
+ ],
+
+ 'managers' => [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Manager
+ |--------------------------------------------------------------------------
+ |
+ | An Application manager determines how your websocket server allows
+ | the use of the TCP protocol based on, for example, a list of allowed
+ | applications.
+ | By default, it uses the defined array in the config file, but you can
+ | anytime implement the same interface as the class and add your own
+ | custom method to retrieve the apps.
+ |
+ */
+
+ 'app' => \BeyondCode\LaravelWebSockets\Apps\ConfigAppManager::class,
+
],
/*
- * 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.
- */
+ |--------------------------------------------------------------------------
+ | Applications Repository
+ |--------------------------------------------------------------------------
+ |
+ | By default, the only allowed app is the one you define with
+ | your PUSHER_* variables from .env.
+ | You can configure to use multiple apps if you need to, or use
+ | a custom App Manager that will handle the apps from a database, per se.
+ |
+ | You can apply multiple settings, like the maximum capacity, enable
+ | client-to-client messages or statistics.
+ |
+ */
+
'apps' => [
[
'id' => env('PUSHER_APP_ID'),
'name' => env('APP_NAME'),
+ 'host' => env('PUSHER_APP_HOST'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'path' => env('PUSHER_APP_PATH'),
'capacity' => null,
'enable_client_messages' => false,
'enable_statistics' => true,
+ 'allowed_origins' => [
+ // env('LARAVEL_WEBSOCKETS_DOMAIN'),
+ ],
],
],
/*
- * This class is responsible for finding the apps. The default provider
- * will use the apps defined in this config file.
- *
- * You can create a custom provider by implementing the
- * `AppProvider` interface.
- */
- 'app_provider' => BeyondCode\LaravelWebSockets\Apps\ConfigAppProvider::class,
+ |--------------------------------------------------------------------------
+ | Broadcasting Replication PubSub
+ |--------------------------------------------------------------------------
+ |
+ | You can enable replication to publish and subscribe to
+ | messages across the driver.
+ |
+ | By default, it is set to 'local', but you can configure it to use drivers
+ | like Redis to ensure connection between multiple instances of
+ | WebSocket servers. Just set the driver to 'redis' to enable the PubSub using Redis.
+ |
+ */
- /*
- * This array contains the hosts of which you want to allow incoming requests.
- * Leave this empty if you want to accept requests from all hosts.
- */
- 'allowed_origins' => [
- //
- ],
+ 'replication' => [
- /*
- * The maximum request size in kilobytes that is allowed for an incoming WebSocket request.
- */
- 'max_request_size_in_kb' => 250,
+ 'mode' => env('WEBSOCKETS_REPLICATION_MODE', 'local'),
- /*
- * This path will be used to register the necessary routes for the package.
- */
- 'path' => 'laravel-websockets',
+ 'modes' => [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Local Replication
+ |--------------------------------------------------------------------------
+ |
+ | Local replication is actually a null replicator, meaning that it
+ | is the default behaviour of storing the connections into an array.
+ |
+ */
+
+ 'local' => [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Channel Manager
+ |--------------------------------------------------------------------------
+ |
+ | The channel manager is responsible for storing, tracking and retrieving
+ | the channels as long as their members and connections.
+ |
+ */
+
+ 'channel_manager' => \BeyondCode\LaravelWebSockets\ChannelManagers\LocalChannelManager::class,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Statistics Collector
+ |--------------------------------------------------------------------------
+ |
+ | The Statistics Collector will, by default, handle the incoming statistics,
+ | storing them until they will become dumped into another database, usually
+ | a MySQL database or a time-series database.
+ |
+ */
+
+ 'collector' => \BeyondCode\LaravelWebSockets\Statistics\Collectors\MemoryCollector::class,
+
+ ],
+
+ 'redis' => [
+
+ 'connection' => env('WEBSOCKETS_REDIS_REPLICATION_CONNECTION', 'default'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Channel Manager
+ |--------------------------------------------------------------------------
+ |
+ | The channel manager is responsible for storing, tracking and retrieving
+ | the channels as long as their members and connections.
+ |
+ */
+
+ 'channel_manager' => \BeyondCode\LaravelWebSockets\ChannelManagers\RedisChannelManager::class,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Statistics Collector
+ |--------------------------------------------------------------------------
+ |
+ | The Statistics Collector will, by default, handle the incoming statistics,
+ | storing them until they will become dumped into another database, usually
+ | a MySQL database or a time-series database.
+ |
+ */
+
+ 'collector' => \BeyondCode\LaravelWebSockets\Statistics\Collectors\RedisCollector::class,
+
+ ],
+
+ ],
- /*
- * Dashboard Routes Middleware
- *
- * These middleware will be assigned to every dashboard route, giving you
- * the chance to add your own middleware to this list or change any of
- * the existing middleware. Or, you can simply stick with this list.
- */
- 'middleware' => [
- 'web',
- Authorize::class,
],
'statistics' => [
+
/*
- * This model will be used to store the statistics of the WebSocketsServer.
- * The only requirement is that the model should extend
- * `WebSocketsStatisticsEntry` provided by this package.
- */
- 'model' => \BeyondCode\LaravelWebSockets\Statistics\Models\WebSocketsStatisticsEntry::class,
-
- /**
- * The Statistics Logger will, by default, handle the incoming statistics, store them
- * and then release them into the database on each interval defined below.
- */
- 'logger' => BeyondCode\LaravelWebSockets\Statistics\Logger\HttpStatisticsLogger::class,
+ |--------------------------------------------------------------------------
+ | Statistics Store
+ |--------------------------------------------------------------------------
+ |
+ | The Statistics Store is the place where all the temporary stats will
+ | be dumped. This is a much reliable store and will be used to display
+ | graphs or handle it later on your app.
+ |
+ */
+
+ 'store' => \BeyondCode\LaravelWebSockets\Statistics\Stores\DatabaseStore::class,
/*
- * Here you can specify the interval in seconds at which statistics should be logged.
- */
+ |--------------------------------------------------------------------------
+ | Statistics Interval Period
+ |--------------------------------------------------------------------------
+ |
+ | Here you can specify the interval in seconds at which
+ | statistics should be logged.
+ |
+ */
+
'interval_in_seconds' => 60,
/*
- * When the clean-command is executed, all recorded statistics older than
- * the number of days specified here will be deleted.
- */
+ |--------------------------------------------------------------------------
+ | Statistics Deletion Period
+ |--------------------------------------------------------------------------
+ |
+ | When the clean-command is executed, all recorded statistics older than
+ | the number of days specified here will be deleted.
+ |
+ */
+
'delete_statistics_older_than_days' => 60,
- /*
- * Use an DNS resolver to make the requests to the statistics logger
- * default is to resolve everything to 127.0.0.1.
- */
- 'perform_dns_lookup' => false,
],
/*
- * Define the optional SSL context for your WebSocket connections.
- * You can see all available options at: http://php.net/manual/en/context.ssl.php
- */
+ |--------------------------------------------------------------------------
+ | Maximum Request Size
+ |--------------------------------------------------------------------------
+ |
+ | The maximum request size in kilobytes that is allowed for
+ | an incoming WebSocket request.
+ |
+ */
+
+ 'max_request_size_in_kb' => 250,
+
+ /*
+ |--------------------------------------------------------------------------
+ | SSL Configuration
+ |--------------------------------------------------------------------------
+ |
+ | By default, the configuration allows only on HTTP. For SSL, you need
+ | to set up the the certificate, the key, and optionally, the passphrase
+ | for the private key.
+ | You will need to restart the server for the settings to take place.
+ |
+ */
+
'ssl' => [
- /*
- * Path to local certificate file on filesystem. It must be a PEM encoded file which
- * contains your certificate and private key. It can optionally contain the
- * certificate chain of issuers. The private key also may be contained
- * in a separate file specified by local_pk.
- */
+
'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),
- /*
- * Path to local private key file on filesystem in case of separate files for
- * certificate (local_cert) and private key.
- */
+ 'capath' => env('LARAVEL_WEBSOCKETS_SSL_CA', null),
+
'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),
- /*
- * Passphrase for your local_cert file.
- */
'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
+
+ 'verify_peer' => env('APP_ENV') === 'production',
+
+ 'allow_self_signed' => env('APP_ENV') !== 'production',
+
],
/*
- * Channel Manager
- * This class handles how channel persistence is handled.
- * By default, persistence is stored in an array by the running webserver.
- * The only requirement is that the class should implement
- * `ChannelManager` interface provided by this package.
- */
- 'channel_manager' => \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManagers\ArrayChannelManager::class,
+ |--------------------------------------------------------------------------
+ | Route Handlers
+ |--------------------------------------------------------------------------
+ |
+ | Here you can specify the route handlers that will take over
+ | the incoming/outgoing websocket connections. You can extend the
+ | original class and implement your own logic, alongside
+ | with the existing logic.
+ |
+ */
+
+ 'handlers' => [
+
+ 'websocket' => \BeyondCode\LaravelWebSockets\Server\WebSocketHandler::class,
+
+ 'health' => \BeyondCode\LaravelWebSockets\Server\HealthHandler::class,
+
+ 'trigger_event' => \BeyondCode\LaravelWebSockets\API\TriggerEvent::class,
+
+ 'fetch_channels' => \BeyondCode\LaravelWebSockets\API\FetchChannels::class,
+
+ 'fetch_channel' => \BeyondCode\LaravelWebSockets\API\FetchChannel::class,
+
+ 'fetch_users' => \BeyondCode\LaravelWebSockets\API\FetchUsers::class,
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Promise Resolver
+ |--------------------------------------------------------------------------
+ |
+ | The promise resolver is a class that takes a input value and is
+ | able to make sure the PHP code runs async by using ->then(). You can
+ | use your own Promise Resolver. This is usually changed when you want to
+ | intercept values by the promises throughout the app, like in testing
+ | to switch from async to sync.
+ |
+ */
+
+ 'promise_resolver' => \React\Promise\FulfilledPromise::class,
+
];
diff --git a/database/migrations/0000_00_00_000000_rename_statistics_counters.php b/database/migrations/0000_00_00_000000_rename_statistics_counters.php
new file mode 100644
index 0000000000..70dbf79acd
--- /dev/null
+++ b/database/migrations/0000_00_00_000000_rename_statistics_counters.php
@@ -0,0 +1,36 @@
+renameColumn('peak_connection_count', 'peak_connections_count');
+ $table->renameColumn('websocket_message_count', 'websocket_messages_count');
+ $table->renameColumn('api_message_count', 'api_messages_count');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('websockets_statistics_entries', function (Blueprint $table) {
+ $table->renameColumn('peak_connections_count', 'peak_connection_count');
+ $table->renameColumn('websocket_messages_count', 'websocket_message_count');
+ $table->renameColumn('api_messages_count', 'api_message_count');
+ });
+ }
+}
diff --git a/docs/_index.md b/docs/_index.md
index 183f7e60d0..7c504e5514 100644
--- a/docs/_index.md
+++ b/docs/_index.md
@@ -1,4 +1,4 @@
---
packageName: Laravel Websockets
githubUrl: https://github.com/beyondcode/laravel-websockets
----
\ No newline at end of file
+---
diff --git a/docs/advanced-usage/app-providers.md b/docs/advanced-usage/app-providers.md
index c0c92ecaf7..77f4502144 100644
--- a/docs/advanced-usage/app-providers.md
+++ b/docs/advanced-usage/app-providers.md
@@ -1,69 +1,74 @@
-# Custom App Providers
+---
+title: Custom App Managers
+order: 1
+---
+
+# Custom App Managers
With the multi-tenancy support of Laravel WebSockets, the default way of storing and retrieving the apps is by using the `websockets.php` config file.
-Depending on your setup, you might have your app configuration stored elsewhere and having to keep the configuration in sync with your app storage can be tedious. To simplify this, you can create your own `AppProvider` class that will take care of retrieving the WebSocket credentials for a specific WebSocket application.
+Depending on your setup, you might have your app configuration stored elsewhere and having to keep the configuration in sync with your app storage can be tedious. To simplify this, you can create your own `AppManager` class that will take care of retrieving the WebSocket credentials for a specific WebSocket application.
-> Make sure that you do **not** perform any IO blocking tasks in your `AppProvider`, as they will interfere with the asynchronous WebSocket execution.
+> Make sure that you do **not** perform any IO blocking tasks in your `AppManager`, as they will interfere with the asynchronous WebSocket execution.
-In order to create your custom `AppProvider`, create a class that implements the `BeyondCode\LaravelWebSockets\AppProviders\AppProvider` interface.
+In order to create your custom `AppManager`, create a class that implements the `BeyondCode\LaravelWebSockets\Contracts\AppManager` interface.
This is what it looks like:
```php
-interface AppProvider
+interface AppManager
{
- /** @return array[BeyondCode\LaravelWebSockets\AppProviders\App] */
+ /** @return array[BeyondCode\LaravelWebSockets\Apps\App] */
public function all(): array;
- /** @return BeyondCode\LaravelWebSockets\AppProviders\App */
+ /** @return BeyondCode\LaravelWebSockets\Apps\App */
public function findById($appId): ?App;
- /** @return BeyondCode\LaravelWebSockets\AppProviders\App */
- public function findByKey(string $appKey): ?App;
+ /** @return BeyondCode\LaravelWebSockets\Apps\App */
+ public function findByKey($appKey): ?App;
- /** @return BeyondCode\LaravelWebSockets\AppProviders\App */
- public function findBySecret(string $appSecret): ?App;
+ /** @return BeyondCode\LaravelWebSockets\Apps\App */
+ public function findBySecret($appSecret): ?App;
}
```
-The following is an example AppProvider that utilizes an Eloquent model:
+The following is an example AppManager that utilizes an Eloquent model:
```php
-namespace App\Providers;
+namespace App\Managers;
use App\Application;
use BeyondCode\LaravelWebSockets\Apps\App;
-use BeyondCode\LaravelWebSockets\Apps\AppProvider;
+use BeyondCode\LaravelWebSockets\Contracts\AppManager;
-class MyCustomAppProvider implements AppProvider
+class MyCustomAppManager implements AppManager
{
public function all() : array
{
return Application::all()
->map(function($app) {
- return $this->instanciate($app->toArray());
+ return $this->normalize($app->toArray());
})
->toArray();
}
- public function findById($appId) : ? App
+ public function findById($appId) : ?App
{
- return $this->instanciate(Application::findById($appId)->toArray());
+ return $this->normalize(Application::findById($appId)->toArray());
}
- public function findByKey(string $appKey) : ? App
+ public function findByKey($appKey) : ?App
{
- return $this->instanciate(Application::findByKey($appKey)->toArray());
+ return $this->normalize(Application::findByKey($appKey)->toArray());
}
- public function findBySecret(string $appSecret) : ? App
+ public function findBySecret($appSecret) : ?App
{
- return $this->instanciate(Application::findBySecret($appSecret)->toArray());
+ return $this->normalize(Application::findBySecret($appSecret)->toArray());
}
- protected function instanciate(?array $appAttributes) : ? App
+ protected function normalize(?array $appAttributes) : ?App
{
- if (!$appAttributes) {
+ if (! $appAttributes) {
return null;
}
@@ -90,15 +95,26 @@ class MyCustomAppProvider implements AppProvider
}
```
-Once you have implemented your own AppProvider, you need to set it in the `websockets.php` configuration file:
-
-```php
-/**
- * This class is responsible for finding the apps. The default provider
- * will use the apps defined in this config file.
- *
- * You can create a custom provider by implementing the
- * `AppProvider` interface.
- */
-'app_provider' => MyCustomAppProvider::class,
+Once you have implemented your own AppManager, you need to set it in the `websockets.php` configuration file:
+
+```php
+'managers' => [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Manager
+ |--------------------------------------------------------------------------
+ |
+ | An Application manager determines how your websocket server allows
+ | the use of the TCP protocol based on, for example, a list of allowed
+ | applications.
+ | By default, it uses the defined array in the config file, but you can
+ | anytime implement the same interface as the class and add your own
+ | custom method to retrieve the apps.
+ |
+ */
+
+ 'app' => \App\Managers\MyCustomAppManager::class,
+
+],
```
diff --git a/docs/advanced-usage/custom-websocket-handlers.md b/docs/advanced-usage/custom-websocket-handlers.md
index 77d4eb9394..71ebe60c81 100644
--- a/docs/advanced-usage/custom-websocket-handlers.md
+++ b/docs/advanced-usage/custom-websocket-handlers.md
@@ -1,6 +1,11 @@
+---
+title: Custom WebSocket Handlers
+order: 2
+---
+
# Custom WebSocket Handlers
-While this package's main purpose is to make the usage of either the Pusher JavaScript client or Laravel Echo as easy as possible, you are not limited to the Pusher protocol at all.
+While this package's main purpose is to make the usage of either the Pusher JavaScript client or Laravel Echo as easy as possible, you are not limited to the Pusher protocol at all.
There might be situations where all you need is a simple, bare-bone, WebSocket server where you want to have full control over the incoming payload and what you want to do with it - without having "channels" in the way.
You can easily create your own custom WebSocketHandler class. All you need to do is implement Ratchets `Ratchet\WebSocket\MessageComponentInterface`.
@@ -10,24 +15,24 @@ Once implemented, you will have a class that looks something like this:
```php
namespace App;
+use Exception;
use Ratchet\ConnectionInterface;
use Ratchet\RFC6455\Messaging\MessageInterface;
use Ratchet\WebSocket\MessageComponentInterface;
class MyCustomWebSocketHandler implements MessageComponentInterface
{
-
public function onOpen(ConnectionInterface $connection)
{
// TODO: Implement onOpen() method.
}
-
+
public function onClose(ConnectionInterface $connection)
{
// TODO: Implement onClose() method.
}
- public function onError(ConnectionInterface $connection, \Exception $e)
+ public function onError(ConnectionInterface $connection, Exception $e)
{
// TODO: Implement onError() method.
}
@@ -43,12 +48,12 @@ In the class itself you have full control over all the lifecycle events of your
The only part missing is, that you will need to tell our WebSocket server to load this handler at a specific route endpoint. This can be achieved using the `WebSocketsRouter` facade.
-This class takes care of registering the routes with the actual webSocket server. You can use the `webSocket` method to define a custom WebSocket endpoint. The method needs two arguments: the path where the WebSocket handled should be available and the fully qualified classname of the WebSocket handler class.
+This class takes care of registering the routes with the actual webSocket server. You can use the `get` method to define a custom WebSocket endpoint. The method needs two arguments: the path where the WebSocket handled should be available and the fully qualified classname of the WebSocket handler class.
This could, for example, be done inside your `routes/web.php` file.
```php
-WebSocketsRouter::webSocket('/my-websocket', \App\MyCustomWebSocketHandler::class);
+WebSocketsRouter::get('/my-websocket', \App\MyCustomWebSocketHandler::class);
```
-Once you've added the custom WebSocket route, be sure to restart our WebSocket server for the changes to take place.
\ No newline at end of file
+Once you've added the custom WebSocket route, be sure to restart our WebSocket server for the changes to take place.
diff --git a/docs/advanced-usage/dispatched-events.md b/docs/advanced-usage/dispatched-events.md
new file mode 100644
index 0000000000..be5e095b24
--- /dev/null
+++ b/docs/advanced-usage/dispatched-events.md
@@ -0,0 +1,82 @@
+---
+title: Dispatched Events
+order: 5
+---
+
+# Dispatched Events
+
+Laravel WebSockets takes advantage of Laravel's Event dispatching observer, in a way that you can handle in-server events outside of it.
+
+For example, you can listen for events like when a new connection establishes or when an user joins a presence channel.
+
+## Events
+
+Below you will find a list of dispatched events:
+
+- `BeyondCode\LaravelWebSockets\Events\NewConnection` - when a connection successfully establishes on the server
+- `BeyondCode\LaravelWebSockets\Events\ConnectionClosed` - when a connection leaves the server
+- `BeyondCode\LaravelWebSockets\Events\SubscribedToChannel` - when a connection subscribes to a specific channel
+- `BeyondCode\LaravelWebSockets\Events\UnsubscribedFromChannel` - when a connection unsubscribes from a specific channel
+- `BeyondCode\LaravelWebSockets\Events\WebSocketMessageReceived` - when the server receives a message
+- `BeyondCode\LaravelWebSockets\EventsConnectionPonged` - when a connection pings to the server that it is still alive
+
+## Queued Listeners
+
+Because the default Redis connection (either PhpRedis or Predis) is a blocking I/O method and can cause problems with the server speed and availability, you might want to check the [Non-Blocking Queue Driver](non-blocking-queue-driver.md) documentation that helps you create the Async Redis queue driver that is going to fix the Blocking I/O issue.
+
+If set up, you can use the `async-redis` queue driver in your listeners:
+
+```php
+ [
+ App\Listeners\HandleNewConnections::class,
+ ],
+];
+```
diff --git a/docs/advanced-usage/non-blocking-queue-driver.md b/docs/advanced-usage/non-blocking-queue-driver.md
new file mode 100644
index 0000000000..98ed10d1a8
--- /dev/null
+++ b/docs/advanced-usage/non-blocking-queue-driver.md
@@ -0,0 +1,30 @@
+---
+title: Non-Blocking Queue Driver
+order: 4
+---
+
+# Non-Blocking Queue Driver
+
+In Laravel, he default Redis connection also interacts with the queues. Since you might want to dispatch jobs on Redis from the server, you can encounter an anti-pattern of using a blocking I/O connection (like PhpRedis or PRedis) within the WebSockets server.
+
+To solve this issue, you can configure the built-in queue driver that uses the Async Redis connection when it's possible, like within the WebSockets server. It's highly recommended to switch your queue to it if you are going to use the queues within the server controllers, for example.
+
+Add the `async-redis` queue driver to your list of connections. The configuration parameters are compatible with the default `redis` driver:
+
+```php
+'connections' => [
+ 'async-redis' => [
+ 'driver' => 'async-redis',
+ 'connection' => env('WEBSOCKETS_REDIS_REPLICATION_CONNECTION', 'default'),
+ 'queue' => env('REDIS_QUEUE', 'default'),
+ 'retry_after' => 90,
+ 'block_for' => null,
+ ],
+]
+```
+
+Also, make sure that the default queue driver is set to `async-redis`:
+
+```
+QUEUE_CONNECTION=async-redis
+```
diff --git a/docs/advanced-usage/webhooks.md b/docs/advanced-usage/webhooks.md
new file mode 100644
index 0000000000..2df8e928ec
--- /dev/null
+++ b/docs/advanced-usage/webhooks.md
@@ -0,0 +1,53 @@
+---
+title: Webhooks
+order: 3
+---
+
+# Webhooks
+
+While you can create any custom websocket handlers, you might still want to intercept and run your own custom business logic on each websocket connection.
+
+In Pusher, there are [Pusher Webhooks](https://pusher.com/docs/channels/server_api/webhooks) that do this job. However, since the implementation is a pure controller,
+you might want to extend it and update the config file to reflect the changes:
+
+For example, running your own business logic on connection open and close:
+
+```php
+namespace App\Controllers\WebSockets;
+
+use BeyondCode\LaravelWebSockets\WebSockets\WebSocketHandler as BaseWebSocketHandler;
+use Ratchet\ConnectionInterface;
+
+class WebSocketHandler extends BaseWebSocketHandler
+{
+ public function onOpen(ConnectionInterface $connection)
+ {
+ parent::onOpen($connection);
+
+ // Run code on open
+ // $connection->app contains the app details
+ // $this->channelManager is accessible
+ }
+
+ public function onClose(ConnectionInterface $connection)
+ {
+ parent::onClose($connection);
+
+ // Run code on close.
+ // $connection->app contains the app details
+ // $this->channelManager is accessible
+ }
+}
+```
+
+Once you implemented it, replace the `handlers.websocket` class name in config:
+
+```php
+'handlers' => [
+
+ 'websocket' => App\Controllers\WebSockets\WebSocketHandler::class,
+
+],
+```
+
+A server restart is required afterwards.
diff --git a/docs/basic-usage/pusher.md b/docs/basic-usage/pusher.md
index 7c07e034e2..6d72a2d549 100644
--- a/docs/basic-usage/pusher.md
+++ b/docs/basic-usage/pusher.md
@@ -7,14 +7,16 @@ order: 1
The easiest way to get started with Laravel WebSockets is by using it as a [Pusher](https://pusher.com) replacement. The integrated WebSocket and HTTP Server has complete feature parity with the Pusher WebSocket and HTTP API. In addition to that, this package also ships with an easy to use debugging dashboard to see all incoming and outgoing WebSocket requests.
+To make it clear, the package does not restrict connections numbers or depend on the Pusher's service. It does comply with the Pusher protocol to make it easy to use the Pusher SDK with it.
+
## Requirements
-To make use of the Laravel WebSockets package in combination with Pusher, you first need to install the official Pusher PHP SDK.
+To make use of the Laravel WebSockets package in combination with Pusher, you first need to install the official Pusher PHP SDK.
-If you are not yet familiar with the concept of Broadcasting in Laravel, please take a look at the [Laravel documentation](https://laravel.com/docs/6.0/broadcasting).
+If you are not yet familiar with the concept of Broadcasting in Laravel, please take a look at the [Laravel documentation](https://laravel.com/docs/8.0/broadcasting).
```bash
-composer require pusher/pusher-php-server "~3.0"
+composer require pusher/pusher-php-server "~4.0"
```
Next, you should make sure to use Pusher as your broadcasting driver. This can be achieved by setting the `BROADCAST_DRIVER` environment variable in your `.env` file:
@@ -38,9 +40,13 @@ To do this, you should add the `host` and `port` configuration key to your `conf
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
- 'host' => '127.0.0.1',
- 'port' => 6001,
- 'scheme' => 'http'
+ 'host' => env('PUSHER_APP_HOST', '127.0.0.1'),
+ 'port' => env('PUSHER_APP_PORT', 6001),
+ 'scheme' => env('PUSHER_APP_SCHEME', 'http'),
+ 'curl_options' => [
+ CURLOPT_SSL_VERIFYHOST => 0,
+ CURLOPT_SSL_VERIFYPEER => 0,
+ ],
],
],
```
@@ -68,8 +74,11 @@ You may add additional apps in your `config/websockets.php` file.
'name' => env('APP_NAME'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
+ 'path' => env('PUSHER_APP_PATH'),
+ 'capacity' => null,
'enable_client_messages' => false,
'enable_statistics' => true,
+ 'allowed_origins' => [],
],
],
```
@@ -90,8 +99,8 @@ To enable or disable the statistics for one of your apps, you can modify the `en
## Usage with Laravel Echo
-The Laravel WebSockets package integrates nicely into [Laravel Echo](https://laravel.com/docs/6.0/broadcasting#receiving-broadcasts) to integrate into your frontend application and receive broadcasted events.
-If you are new to Laravel Echo, be sure to take a look at the [official documentation](https://laravel.com/docs/6.0/broadcasting#receiving-broadcasts).
+The Laravel WebSockets package integrates nicely into [Laravel Echo](https://laravel.com/docs/8.0/broadcasting#receiving-broadcasts) to integrate into your frontend application and receive broadcasted events.
+If you are new to Laravel Echo, be sure to take a look at the [official documentation](https://laravel.com/docs/8.0/broadcasting#receiving-broadcasts).
To make Laravel Echo work with Laravel WebSockets, you need to make some minor configuration changes when working with Laravel Echo. Add the `wsHost` and `wsPort` parameters and point them to your Laravel WebSocket server host and port.
@@ -102,7 +111,7 @@ When using Laravel WebSockets in combination with a custom SSL certificate, be s
:::
```js
-import Echo from "laravel-echo"
+import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
@@ -113,7 +122,8 @@ window.Echo = new Echo({
wsPort: 6001,
forceTLS: false,
disableStats: true,
+ enabledTransports: ['ws', 'wss'],
});
```
-Now you can use all Laravel Echo features in combination with Laravel WebSockets, such as [Presence Channels](https://laravel.com/docs/6.0/broadcasting#presence-channels), [Notifications](https://laravel.com/docs/6.0/broadcasting#notifications) and [Client Events](https://laravel.com/docs/6.0/broadcasting#client-events).
+Now you can use all Laravel Echo features in combination with Laravel WebSockets, such as [Presence Channels](https://laravel.com/docs/8.x/broadcasting#presence-channels), [Notifications](https://laravel.com/docs/8.x/broadcasting#notifications) and [Client Events](https://laravel.com/docs/8.x/broadcasting#client-events).
diff --git a/docs/basic-usage/restarting.md b/docs/basic-usage/restarting.md
new file mode 100644
index 0000000000..56c5539289
--- /dev/null
+++ b/docs/basic-usage/restarting.md
@@ -0,0 +1,14 @@
+---
+title: Restarting Server
+order: 4
+---
+
+# Restarting Server
+
+If you use Supervisor to keep your server alive, you might want to restart it just like `queue:restart` does.
+
+To do so, consider using the `websockets:restart`. In a maximum of 10 seconds since issuing the command, the server will be restarted.
+
+```bash
+php artisan websockets:restart
+```
diff --git a/docs/basic-usage/ssl.md b/docs/basic-usage/ssl.md
index 7e700d8459..33092435d5 100644
--- a/docs/basic-usage/ssl.md
+++ b/docs/basic-usage/ssl.md
@@ -10,32 +10,29 @@ Since most of the web's traffic is going through HTTPS, it's also crucial to sec
## Configuration
The SSL configuration takes place in your `config/websockets.php` file.
+
The default configuration has a SSL section that looks like this:
```php
'ssl' => [
- /*
- * Path to local certificate file on filesystem. It must be a PEM encoded file which
- * contains your certificate and private key. It can optionally contain the
- * certificate chain of issuers. The private key also may be contained
- * in a separate file specified by local_pk.
- */
- 'local_cert' => null,
-
- /*
- * Path to local private key file on filesystem in case of separate files for
- * certificate (local_cert) and private key.
- */
- 'local_pk' => null,
-
- /*
- * Passphrase with which your local_cert file was encoded.
- */
- 'passphrase' => null
+
+ 'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),
+
+ 'capath' => env('LARAVEL_WEBSOCKETS_SSL_CA', null),
+
+ 'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),
+
+ 'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
+
+ 'verify_peer' => env('APP_ENV') === 'production',
+
+ 'allow_self_signed' => env('APP_ENV') !== 'production',
+
],
```
But this is only a subset of all the available configuration options.
+
This packages makes use of the official PHP [SSL context options](http://php.net/manual/en/context.ssl.php).
So if you find yourself in the need of adding additional configuration settings, take a look at the PHP documentation and simply add the configuration parameters that you need.
@@ -62,13 +59,20 @@ window.Echo = new Echo({
wsHost: window.location.hostname,
wsPort: 6001,
disableStats: true,
- forceTLS: true
+ forceTLS: true,
+ enabledTransports: ['ws', 'wss'],
});
```
## Server configuration
-When broadcasting events from your Laravel application to the WebSocket server, you also need to tell Laravel to make use of HTTPS instead of HTTP. You can do this by setting the `scheme` option in your `config/broadcasting.php` file to `https`:
+When broadcasting events from your Laravel application to the WebSocket server, you also need to tell Laravel to make use of HTTPS instead of HTTP. You can do this by setting the `PUSHER_APP_SCHEME` variable to `https`
+
+```env
+PUSHER_APP_SCHEME=https
+```
+
+Your connection from `config/broadcasting.php` would look like this:
```php
'pusher' => [
@@ -78,9 +82,10 @@ When broadcasting events from your Laravel application to the WebSocket server,
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
- 'host' => '127.0.0.1',
- 'port' => 6001,
- 'scheme' => 'https'
+ 'encrypted' => true,
+ 'host' => env('PUSHER_APP_HOST', '127.0.0.1'),
+ 'port' => env('PUSHER_APP_PORT', 6001),
+ 'scheme' => env('PUSHER_APP_SCHEME', 'http'),
],
],
```
@@ -98,26 +103,19 @@ Make sure that you replace `YOUR-USERNAME` with your Mac username and `VALET-SIT
```php
'ssl' => [
- /*
- * Path to local certificate file on filesystem. It must be a PEM encoded file which
- * contains your certificate and private key. It can optionally contain the
- * certificate chain of issuers. The private key also may be contained
- * in a separate file specified by local_pk.
- */
+
'local_cert' => '/Users/YOUR-USERNAME/.config/valet/Certificates/VALET-SITE.TLD.crt',
- /*
- * Path to local private key file on filesystem in case of separate files for
- * certificate (local_cert) and private key.
- */
+ 'capath' => env('LARAVEL_WEBSOCKETS_SSL_CA', null),
+
'local_pk' => '/Users/YOUR-USERNAME/.config/valet/Certificates/VALET-SITE.TLD.key',
- /*
- * Passphrase with which your local_cert file was encoded.
- */
- 'passphrase' => null,
+ 'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
+
+ 'verify_peer' => env('APP_ENV') === 'production',
+
+ 'allow_self_signed' => env('APP_ENV') !== 'production',
- 'verify_peer' => false,
],
```
@@ -133,13 +131,14 @@ You also need to disable SSL verification.
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
- 'host' => '127.0.0.1',
- 'port' => 6001,
- 'scheme' => 'https',
+ 'encrypted' => true,
+ 'host' => env('PUSHER_APP_HOST', '127.0.0.1'),
+ 'port' => env('PUSHER_APP_PORT', 6001),
+ 'scheme' => env('PUSHER_APP_SCHEME', 'http'),
'curl_options' => [
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_SSL_VERIFYPEER => 0,
- ]
+ ],
],
],
```
@@ -208,7 +207,7 @@ server {
location / {
try_files /nonexistent @$type;
}
-
+
location @web {
try_files $uri $uri/ /index.php?$query_string;
}
@@ -273,28 +272,20 @@ You know you've reached this limit of your Nginx error logs contain similar mess
Remember to restart your Nginx after you've modified the `worker_connections`.
-### Example using Caddy
+### Example using Caddy v2
-[Caddy](https://caddyserver.com) can also be used to automatically obtain a TLS certificate from Let's Encrypt and terminate TLS before proxying to your echo server.
+[Caddy](https://caddyserver.com) can also be used to automatically obtain a TLS certificate from Let's Encrypt and terminate TLS before proxying to your websocket server.
An example configuration would look like this:
```
socket.yourapp.tld {
- rewrite / {
- if {>Connection} has Upgrade
- if {>Upgrade} is websocket
- to /websocket-proxy/{path}?{query}
- }
-
- proxy /websocket-proxy 127.0.0.1:6001 {
- without /special-websocket-url
- transparent
- websocket
+ @ws {
+ header Connection *Upgrade*
+ header Upgrade websocket
}
-
- tls youremail.com
+ reverse_proxy @ws 127.0.0.1:6001
}
```
-Note the `to /websocket-proxy`, this is a dummy path to allow the `proxy` directive to only proxy on websocket connections. This should be a path that will never be used by your application's routing. Also, note that you should change `127.0.0.1` to the hostname of your websocket server. For example, if you're running in a Docker environment, this might be the container name of your websocket server.
+Note that you should change `127.0.0.1` to the hostname of your websocket server. For example, if you're running in a Docker environment, this might be the container name of your websocket server.
diff --git a/docs/basic-usage/starting.md b/docs/basic-usage/starting.md
index 8892468f74..6b28439778 100644
--- a/docs/basic-usage/starting.md
+++ b/docs/basic-usage/starting.md
@@ -30,51 +30,3 @@ For example, by using `127.0.0.1`, you will only allow WebSocket connections fro
```bash
php artisan websockets:serve --host=127.0.0.1
```
-
-## Keeping the socket server running with supervisord
-
-The `websockets:serve` daemon needs to always be running in order to accept connections. This is a prime use case for `supervisor`, a task runner on Linux.
-
-First, make sure `supervisor` is installed.
-
-```bash
-# On Debian / Ubuntu
-apt install supervisor
-
-# On Red Hat / CentOS
-yum install supervisor
-systemctl enable supervisord
-```
-
-Once installed, add a new process that `supervisor` needs to keep running. You place your configurations in the `/etc/supervisor/conf.d` (Debian/Ubuntu) or `/etc/supervisord.d` (Red Hat/CentOS) directory.
-
-Within that directory, create a new file called `websockets.conf`.
-
-```bash
-[program:websockets]
-command=/usr/bin/php /home/laravel-echo/laravel-websockets/artisan websockets:serve
-numprocs=1
-autostart=true
-autorestart=true
-user=laravel-echo
-```
-
-Once created, instruct `supervisor` to reload its configuration files (without impacting the already running `supervisor` jobs).
-
-```bash
-supervisorctl update
-supervisorctl start websockets
-```
-
-Your echo server should now be running (you can verify this with `supervisorctl status`). If it were to crash, `supervisor` will automatically restart it.
-
-Please note that, by default, `supervisor` will force a maximum number of open files onto all the processes that it manages. This is configured by the `minfds` parameter in `supervisord.conf`.
-
-If you want to increase the maximum number of open files, you may do so in `/etc/supervisor/supervisord.conf` (Debian/Ubuntu) or `/etc/supervisord.conf` (Red Hat/CentOS):
-
-```
-[supervisord]
-minfds=10240; (min. avail startup file descriptors;default 1024)
-```
-
-After changing this setting, you'll need to restart the supervisor process (which in turn will restart all your processes that it manages).
diff --git a/docs/debugging/console.md b/docs/debugging/console.md
index 4ff9013ac8..cf0e97a652 100644
--- a/docs/debugging/console.md
+++ b/docs/debugging/console.md
@@ -7,4 +7,6 @@ order: 1
When you start the Laravel WebSocket server and your application is in debug mode, you will automatically see all incoming and outgoing WebSocket events in your terminal.
-
\ No newline at end of file
+On production environments, you shall use the `--debug` flag to display the events in the terminal.
+
+
diff --git a/docs/debugging/dashboard.md b/docs/debugging/dashboard.md
index af54bf9886..bba0551bf7 100644
--- a/docs/debugging/dashboard.md
+++ b/docs/debugging/dashboard.md
@@ -14,7 +14,7 @@ In addition to logging the events to the console, you can also use a real-time d
The default location of the WebSocket dashboard is at `/laravel-websockets`. The routes get automatically registered.
If you want to change the URL of the dashboard, you can configure it with the `path` setting in your `config/websockets.php` file.
-To access the debug dashboard, you can visit the dashboard URL of your Laravel project in the browser.
+To access the debug dashboard, you can visit the dashboard URL of your Laravel project in the browser
Since your WebSocket server has support for multiple apps, you can select which app you want to connect to and inspect.
By pressing the "Connect" button, you can establish the WebSocket connection and see all events taking place on your WebSocket server from there on in real-time.
@@ -67,6 +67,16 @@ protected function schedule(Schedule $schedule)
}
```
+## Disable Statistics
+
+Each app contains an `enable_statistics` that defines wether that app generates statistics or not. The statistics are being stored for the `interval_in_seconds` seconds and then they are inserted in the database.
+
+However, to disable it entirely and void any incoming statistic, you can call `--disable-statistics` when running the server command:
+
+```bash
+php artisan websockets:serve --disable-statistics
+```
+
## Event Creator
The dashboard also comes with an easy-to-use event creator, that lets you manually send events to your channels.
diff --git a/docs/faq/_index.md b/docs/faq/_index.md
index 688d140733..47b9d3aa0f 100644
--- a/docs/faq/_index.md
+++ b/docs/faq/_index.md
@@ -1,4 +1,4 @@
---
title: FAQ
-order: 5
+order: 6
---
diff --git a/docs/faq/cloudflare.md b/docs/faq/cloudflare.md
new file mode 100644
index 0000000000..d5a933a9ea
--- /dev/null
+++ b/docs/faq/cloudflare.md
@@ -0,0 +1,18 @@
+---
+title: Cloudflare
+order: 3
+---
+
+# Cloudflare
+
+In some cases, you might use Cloudflare and notice that your production server does not seem to respond to your `:6001` port.
+
+This is because Cloudflare does not seem to open ports, [excepting a few of them](https://blog.cloudflare.com/cloudflare-now-supporting-more-ports/).
+
+To mitigate this issue, for example, you can run your server on port `2096`:
+
+```bash
+php artisan websockets:serve --port=2096
+```
+
+You will notice that the new `:2096` websockets server will work properly.
diff --git a/docs/faq/deploying.md b/docs/faq/deploying.md
index 7ed276758d..8cca2dc58d 100644
--- a/docs/faq/deploying.md
+++ b/docs/faq/deploying.md
@@ -46,3 +46,61 @@ sudo pecl install event
#### Deploying on Laravel Forge
If your are using [Laravel Forge](https://forge.laravel.com/) for the deployment [this article by Alex Bouma](https://alex.bouma.dev/installing-laravel-websockets-on-forge) might help you out.
+
+#### Deploying on Laravel Vapor
+
+Since [Laravel Vapor](https://vapor.laravel.com) runs on a serverless architecture, you will need to spin up an actual EC2 Instance that runs in the same VPC as the Lambda function to be able to make use of the WebSocket connection.
+
+The Lambda function will make sure your HTTP request gets fulfilled, then the EC2 Instance will be continuously polled through the WebSocket protocol.
+
+## Keeping the socket server running with supervisord
+
+The `websockets:serve` daemon needs to always be running in order to accept connections. This is a prime use case for `supervisor`, a task runner on Linux.
+
+First, make sure `supervisor` is installed.
+
+```bash
+# On Debian / Ubuntu
+apt install supervisor
+
+# On Red Hat / CentOS
+yum install supervisor
+systemctl enable supervisord
+```
+
+Once installed, add a new process that `supervisor` needs to keep running. You place your configurations in the `/etc/supervisor/conf.d` (Debian/Ubuntu) or `/etc/supervisord.d` (Red Hat/CentOS) directory.
+
+Within that directory, create a new file called `websockets.conf`.
+
+```bash
+[program:websockets]
+command=/usr/bin/php /home/laravel-echo/laravel-websockets/artisan websockets:serve
+numprocs=1
+autostart=true
+autorestart=true
+user=laravel-echo
+```
+
+Once created, instruct `supervisor` to reload its configuration files (without impacting the already running `supervisor` jobs).
+
+```bash
+supervisorctl update
+supervisorctl start websockets
+```
+
+Your echo server should now be running (you can verify this with `supervisorctl status`). If it were to crash, `supervisor` will automatically restart it.
+
+Please note that, by default, just like file descriptiors, `supervisor` will force a maximum number of open files onto all the processes that it manages. This is configured by the `minfds` parameter in `supervisord.conf`.
+
+If you want to increase the maximum number of open files, you may do so in `/etc/supervisor/supervisord.conf` (Debian/Ubuntu) or `/etc/supervisord.conf` (Red Hat/CentOS):
+
+```
+[supervisord]
+minfds=10240; (min. avail startup file descriptors;default 1024)
+```
+
+After changing this setting, you'll need to restart the supervisor process (which in turn will restart all your processes that it manages).
+
+## Debugging supervisor
+
+If you run into issues with Supervisor, like not supporting a lot of connections, consider checking the [Ratched docs on deploying with Supervisor](http://socketo.me/docs/deploy#supervisor).
diff --git a/docs/faq/scaling.md b/docs/faq/scaling.md
index f3768d34db..b5033f0ec5 100644
--- a/docs/faq/scaling.md
+++ b/docs/faq/scaling.md
@@ -1,9 +1,9 @@
---
-title: ... but does it scale?
+title: Benchmarks
order: 2
---
-# ... but does it scale?
+# Benchmarks
Of course, this is not a question with an easy answer as your mileage may vary. But with the appropriate server-side configuration your WebSocket server can easily hold a **lot** of concurrent connections.
@@ -16,3 +16,7 @@ Here is another benchmark that was run on a 2GB Digital Ocean droplet with 2 CPU

Make sure to take a look at the [Deployment Tips](/docs/laravel-websockets/faq/deploying) to find out how to improve your specific setup.
+
+# Horizontal Scaling
+
+When deploying to multi-node environments, you will notice that the server won't behave correctly. Check [Horizontal Scaling](../horizontal-scaling/getting-started.md) section.
diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md
index 0eddbd0b68..5d24d7dd6a 100644
--- a/docs/getting-started/installation.md
+++ b/docs/getting-started/installation.md
@@ -13,162 +13,24 @@ composer require beyondcode/laravel-websockets
The package will automatically register a service provider.
-This package comes with a migration to store statistic information while running your WebSocket server. You can publish the migration file using:
+You need to publish the WebSocket configuration file:
```bash
-php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
+php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
```
-Run the migrations with:
+# Statistics
-```bash
-php artisan migrate
-```
+This package comes with migrations to store statistic information while running your WebSocket server. For more info, check the [Debug Dashboard](../debugging/dashboard.md) section.
-Next, you need to publish the WebSocket configuration file:
+You can publish the migration file using:
```bash
-php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
+php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
```
-This is the default content of the config file that will be published as `config/websockets.php`:
-
-```php
-return [
-
- /*
- * Set a custom dashboard configuration
- */
- 'dashboard' => [
- 'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
- ],
-
- /*
- * 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.
- */
- 'apps' => [
- [
- 'id' => env('PUSHER_APP_ID'),
- 'name' => env('APP_NAME'),
- 'key' => env('PUSHER_APP_KEY'),
- 'secret' => env('PUSHER_APP_SECRET'),
- 'path' => env('PUSHER_APP_PATH'),
- 'capacity' => null,
- 'enable_client_messages' => false,
- 'enable_statistics' => true,
- ],
- ],
-
- /*
- * This class is responsible for finding the apps. The default provider
- * will use the apps defined in this config file.
- *
- * You can create a custom provider by implementing the
- * `AppProvider` interface.
- */
- 'app_provider' => BeyondCode\LaravelWebSockets\Apps\ConfigAppProvider::class,
-
- /*
- * This array contains the hosts of which you want to allow incoming requests.
- * Leave this empty if you want to accept requests from all hosts.
- */
- 'allowed_origins' => [
- //
- ],
-
- /*
- * The maximum request size in kilobytes that is allowed for an incoming WebSocket request.
- */
- 'max_request_size_in_kb' => 250,
-
- /*
- * This path will be used to register the necessary routes for the package.
- */
- 'path' => 'laravel-websockets',
-
- /*
- * Dashboard Routes Middleware
- *
- * These middleware will be assigned to every dashboard route, giving you
- * the chance to add your own middleware to this list or change any of
- * the existing middleware. Or, you can simply stick with this list.
- */
- 'middleware' => [
- 'web',
- Authorize::class,
- ],
-
- 'statistics' => [
- /*
- * This model will be used to store the statistics of the WebSocketsServer.
- * The only requirement is that the model should extend
- * `WebSocketsStatisticsEntry` provided by this package.
- */
- 'model' => \BeyondCode\LaravelWebSockets\Statistics\Models\WebSocketsStatisticsEntry::class,
-
- /**
- * The Statistics Logger will, by default, handle the incoming statistics, store them
- * and then release them into the database on each interval defined below.
- */
- 'logger' => BeyondCode\LaravelWebSockets\Statistics\Logger\HttpStatisticsLogger::class,
-
- /*
- * Here you can specify the interval in seconds at which statistics should be logged.
- */
- 'interval_in_seconds' => 60,
-
- /*
- * When the clean-command is executed, all recorded statistics older than
- * the number of days specified here will be deleted.
- */
- 'delete_statistics_older_than_days' => 60,
-
- /*
- * Use an DNS resolver to make the requests to the statistics logger
- * default is to resolve everything to 127.0.0.1.
- */
- 'perform_dns_lookup' => false,
- ],
-
- /*
- * Define the optional SSL context for your WebSocket connections.
- * You can see all available options at: http://php.net/manual/en/context.ssl.php
- */
- 'ssl' => [
- /*
- * Path to local certificate file on filesystem. It must be a PEM encoded file which
- * contains your certificate and private key. It can optionally contain the
- * certificate chain of issuers. The private key also may be contained
- * in a separate file specified by local_pk.
- */
- 'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),
-
- /*
- * Path to local private key file on filesystem in case of separate files for
- * certificate (local_cert) and private key.
- */
- 'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),
-
- /*
- * Passphrase for your local_cert file.
- */
- 'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
- ],
+Run the migrations with:
- /*
- * Channel Manager
- * This class handles how channel persistence is handled.
- * By default, persistence is stored in an array by the running webserver.
- * The only requirement is that the class should implement
- * `ChannelManager` interface provided by this package.
- */
- 'channel_manager' => \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManagers\ArrayChannelManager::class,
-];
+```bash
+php artisan migrate
```
diff --git a/docs/getting-started/introduction.md b/docs/getting-started/introduction.md
index e061c8aa48..0e5050aee8 100644
--- a/docs/getting-started/introduction.md
+++ b/docs/getting-started/introduction.md
@@ -4,9 +4,10 @@ order: 1
---
# Laravel WebSockets 🛰
+
WebSockets for Laravel. Done right.
-Laravel WebSockets is a package for Laravel 5.7 and up that will get your application started with WebSockets in no-time! It has a drop-in Pusher API replacement, has a debug dashboard, realtime statistics and even allows you to create custom WebSocket controllers.
+Laravel WebSockets is a package for Laravel that will get your application started with WebSockets in no-time! It has a drop-in Pusher API replacement, has a debug dashboard, realtime statistics and even allows you to create custom WebSocket controllers.
Once installed, you can start it with one simple command:
@@ -18,4 +19,4 @@ php artisan websockets:serve
If you want to know how all of it works under the hood, we wrote an in-depth [blogpost](https://murze.be/introducing-laravel-websockets-an-easy-to-use-websocket-server-implemented-in-php) about it.
-To help you get started, you can also take a look at the [demo repository](https://github.com/beyondcode/laravel-websockets-demo), that implements a basic Chat built with this package.
\ No newline at end of file
+To help you get started, you can also take a look at the [demo repository](https://github.com/beyondcode/laravel-websockets-demo), that implements a basic Chat built with this package.
diff --git a/docs/horizontal-scaling/_index.md b/docs/horizontal-scaling/_index.md
new file mode 100644
index 0000000000..f66c2b551e
--- /dev/null
+++ b/docs/horizontal-scaling/_index.md
@@ -0,0 +1,4 @@
+---
+title: Horizontal Scaling
+order: 5
+---
diff --git a/docs/horizontal-scaling/getting-started.md b/docs/horizontal-scaling/getting-started.md
new file mode 100644
index 0000000000..1bb3ab42d8
--- /dev/null
+++ b/docs/horizontal-scaling/getting-started.md
@@ -0,0 +1,34 @@
+---
+title: Getting Started
+order: 1
+---
+
+When running Laravel WebSockets without additional configuration, you won't be able to scale your servers out.
+
+For example, even with Sticky Load Balancer settings, you won't be able to keep track of your users' connections to notify them properly when messages occur if you got multiple nodes that run the same `websockets:serve` command.
+
+The reason why this happen is because the default channel manager runs on arrays, which is not a database other instances can access.
+
+To do so, we need a database and a way of notifying other instances when connections occur.
+
+For example, Redis does a great job by encapsulating the both the way of notifying (Pub/Sub module) and the storage (key-value datastore).
+
+## Configure the replication
+
+To enable the replication, simply change the `replication.mode` name in the `websockets.php` file:
+
+```php
+'replication' => [
+
+ 'mode' => 'redis',
+
+ ...
+
+],
+```
+
+Now, when your app broadcasts the message, it will make sure the connection reaches other servers which are under the same load balancer.
+
+The available drivers for replication are:
+
+- [Redis](redis)
diff --git a/docs/horizontal-scaling/redis.md b/docs/horizontal-scaling/redis.md
new file mode 100644
index 0000000000..4f6383583b
--- /dev/null
+++ b/docs/horizontal-scaling/redis.md
@@ -0,0 +1,42 @@
+---
+title: Redis Mode
+order: 2
+---
+
+# Redis Mode
+
+Redis has the powerful ability to act both as a key-value store and as a PubSub service. This way, the connected servers will communicate between them whenever a message hits the server, so you can scale out to any amount of servers while preserving the WebSockets functionalities.
+
+## Configure Redis mode
+
+To enable the replication, simply change the `replication.mode` name in the `websockets.php` file to `redis`:
+
+```php
+'replication' => [
+
+ 'mode' => 'redis',
+
+ ...
+
+],
+```
+
+You can set the connection name to the Redis database under `redis`:
+
+```php
+'replication' => [
+
+ 'modes' =>
+
+ 'redis' => [
+
+ 'connection' => 'default',
+
+ ],
+
+ ],
+
+],
+```
+
+The connections can be found in your `config/database.php` file, under the `redis` key.
diff --git a/phpunit.xml.dist b/phpunit.xml
similarity index 82%
rename from phpunit.xml.dist
rename to phpunit.xml
index 179f0b3086..229ec35459 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml
@@ -10,7 +10,7 @@
processIsolation="false"
stopOnFailure="false">
Type | -Socket | -Details | -Time | -
---|---|---|---|
@{{ log.type }} | -@{{ log.socketId }} | -@{{ log.details }} | -@{{ log.time }} | -
+ Type + | ++ Details + | ++ Time + | +
---|---|---|
+
+ @{{ log.type }}
+
+ |
+
+ @{{ log.details }}+ |
+ + @{{ log.time }} + | +