Completed
Pull Request — master (#447)
by Alexandru
01:33
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
            $replicationDriver = config('websockets.replication.driver', 'local');
101
102
            $class = config("websockets.replication.{$replicationDriver}.statistics_logger", \BeyondCode\LaravelWebSockets\Statistics\Logger\MemoryStatisticsLogger::class);
103
104
            return new $class(
105
                $this->laravel->make(ChannelManager::class),
106
                $this->laravel->make(StatisticsDriver::class)
107
            );
108
        });
109
110
        $this->loop->addPeriodicTimer($this->option('statistics-interval') ?: config('websockets.statistics.interval_in_seconds'), function () {
111
            $this->line('Saving statistics...');
112
113
            StatisticsLogger::save();
114
        });
115
116
        return $this;
117
    }
118
119
    /**
120
     * Configure the HTTP logger class.
121
     *
122
     * @return $this
123
     */
124 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...
125
    {
126
        $this->laravel->singleton(HttpLogger::class, function () {
127
            return (new HttpLogger($this->output))
128
                ->enable($this->option('debug') ?: config('app.debug'))
129
                ->verbose($this->output->isVerbose());
130
        });
131
132
        return $this;
133
    }
134
135
    /**
136
     * Configure the logger for messages.
137
     *
138
     * @return $this
139
     */
140 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...
141
    {
142
        $this->laravel->singleton(WebsocketsLogger::class, function () {
143
            return (new WebsocketsLogger($this->output))
144
                ->enable($this->option('debug') ?: config('app.debug'))
145
                ->verbose($this->output->isVerbose());
146
        });
147
148
        return $this;
149
    }
150
151
    /**
152
     * Configure the connection logger.
153
     *
154
     * @return $this
155
     */
156 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...
157
    {
158
        $this->laravel->bind(ConnectionLogger::class, function () {
159
            return (new ConnectionLogger($this->output))
160
                ->enable(config('app.debug'))
161
                ->verbose($this->output->isVerbose());
162
        });
163
164
        return $this;
165
    }
166
167
    /**
168
     * Configure the Redis PubSub handler.
169
     *
170
     * @return $this
171
     */
172
    public function configureRestartTimer()
173
    {
174
        $this->lastRestart = $this->getLastRestart();
175
176
        $this->loop->addPeriodicTimer(10, function () {
177
            if ($this->getLastRestart() !== $this->lastRestart) {
178
                $this->loop->stop();
179
            }
180
        });
181
182
        return $this;
183
    }
184
185
    /**
186
     * Configure the replicators.
187
     *
188
     * @return void
189
     */
190
    public function configurePubSub()
191
    {
192
        $this->laravel->singleton(ReplicationInterface::class, function () {
193
            $driver = config('websockets.replication.driver', 'local');
194
195
            $client = config(
196
                "websockets.replication.{$driver}.client",
197
                \BeyondCode\LaravelWebSockets\PubSub\Drivers\LocalClient::class
198
            );
199
200
            return (new $client)->boot($this->loop);
201
        });
202
203
        $this->laravel
204
            ->get(ReplicationInterface::class)
205
            ->boot($this->loop);
206
207
        return $this;
208
    }
209
210
    /**
211
     * Register the routes.
212
     *
213
     * @return $this
214
     */
215
    protected function registerRoutes()
216
    {
217
        WebSocketsRouter::routes();
218
219
        return $this;
220
    }
221
222
    /**
223
     * Start the server.
224
     *
225
     * @return void
226
     */
227
    protected function startWebSocketServer()
228
    {
229
        $this->info("Starting the WebSocket server on port {$this->option('port')}...");
230
231
        $this->buildServer();
232
233
        // For testing, just boot up the server, run it
234
        // but exit after the next tick.
235
        if ($this->option('test')) {
236
            $this->loop->futureTick(function () {
237
                $this->loop->stop();
238
            });
239
        }
240
241
        /* 🛰 Start the server 🛰  */
242
        $this->server->run();
243
    }
244
245
    /**
246
     * Build the server instance.
247
     *
248
     * @return void
249
     */
250
    protected function buildServer()
251
    {
252
        $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...
253
            $this->option('host'), $this->option('port')
254
        );
255
256
        $this->server = $this->server
257
            ->setLoop($this->loop)
258
            ->useRoutes(WebSocketsRouter::getRoutes())
259
            ->setConsoleOutput($this->output)
260
            ->createServer();
261
    }
262
263
    /**
264
     * Get the last time the server restarted.
265
     *
266
     * @return int
267
     */
268
    protected function getLastRestart()
269
    {
270
        return Cache::get('beyondcode:websockets:restart', 0);
271
    }
272
}
273