Skip to content

Commit ed2022f

Browse files
author
Daniel LaBarge
committed
Update to stable version of PHPCS Fixer. Made manager more extensible. Added provider to make setup easier. Added more docs.
1 parent 7c052ba commit ed2022f

28 files changed

+186
-73
lines changed

.editorconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ indent_size = 4
1515
indent_style = tab
1616

1717
# 4-spaced files
18-
[**.{js,json,php,xml,md}]
18+
[**.{js,json,php,xml,md,yml,yaml}]
1919
indent_size = 4
2020

2121
# 2-spaced files
22-
[**.{css,less,sass,scss,html,htm,xhtml,yml,blade.php}]
22+
[**.{css,less,sass,scss,html,htm,xhtml,blade.php}]
2323
indent_size = 2
2424

2525
[{node_modules,vendor,bower_components}/**]

.php_cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@ return Config::create()
1414
'not_operator_with_space' => true,
1515
'ordered_imports' => true,
1616
'phpdoc_order' => true,
17-
'phpdoc_type_to_var' => true,
1817
'psr0' => false,
19-
'short_array_syntax' => true,
20-
'unalign_double_arrow' => false,
21-
'unalign_equals' => false,
18+
'array_syntax' => [
19+
'syntax' => 'short',
20+
],
21+
'binary_operator_spaces' => [
22+
'align_double_arrow' => true,
23+
'align_equals' => true,
24+
],
2225
])
23-
->finder(
26+
->setFinder(
2427
Finder::create()
25-
->in(__DIR__.'/src')
2628
->in(__DIR__.'/config')
29+
->in(__DIR__.'/src')
2730
->in(__DIR__.'/tests')
2831
);

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"wyrihaximus/react-guzzle-psr7": "~2.0"
1616
},
1717
"require-dev": {
18-
"friendsofphp/php-cs-fixer": "2.0.0-alpha",
18+
"friendsofphp/php-cs-fixer": "~2.2",
1919
"fzaninotto/faker": "~1.4",
2020
"mockery/mockery": "0.9.*",
2121
"phpunit/phpunit": "~5.7"

config/server.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
<?php
22

33
return [
4+
/*
5+
|--------------------------------------------------------------------------
6+
| Manager Class
7+
|--------------------------------------------------------------------------
8+
|
9+
| The server runs as a singleton instance with with the server being the
10+
| main event loop manager, the broker being the connection handler, and
11+
| the manager being the kernel of the application. Sometimes you have
12+
| to extend the manager and this config lets you customize that.
13+
|
14+
*/
15+
16+
'manager' => ArtisanSDK\Server\Manager::class,
17+
418
/*
519
|--------------------------------------------------------------------------
620
| Server Address Bindings
@@ -65,5 +79,4 @@
6579
'namespaces' => [
6680
'ArtianSDK\\Server\\Messages\\',
6781
],
68-
6982
];

readme.md

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
A service-based, Laravel PHP implementation of an async, realtime, WebSocket server.
44

5+
## Table of Contents
6+
7+
- [Installation](#installation)
8+
- [Configure the Environment](#configure-the-environment)
9+
- [Nginx Websocket Proxy Configuration](#nginx-websocket-proxy-configuration)
10+
- [Running the Server (Supervisord)](#running-the-server)
11+
- [Usage Guide](#usage-guide)
12+
- [Extending the Server Manager](#extending-the-server-manager)
13+
- [Pushing Messages to the Realtime Queue](#pushing-messages-to-the-realtime-queue)
14+
- [Authenticating Client Messages](#authenticating-client-messages)
15+
- [Licensing](#licensing)
16+
517
## Installation
618

719
The package installs into a Laravel application like any other Laravel package:
@@ -10,6 +22,14 @@ The package installs into a Laravel application like any other Laravel package:
1022
composer require artisansdk/server ~1.0
1123
```
1224

25+
Then in your Laravel application's `config/app.php` add the `ArtisanSDK\Server\Provider::class`
26+
to the `providers` key. This will register the configs and Artisan commands provided
27+
by the package. You can publish these configs to `config/server.php` by running:
28+
29+
```
30+
php artisan vendor:publish --provider="ArtisanSDK\\Server\\Provider" --tag=config`
31+
```
32+
1333
> **Show Me:** You can see how to integrate this package by browsing the source
1434
code of [`larandomizer/app`](http://github.com/larandomizer/app) which powers
1535
[Larandomizer.com](http://larandomizer.com).
@@ -28,16 +48,6 @@ for server customization:
2848
- `SERVER_QUEUE_DRIVER` (`beanstalkd`): the driver to use for the realtime message queue
2949
- `SERVER_KEY` (`password`): the admin password to authenticate connections against admin protected connections
3050

31-
There is a basic auth scheme in place which allows the server to `PromptForAuthentication`
32-
against a connection and then remember that the connection is authenticated. This
33-
simplifies further message processing and relies on any `ClientMessage` that must
34-
be authenticated to implement the `authorize()` method. There are three basic
35-
traits that can be used on any message to achieve a couple of common strategies:
36-
37-
- `ArtisanSDK\Server\Traits\NoProtection`: always returns true so allows any client to send the message
38-
- `ArtisanSDK\Server\Traits\ClientProtection`: allows admin connections and a specific related connection to be authorized
39-
- `ArtisanSDK\Server\Traits\AdminProtection`: allows only admins to be authorized to send the message
40-
4151
### Nginx Websocket Proxy Configuration
4252

4353
Nginx makes the perfect lightweight frontend server for the Laravel backend
@@ -49,7 +59,7 @@ settings you can host websockets securely with the `wss://` protocol allowing
4959
Nginx to handle the SSL connection and your websocket server handling basic HTTP.
5060

5161
```
52-
location /socket/ {
62+
location /server/ {
5363
proxy_pass http://127.0.0.1:8080;
5464
proxy_set_header X-Real-IP $remote_addr;
5565
proxy_set_header Host $host;
@@ -63,16 +73,14 @@ location /socket/ {
6373

6474
A quick note on the settings used:
6575

66-
- `location /socket/` directs all traffic going to `/socket/` to the proxy
76+
- `location /server/` directs all traffic going to `/server/` to the proxy
6777
- `proxy_pass` passes the traffic to the localhost webserver on port `8080`
6878
- `proxy_read_timeout` customizes the connection drop to hang up idle connections
6979
- `proxy_http_version` is the version of the websocket protocol in HTTP
7080
- `X-Real-IP` header gives your websocket server the real IP of the client connection
7181
- `Upgrade` and `Connection` headers instruct the browser to upgrade to websocket connection
7282

73-
## Usage Guide
74-
75-
### Starting the Server
83+
### Running the Server
7684

7785
The websocket server can be ran as an console command using `php artisan server:start`
7886
and if you pass `--help` to the command you can see additional options. You can
@@ -104,9 +112,56 @@ Forge does not add the `startsecs` by default but in practice this may be needed
104112
to give the server ample time to start without hard exiting and forcing Supervisor
105113
to give up on starting the process.
106114

115+
116+
## Usage Guide
117+
118+
### Extending the Server Manager
119+
120+
The WebSocket server is a singleton instance that wraps brokers all connections
121+
and messages between connected clients and the server via `Broker`. While this class
122+
rarely needs modification, the broker collaborates with the `Manager` class. You
123+
can think of the manager as the kernel of the application as it maintains the
124+
initial boot state and event loop the entire time the server is running. It has
125+
sensible defaults but will likely need extending for anything domain specific.
126+
127+
Simple create a new manager class in your local namespace such and include a `boot()`
128+
method which will be called to initialize your application's custom listeners:
129+
130+
```php
131+
<?php
132+
133+
namespace App;
134+
135+
use ArtisanSDK\Server\Manager as BaseManager;
136+
137+
class Manager extends BaseManager
138+
{
139+
public function boot()
140+
{
141+
parent::boot();
142+
143+
$this->listener(...);
144+
}
145+
}
146+
```
147+
148+
As you can see in this example it's a good idea to call the parent `boot()` method
149+
if you want to maintain the existing behavior and simply add on new behavior. With
150+
the class extended, you now just need to update the configuration setting in
151+
`app/server.php` under the key `server.manager` to `App\Manager::class` so the
152+
server knows which manager to use:
153+
154+
```php
155+
<?php
156+
157+
return [
158+
'manager' => App\Manager::class,
159+
];
160+
```
161+
107162
### Pushing Messages to the Realtime Queue
108163

109-
By default the `ArtisanSDK\Server\Manager@start()` method adds a queue worker to the
164+
By default the `ArtisanSDK\Server\Manager@boot()` method adds a queue worker to the
110165
async event loop so that "offline" messages can be sent to the "realtime" connected
111166
websocket clients. You can use any async driver (basically don't use `sync` as
112167
the queue driver) but if you are using Laravel Forge it is pretty easy to use
@@ -118,9 +173,22 @@ to your "realtime" code you can `use ArtisanSDK\Server\Traits\WebsocketQueue` tr
118173
your caller class and then call `$this->queue(new Command)` to push server
119174
commands into the event loop of the websocket server. Commands should run nearly
120175
instantly though there can be some lag depending on remaining commands within the
121-
event loop. You can tweak the timing of the worker in `ArtisanSDK\Server\Manager@start()`
176+
event loop. You can tweak the timing of the worker in `ArtisanSDK\Server\Manager@boot()`
122177
method's configuration of the worker.
123178

179+
### Authenticating Client Messages
180+
181+
There is a basic auth scheme in place which allows the server to `PromptForAuthentication`
182+
against a connection and then remember that the connection is authenticated. This
183+
simplifies further message processing and relies on any `ClientMessage` that must
184+
be authenticated to implement the `authorize()` method. There are three basic
185+
traits that can be used on any message to achieve a couple of common strategies:
186+
187+
- `ArtisanSDK\Server\Traits\NoProtection`: always returns true so allows any client to send the message
188+
- `ArtisanSDK\Server\Traits\ClientProtection`: allows admin or specific connections to be authorized
189+
- `ArtisanSDK\Server\Traits\AdminProtection`: allows only admins to be authorized to send the message
190+
191+
124192
## Licensing
125193

126194
Copyright (c) 2017 [Artisans Collaborative](http://artisanscollaborative.com)

src/Broker.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ protected function maxConnections()
284284
protected function resolveMessage($message)
285285
{
286286
$arguments = (array) json_decode($message, true);
287-
$name = array_get($arguments, 'name');
288-
$class = $this->resolveMessageClass($name);
287+
$name = array_get($arguments, 'name');
288+
$class = $this->resolveMessageClass($name);
289289

290290
return new $class($arguments);
291291
}
@@ -295,7 +295,7 @@ protected function resolveMessage($message)
295295
*
296296
* @param string $name of class
297297
*
298-
* @throws \InvalidArgumentException if class cannot be found in path.
298+
* @throws \InvalidArgumentException if class cannot be found in path
299299
*
300300
* @return string
301301
*/

src/Commands/GetJob.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class GetJob extends Command
1212
public function run()
1313
{
1414
$dispatcher = $this->dispatcher();
15-
$job = $dispatcher->connector()
15+
$job = $dispatcher->connector()
1616
->pop($dispatcher->queue());
1717
if ( ! $job) {
1818
return;

src/Commands/NotifyConnection.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function __construct(array $arguments = [])
1717
{
1818
parent::__construct($arguments);
1919
$this->receiver = array_get($arguments, 'receiver');
20-
$this->sender = array_get($arguments, 'sender');
20+
$this->sender = array_get($arguments, 'sender');
2121
}
2222

2323
/**
@@ -32,7 +32,7 @@ public function run()
3232

3333
$receiver = $everyone->uuid($this->receiver);
3434

35-
$notification = new Notification($this->sender);
35+
$notification = new Notification($this->sender);
3636
$notifications = $receiver->notifications();
3737
$notifications->put($notification->sender(), $notification);
3838

src/Commands/RunQueuedCommands.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class RunQueuedCommands extends Command
1212
public function run()
1313
{
1414
$dispatcher = $this->dispatcher();
15-
$commands = $dispatcher->commands();
15+
$commands = $dispatcher->commands();
1616

1717
$commands->each(function ($command) use ($dispatcher, $commands) {
1818
$dispatcher->run($command);

src/Console/ServerStart.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace ArtisanSDK\Server\Console;
44

5-
use ArtisanSDK\Server\Manager;
65
use ArtisanSDK\Server\Server;
76
use Illuminate\Console\Command;
87
use Illuminate\Support\Facades\Queue;
@@ -38,7 +37,7 @@ public function __construct()
3837
*/
3938
protected function makeSignature()
4039
{
41-
$options = [];
40+
$options = [];
4241
$options[] = '--A|address='.config('server.address').' : The address that the server will bind to for client connections';
4342
$options[] = '--P|port='.config('server.port').' : The port that the server will listen on for client connections';
4443
$options[] = '--Q|queue='.config('server.queue').' : The message queue that the server will be responsible for processing';
@@ -58,7 +57,6 @@ public function handle()
5857
{
5958
Server::make()
6059
->bind($this->option('address'), $this->option('port'))
61-
->uses(new Manager())
6260
->uses($this->getOutput())
6361
->uses(Queue::connection($this->option('connector')), $this->option('queue'))
6462
->password($this->option('key'))

0 commit comments

Comments
 (0)