Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

Commit a08eee6

Browse files
authored
Merge pull request #475 from beyondcode/fix/memory-leaks
[fix] Memory Leaks
2 parents b4c7f34 + 70ce44e commit a08eee6

File tree

15 files changed

+137
-323
lines changed

15 files changed

+137
-323
lines changed

config/websockets.php

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -239,37 +239,6 @@
239239

240240
'delete_statistics_older_than_days' => 60,
241241

242-
/*
243-
|--------------------------------------------------------------------------
244-
| DNS Lookup
245-
|--------------------------------------------------------------------------
246-
|
247-
| Use an DNS resolver to make the requests to the statistics logger
248-
| default is to resolve everything to 127.0.0.1.
249-
|
250-
*/
251-
252-
'perform_dns_lookup' => false,
253-
254-
/*
255-
|--------------------------------------------------------------------------
256-
| DNS Lookup TLS Settings
257-
|--------------------------------------------------------------------------
258-
|
259-
| You can configure the DNS Lookup Connector the TLS settings.
260-
| Check the available options here:
261-
| https://github.com/reactphp/socket/blob/master/src/Connector.php#L29
262-
|
263-
*/
264-
265-
'tls' => [
266-
267-
'verify_peer' => env('APP_ENV') === 'production',
268-
269-
'verify_peer_name' => env('APP_ENV') === 'production',
270-
271-
],
272-
273242
],
274243

275244
];

resources/views/dashboard.blade.php

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,29 @@ class="rounded-full px-3 py-2 text-white focus:outline-none"
8484
v-if="connected && app.statisticsEnabled"
8585
class="w-full my-6 px-6"
8686
>
87-
<div class="font-semibold uppercase text-gray-700">
88-
Live statistics
89-
</div>
87+
<div class="flex justify-between items-center">
88+
<span class="font-semibold uppercase text-gray-700">
89+
Live statistics
90+
</span>
91+
92+
<div class="space-x-3 flex items-center">
93+
<div>
94+
<input
95+
type="checkbox"
96+
v-model="autoRefresh"
97+
class="mr-2"
98+
/>
99+
Refresh automatically
100+
</div>
101+
102+
<button
103+
@click="loadChart"
104+
class="rounded-full bg-blue-500 hover:bg-blue-600 focus:outline-none text-white px-3 py-1"
105+
>
106+
Refresh
107+
</button>
108+
</div>
109+
</div>
90110

91111
<div
92112
id="statisticsChart"
@@ -222,6 +242,9 @@ class="rounded-full px-3 py-1 inline-block text-sm"
222242
connected: false,
223243
connecting: false,
224244
sendingEvent: false,
245+
autoRefresh: true,
246+
refreshInterval: {{ $refreshInterval }},
247+
refreshTicker: null,
225248
chart: null,
226249
pusher: null,
227250
app: null,
@@ -236,6 +259,19 @@ class="rounded-full px-3 py-1 inline-block text-sm"
236259
mounted () {
237260
this.app = this.apps[0] || null;
238261
},
262+
destroyed () {
263+
if (this.refreshTicker) {
264+
this.clearRefreshInterval();
265+
}
266+
},
267+
watch: {
268+
connected (newVal) {
269+
newVal ? this.startRefreshInterval() : this.clearRefreshInterval();
270+
},
271+
autoRefresh (newVal) {
272+
newVal ? this.startRefreshInterval() : this.clearRefreshInterval();
273+
},
274+
},
239275
methods: {
240276
connect () {
241277
this.connecting = true;
@@ -274,12 +310,14 @@ class="rounded-full px-3 py-1 inline-block text-sm"
274310
this.connected = false;
275311
this.connecting = false;
276312
this.logs = [];
313+
this.chart = null;
277314
});
278315
279316
this.pusher.connection.bind('error', event => {
280317
if (event.error.data.code === 4100) {
281318
this.connected = false;
282319
this.logs = [];
320+
this.chart = null;
283321
284322
throw new Error("Over capacity");
285323
}
@@ -288,12 +326,12 @@ class="rounded-full px-3 py-1 inline-block text-sm"
288326
});
289327
290328
this.subscribeToAllChannels();
291-
this.subscribeToStatistics();
292329
},
293330
294331
disconnect () {
295332
this.pusher.disconnect();
296333
this.connecting = false;
334+
this.chart = null;
297335
},
298336
299337
loadChart () {
@@ -333,7 +371,10 @@ class="rounded-full px-3 py-1 inline-block text-sm"
333371
autosize: true,
334372
};
335373
336-
this.chart = Plotly.newPlot('statisticsChart', chartData, layout);
374+
this.chart = this.chart
375+
? Plotly.react('statisticsChart', chartData, layout)
376+
: Plotly.newPlot('statisticsChart', chartData, layout);
377+
337378
});
338379
},
339380
@@ -348,18 +389,6 @@ class="rounded-full px-3 py-1 inline-block text-sm"
348389
});
349390
},
350391
351-
subscribeToStatistics () {
352-
this.pusher.subscribe('{{ $logPrefix }}statistics')
353-
.bind('statistics-updated', (data) => {
354-
var update = {
355-
x: [[data.time], [data.time], [data.time]],
356-
y: [[data.peak_connection_count], [data.websocket_message_count], [data.api_message_count]],
357-
};
358-
359-
Plotly.extendTraces('statisticsChart', update, [0, 1, 2]);
360-
});
361-
},
362-
363392
sendEvent () {
364393
if (! this.sendingEvent) {
365394
this.sendingEvent = true;
@@ -415,6 +444,17 @@ class="rounded-full px-3 py-1 inline-block text-sm"
415444
416445
return 'bg-gray-700 text-white';
417446
},
447+
448+
startRefreshInterval () {
449+
this.refreshTicker = setInterval(function () {
450+
this.loadChart();
451+
}.bind(this), this.refreshInterval * 1000);
452+
},
453+
454+
stopRefreshInterval () {
455+
clearInterval(this.refreshTicker);
456+
this.refreshTicker = null;
457+
},
418458
},
419459
});
420460
</script>

src/Console/StartWebSocketServer.php

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,12 @@
1111
use BeyondCode\LaravelWebSockets\Server\Logger\HttpLogger;
1212
use BeyondCode\LaravelWebSockets\Server\Logger\WebsocketsLogger;
1313
use BeyondCode\LaravelWebSockets\Server\WebSocketServerFactory;
14-
use BeyondCode\LaravelWebSockets\Statistics\DnsResolver;
14+
use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver;
1515
use BeyondCode\LaravelWebSockets\Statistics\Logger\StatisticsLogger as StatisticsLoggerInterface;
1616
use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
17-
use Clue\React\Buzz\Browser;
1817
use Illuminate\Console\Command;
1918
use Illuminate\Support\Facades\Cache;
20-
use React\Dns\Config\Config as DnsConfig;
21-
use React\Dns\Resolver\Factory as DnsFactory;
22-
use React\Dns\Resolver\ResolverInterface;
2319
use React\EventLoop\Factory as LoopFactory;
24-
use React\Socket\Connector;
2520

2621
class StartWebSocketServer extends Command
2722
{
@@ -103,19 +98,12 @@ public function handle()
10398
*/
10499
protected function configureStatisticsLogger()
105100
{
106-
$connector = new Connector($this->loop, [
107-
'dns' => $this->getDnsResolver(),
108-
'tls' => config('websockets.statistics.tls'),
109-
]);
110-
111-
$browser = new Browser($this->loop, $connector);
112-
113-
$this->laravel->singleton(StatisticsLoggerInterface::class, function () use ($browser) {
101+
$this->laravel->singleton(StatisticsLoggerInterface::class, function () {
114102
$class = config('websockets.statistics.logger', \BeyondCode\LaravelWebSockets\Statistics\Logger\MemoryStatisticsLogger::class);
115103

116104
return new $class(
117105
$this->laravel->make(ChannelManager::class),
118-
$browser
106+
$this->laravel->make(StatisticsDriver::class)
119107
);
120108
});
121109

@@ -273,27 +261,6 @@ protected function buildServer()
273261
->createServer();
274262
}
275263

276-
/**
277-
* Create a DNS resolver for the stats manager.
278-
*
279-
* @return \React\Dns\Resolver\ResolverInterface
280-
*/
281-
protected function getDnsResolver(): ResolverInterface
282-
{
283-
if (! config('websockets.statistics.perform_dns_lookup')) {
284-
return new DnsResolver;
285-
}
286-
287-
$dnsConfig = DnsConfig::loadSystemConfigBlocking();
288-
289-
return (new DnsFactory)->createCached(
290-
$dnsConfig->nameservers
291-
? reset($dnsConfig->nameservers)
292-
: '1.1.1.1',
293-
$this->loop
294-
);
295-
}
296-
297264
/**
298265
* Get the last time the server restarted.
299266
*

src/Dashboard/Http/Controllers/DashboardApiController.php

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,21 @@
22

33
namespace BeyondCode\LaravelWebSockets\Dashboard\Http\Controllers;
44

5+
use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver;
6+
use Illuminate\Http\Request;
7+
58
class DashboardApiController
69
{
710
/**
811
* Get statistics for an app ID.
912
*
13+
* @param \Illuminate\Http\Request $request
14+
* @param \BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver $driver
1015
* @param mixed $appId
1116
* @return \Illuminate\Http\Response
1217
*/
13-
public function getStatistics($appId)
18+
public function getStatistics(Request $request, StatisticsDriver $driver, $appId)
1419
{
15-
$model = config('websockets.statistics.model');
16-
17-
$statistics = $model::where('app_id', $appId)
18-
->latest()
19-
->limit(120)
20-
->get();
21-
22-
$statisticData = $statistics->map(function ($statistic) {
23-
return [
24-
'timestamp' => (string) $statistic->created_at,
25-
'peak_connection_count' => $statistic->peak_connection_count,
26-
'websocket_message_count' => $statistic->websocket_message_count,
27-
'api_message_count' => $statistic->api_message_count,
28-
];
29-
})->reverse();
30-
31-
return [
32-
'peak_connections' => [
33-
'x' => $statisticData->pluck('timestamp'),
34-
'y' => $statisticData->pluck('peak_connection_count'),
35-
],
36-
'websocket_message_count' => [
37-
'x' => $statisticData->pluck('timestamp'),
38-
'y' => $statisticData->pluck('websocket_message_count'),
39-
],
40-
'api_message_count' => [
41-
'x' => $statisticData->pluck('timestamp'),
42-
'y' => $statisticData->pluck('api_message_count'),
43-
],
44-
];
20+
return $driver::get($appId, $request);
4521
}
4622
}

src/Dashboard/Http/Controllers/ShowDashboard.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function __invoke(Request $request, AppManager $apps)
2222
'port' => config('websockets.dashboard.port', 6001),
2323
'channels' => DashboardLogger::$channels,
2424
'logPrefix' => DashboardLogger::LOG_CHANNEL_PREFIX,
25+
'refreshInterval' => config('websockets.statistics.interval_in_seconds'),
2526
]);
2627
}
2728
}

src/Statistics/Drivers/DatabaseDriver.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace BeyondCode\LaravelWebSockets\Statistics\Drivers;
44

55
use Carbon\Carbon;
6+
use Illuminate\Http\Request;
67

78
class DatabaseDriver implements StatisticsDriver
89
{
@@ -87,6 +88,46 @@ public static function create(array $data): StatisticsDriver
8788
return new static($class::create($data));
8889
}
8990

91+
/**
92+
* Get the records to show to the dashboard.
93+
*
94+
* @param mixed $appId
95+
* @param \Illuminate\Http\Request $request
96+
* @return array
97+
*/
98+
public static function get($appId, Request $request): array
99+
{
100+
$class = config('websockets.statistics.database.model');
101+
102+
$statistics = $class::whereAppId($appId)
103+
->latest()
104+
->limit(120)
105+
->get()
106+
->map(function ($statistic) {
107+
return [
108+
'timestamp' => (string) $statistic->created_at,
109+
'peak_connection_count' => $statistic->peak_connection_count,
110+
'websocket_message_count' => $statistic->websocket_message_count,
111+
'api_message_count' => $statistic->api_message_count,
112+
];
113+
})->reverse();
114+
115+
return [
116+
'peak_connections' => [
117+
'x' => $statistics->pluck('timestamp'),
118+
'y' => $statistics->pluck('peak_connection_count'),
119+
],
120+
'websocket_message_count' => [
121+
'x' => $statistics->pluck('timestamp'),
122+
'y' => $statistics->pluck('websocket_message_count'),
123+
],
124+
'api_message_count' => [
125+
'x' => $statistics->pluck('timestamp'),
126+
'y' => $statistics->pluck('api_message_count'),
127+
],
128+
];
129+
}
130+
90131
/**
91132
* Delete statistics from the store,
92133
* optionally by app id, returning

src/Statistics/Drivers/StatisticsDriver.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace BeyondCode\LaravelWebSockets\Statistics\Drivers;
44

5+
use Illuminate\Http\Request;
6+
57
interface StatisticsDriver
68
{
79
/**
@@ -55,6 +57,15 @@ public function getApiMessageCount(): int;
5557
*/
5658
public static function create(array $data): StatisticsDriver;
5759

60+
/**
61+
* Get the records to show to the dashboard.
62+
*
63+
* @param mixed $appId
64+
* @param \Illuminate\Http\Request $request
65+
* @return void
66+
*/
67+
public static function get($appId, Request $request);
68+
5869
/**
5970
* Delete statistics from the store,
6071
* optionally by app id, returning

0 commit comments

Comments
 (0)