Completed
Pull Request — master (#447)
by Marcel
03:06 queued 01:18
created

StartWebSocketServer::configureHttpLogger()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
dl 10
loc 10
rs 9.9332
c 0
b 0
f 0
cc 2
nc 1
nop 0
1
<?php
2
3
namespace BeyondCode\LaravelWebSockets\Console;
4
5
use BeyondCode\LaravelWebSockets\Facades\StatisticsLogger;
6
use BeyondCode\LaravelWebSockets\Facades\WebSocketsRouter;
7
use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface;
8
use BeyondCode\LaravelWebSockets\Server\Logger\ConnectionLogger;
9
use BeyondCode\LaravelWebSockets\Server\Logger\HttpLogger;
10
use BeyondCode\LaravelWebSockets\Server\Logger\WebsocketsLogger;
11
use BeyondCode\LaravelWebSockets\Server\WebSocketServerFactory;
12
use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver;
13
use BeyondCode\LaravelWebSockets\Statistics\Logger\StatisticsLogger as StatisticsLoggerInterface;
14
use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
15
use Illuminate\Console\Command;
16
use Illuminate\Support\Facades\Cache;
17
use React\EventLoop\Factory as LoopFactory;
18
19
class StartWebSocketServer extends Command
20
{
21
    /**
22
     * The name and signature of the console command.
23
     *
24
     * @var string
25
     */
26
    protected $signature = 'websockets:serve
27
        {--host=0.0.0.0}
28
        {--port=6001}
29
        {--statistics-interval= : Overwrite the statistics interval set in the config.}
30
        {--debug : Forces the loggers to be enabled and thereby overriding the APP_DEBUG setting.}
31
        {--test : Prepare the server, but do not start it.}
32
    ';
33
34
    /**
35
     * The console command description.
36
     *
37
     * @var string|null
38
     */
39
    protected $description = 'Start the Laravel WebSocket Server';
40
41
    /**
42
     * Get the loop instance.
43
     *
44
     * @var \React\EventLoop\LoopInterface
45
     */
46
    protected $loop;
47
48
    /**
49
     * The Pusher server instance.
50
     *
51
     * @var \Ratchet\Server\IoServer
52
     */
53
    public $server;
54
55
    /**
56
     * Track the last restart.
57
     *
58
     * @var int
59
     */
60
    protected $lastRestart;
61
62
    /**
63
     * Initialize the command.
64
     *
65
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
66
     */
67
    public function __construct()
68
    {
69
        parent::__construct();
70
71
        $this->loop = LoopFactory::create();
72
    }
73
74
    /**
75
     * Run the command.
76
     *
77
     * @return void
78
     */
79
    public function handle()
80
    {
81
        $this
82
            ->configureStatisticsLogger()
83
            ->configureHttpLogger()
84
            ->configureMessageLogger()
85
            ->configureConnectionLogger()
86
            ->configureRestartTimer()
87
            ->configurePubSub()
88
            ->registerRoutes()
89
            ->startWebSocketServer();
90
    }
91
92
    /**
93
     * Configure the statistics logger class.
94
     *
95
     * @return $this
96
     */
97
    protected function configureStatisticsLogger()
98
    {
99
        $this->laravel->singleton(StatisticsLoggerInterface::class, function () {
100
            $class = config('websockets.statistics.logger', \BeyondCode\LaravelWebSockets\Statistics\Logger\MemoryStatisticsLogger::class);
101
102
            return new $class(
103
                $this->laravel->make(ChannelManager::class),
104
                $this->laravel->make(StatisticsDriver::class)
105
            );
106
        });
107
108
        $this->loop->addPeriodicTimer($this->option('statistics-interval') ?: config('websockets.statistics.interval_in_seconds'), function () {
109
            $this->line('Saving statistics...');
110
111
            StatisticsLogger::save();
112
        });
113
114
        return $this;
115
    }
116
117
    /**
118
     * Configure the HTTP logger class.
119
     *
120
     * @return $this
121
     */
122 View Code Duplication
    protected function configureHttpLogger()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123
    {
124
        $this->laravel->singleton(HttpLogger::class, function () {
125
            return (new HttpLogger($this->output))
126
                ->enable($this->option('debug') ?: config('app.debug'))
127
                ->verbose($this->output->isVerbose());
128
        });
129
130
        return $this;
131
    }
132
133
    /**
134
     * Configure the logger for messages.
135
     *
136
     * @return $this
137
     */
138 View Code Duplication
    protected function configureMessageLogger()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
139
    {
140
        $this->laravel->singleton(WebsocketsLogger::class, function () {
141
            return (new WebsocketsLogger($this->output))
142
                ->enable($this->option('debug') ?: config('app.debug'))
143
                ->verbose($this->output->isVerbose());
144
        });
145
146
        return $this;
147
    }
148
149
    /**
150
     * Configure the connection logger.
151
     *
152
     * @return $this
153
     */
154 View Code Duplication
    protected function configureConnectionLogger()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
155
    {
156
        $this->laravel->bind(ConnectionLogger::class, function () {
157
            return (new ConnectionLogger($this->output))
158
                ->enable(config('app.debug'))
159
                ->verbose($this->output->isVerbose());
160
        });
161
162
        return $this;
163
    }
164
165
    /**
166
     * Configure the Redis PubSub handler.
167
     *
168
     * @return $this
169
     */
170
    public function configureRestartTimer()
171
    {
172
        $this->lastRestart = $this->getLastRestart();
173
174
        $this->loop->addPeriodicTimer(10, function () {
175
            if ($this->getLastRestart() !== $this->lastRestart) {
176
                $this->loop->stop();
177
            }
178
        });
179
180
        return $this;
181
    }
182
183
    /**
184
     * Configure the replicators.
185
     *
186
     * @return void
187
     */
188
    public function configurePubSub()
189
    {
190
        $this->laravel->singleton(ReplicationInterface::class, function () {
191
            $driver = config('websockets.replication.driver', 'local');
192
193
            $client = config(
194
                "websockets.replication.{$driver}.client",
195
                \BeyondCode\LaravelWebSockets\PubSub\Drivers\LocalClient::class
196
            );
197
198
            return (new $client)->boot($this->loop);
199
        });
200
201
        $this->laravel
202
            ->get(ReplicationInterface::class)
203
            ->boot($this->loop);
204
205
        return $this;
206
    }
207
208
    /**
209
     * Register the routes.
210
     *
211
     * @return $this
212
     */
213
    protected function registerRoutes()
214
    {
215
        WebSocketsRouter::routes();
216
217
        return $this;
218
    }
219
220
    /**
221
     * Start the server.
222
     *
223
     * @return void
224
     */
225
    protected function startWebSocketServer()
226
    {
227
        $this->info("Starting the WebSocket server on port {$this->option('port')}...");
228
229
        $this->buildServer();
230
231
        // For testing, just boot up the server, run it
232
        // but exit after the next tick.
233
        if ($this->option('test')) {
234
            $this->loop->futureTick(function () {
235
                $this->loop->stop();
236
            });
237
        }
238
239
        /* 🛰 Start the server 🛰  */
240
        $this->server->run();
241
    }
242
243
    /**
244
     * Build the server instance.
245
     *
246
     * @return void
247
     */
248
    protected function buildServer()
249
    {
250
        $this->server = new WebSocketServerFactory(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \BeyondCode\LaravelW... $this->option('port')) of type object<BeyondCode\Larave...WebSocketServerFactory> is incompatible with the declared type object<Ratchet\Server\IoServer> of property $server.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
251
            $this->option('host'), $this->option('port')
252
        );
253
254
        $this->server = $this->server
255
            ->setLoop($this->loop)
256
            ->useRoutes(WebSocketsRouter::getRoutes())
257
            ->setConsoleOutput($this->output)
258
            ->createServer();
259
    }
260
261
    /**
262
     * Get the last time the server restarted.
263
     *
264
     * @return int
265
     */
266
    protected function getLastRestart()
267
    {
268
        return Cache::get('beyondcode:websockets:restart', 0);
269
    }
270
}
271