-
Notifications
You must be signed in to change notification settings - Fork 99
/
Factory.php
129 lines (110 loc) · 4.91 KB
/
Factory.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php
namespace Laravel\Reverb\Servers\Reverb;
use InvalidArgumentException;
use Laravel\Reverb\Certificate;
use Laravel\Reverb\Contracts\ApplicationProvider;
use Laravel\Reverb\Protocols\Pusher\Contracts\ChannelConnectionManager;
use Laravel\Reverb\Protocols\Pusher\Contracts\ChannelManager;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\ChannelController;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\ChannelsController;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\ChannelUsersController;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\ConnectionsController;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\EventsBatchController;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\EventsController;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\PusherController;
use Laravel\Reverb\Protocols\Pusher\Http\Controllers\UsersTerminateController;
use Laravel\Reverb\Protocols\Pusher\Managers\ArrayChannelConnectionManager;
use Laravel\Reverb\Protocols\Pusher\Managers\ArrayChannelManager;
use Laravel\Reverb\Protocols\Pusher\PusherPubSubIncomingMessageHandler;
use Laravel\Reverb\Protocols\Pusher\Server as PusherServer;
use Laravel\Reverb\Servers\Reverb\Contracts\PubSubIncomingMessageHandler;
use Laravel\Reverb\Servers\Reverb\Http\Route;
use Laravel\Reverb\Servers\Reverb\Http\Router;
use Laravel\Reverb\Servers\Reverb\Http\Server as HttpServer;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\Socket\SocketServer;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
class Factory
{
/**
* Create a new WebSocket server instance.
*/
public static function make(
string $host = '0.0.0.0',
string $port = '8080',
?string $hostname = null,
int $maxRequestSize = 10_000,
array $options = [],
string $protocol = 'pusher',
?LoopInterface $loop = null
): HttpServer {
$loop = $loop ?: Loop::get();
$router = match ($protocol) {
'pusher' => static::makePusherRouter(),
default => throw new InvalidArgumentException("Unsupported protocol [{$protocol}]."),
};
$options['tls'] = static::configureTls($options['tls'] ?? [], $hostname);
$uri = empty($options['tls']) ? "{$host}:{$port}" : "tls://{$host}:{$port}";
return new HttpServer(
new SocketServer($uri, $options, $loop),
$router,
$maxRequestSize,
$loop
);
}
/**
* Create a new WebSocket server for the Pusher protocol.
*/
public static function makePusherRouter(): Router
{
app()->singleton(
ChannelManager::class,
fn () => new ArrayChannelManager
);
app()->bind(
ChannelConnectionManager::class,
fn () => new ArrayChannelConnectionManager
);
app()->singleton(
PubSubIncomingMessageHandler::class,
fn () => new PusherPubSubIncomingMessageHandler,
);
return new Router(new UrlMatcher(static::pusherRoutes(), new RequestContext));
}
/**
* Generate the routes required to handle Pusher requests.
*/
protected static function pusherRoutes(): RouteCollection
{
$routes = new RouteCollection;
$routes->add('sockets', Route::get('/app/{appKey}', new PusherController(app(PusherServer::class), app(ApplicationProvider::class))));
$routes->add('events', Route::post('/apps/{appId}/events', new EventsController));
$routes->add('events_batch', Route::post('/apps/{appId}/batch_events', new EventsBatchController));
$routes->add('connections', Route::get('/apps/{appId}/connections', new ConnectionsController));
$routes->add('channels', Route::get('/apps/{appId}/channels', new ChannelsController));
$routes->add('channel', Route::get('/apps/{appId}/channels/{channel}', new ChannelController));
$routes->add('channel_users', Route::get('/apps/{appId}/channels/{channel}/users', new ChannelUsersController));
$routes->add('users_terminate', Route::post('/apps/{appId}/users/{userId}/terminate_connections', new UsersTerminateController));
return $routes;
}
/**
* Configure the TLS context for the server.
*
* @param array $context<string, mixed>
* @return array<string, mixed>
*/
protected static function configureTls(array $context, ?string $hostname): array
{
$context = array_filter($context, fn ($value) => $value !== null);
$usesTls = ($context['local_cert'] ?? false) || ($context['local_pk'] ?? false);
if (! $usesTls && $hostname && Certificate::exists($hostname)) {
[$certificate, $key] = Certificate::resolve($hostname);
$context['local_cert'] = $certificate;
$context['local_pk'] = $key;
}
return $context;
}
}