Skip to content

Commit 59677db

Browse files
authored
[Feature] Refactor manual and scheduled speedtest process (alexjustesen#1804)
* cache external ip address response for 30s * removed ping url config * case result service to enum * refactored scheduled speedtest process * use new speedtest process when triggering a manual test * removed old jobs * set run speedtest job timeout * removed color from result service enum * default skip ips to an empty string * fixed service enum label * log an error when a job in the speedtest batch fails * prune batches and failed jobs * moved parsing cli exception message to a helper * removed unused tests
1 parent 6c01aad commit 59677db

22 files changed

+489
-456
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace App\Actions;
4+
5+
use App\Actions\Ookla\StartSpeedtest;
6+
use Cron\CronExpression;
7+
use Lorisleiva\Actions\Concerns\AsAction;
8+
9+
class CheckForScheduledSpeedtests
10+
{
11+
use AsAction;
12+
13+
public function handle(): void
14+
{
15+
$schedule = config('speedtest.schedule');
16+
17+
if (blank($schedule) || $schedule === false) {
18+
return;
19+
}
20+
21+
StartSpeedtest::runIf(
22+
$this->isSpeedtestDue(schedule: $schedule),
23+
scheduled: true,
24+
);
25+
}
26+
27+
/**
28+
* Assess if a speedtest is due to run based on the schedule.
29+
*/
30+
private function isSpeedtestDue(string $schedule): bool
31+
{
32+
$cron = new CronExpression($schedule);
33+
34+
return $cron->isDue(
35+
currentTime: now(),
36+
timeZone: config('app.display_timezone')
37+
);
38+
}
39+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace App\Actions;
4+
5+
use Illuminate\Support\Facades\Cache;
6+
use Illuminate\Support\Facades\Http;
7+
use Illuminate\Support\Facades\Log;
8+
use Illuminate\Support\Str;
9+
use Lorisleiva\Actions\Concerns\AsAction;
10+
11+
class GetExternalIpAddress
12+
{
13+
use AsAction;
14+
15+
public function handle(): bool|string
16+
{
17+
$externalIp = Cache::remember('external_ip', 30, function (): bool|string {
18+
$response = Http::retry(3, 100)
19+
->get('https://icanhazip.com/');
20+
21+
if ($response->failed()) {
22+
$message = sprintf('Failed to fetch external IP address, %d', $response->status());
23+
24+
Log::warning($message);
25+
26+
return false;
27+
}
28+
29+
return Str::trim($response->body());
30+
});
31+
32+
return $externalIp;
33+
}
34+
}

app/Actions/Helpers/GetExternalIpAddress.php

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace App\Actions\Ookla;
4+
5+
use Illuminate\Support\Arr;
6+
use Lorisleiva\Actions\Concerns\AsAction;
7+
8+
class SelectSpeedtestServer
9+
{
10+
use AsAction;
11+
12+
public function handle(): string
13+
{
14+
$servers = config('speedtest.servers');
15+
16+
if (blank($servers)) {
17+
return '';
18+
}
19+
20+
$servers = array_filter(
21+
array_map(
22+
'trim',
23+
explode(',', $servers),
24+
),
25+
);
26+
27+
if (count($servers) < 1) {
28+
return '';
29+
}
30+
31+
return Arr::random($servers);
32+
}
33+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace App\Actions\Ookla;
4+
5+
use App\Enums\ResultService;
6+
use App\Enums\ResultStatus;
7+
use App\Events\SpeedtestStarted;
8+
use App\Jobs\Ookla\ProcessSpeedtestBatch;
9+
use App\Models\Result;
10+
use Lorisleiva\Actions\Concerns\AsAction;
11+
12+
class StartSpeedtest
13+
{
14+
use AsAction;
15+
16+
public function handle(bool $scheduled = false): void
17+
{
18+
$result = Result::create([
19+
'service' => ResultService::Ookla,
20+
'status' => ResultStatus::Started,
21+
'scheduled' => $scheduled,
22+
]);
23+
24+
$serverId = SelectSpeedtestServer::run();
25+
26+
if (! blank($serverId)) {
27+
$result->update([
28+
'data->server->id' => $serverId,
29+
]);
30+
}
31+
32+
ProcessSpeedtestBatch::dispatch(
33+
result: $result,
34+
);
35+
36+
SpeedtestStarted::dispatch($result);
37+
}
38+
}

app/Actions/Speedtests/RunOoklaSpeedtest.php

Lines changed: 0 additions & 27 deletions
This file was deleted.

app/Actions/Speedtests/RunScheduledSpeedtests.php

Lines changed: 0 additions & 36 deletions
This file was deleted.

app/Enums/ResultService.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace App\Enums;
4+
5+
use Filament\Support\Contracts\HasLabel;
6+
use Illuminate\Support\Str;
7+
8+
enum ResultService: string implements HasLabel
9+
{
10+
case Ookla = 'ookla';
11+
12+
public function getLabel(): ?string
13+
{
14+
return Str::title($this->name);
15+
}
16+
}

app/Filament/Exports/ResultExporter.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ public static function getColumns(): array
4242
return $record->server_location;
4343
})
4444
->enabledByDefault(false),
45-
ExportColumn::make('service'),
45+
ExportColumn::make('service')
46+
->state(function (Result $record) {
47+
return $record->service->getLabel();
48+
}),
4649
ExportColumn::make('server_id')
4750
->label('Server ID')
4851
->state(function (Result $record): ?string {
@@ -107,7 +110,10 @@ public static function getColumns(): array
107110
}),
108111
ExportColumn::make('comments')
109112
->enabledByDefault(false),
110-
// ExportColumn::make('status'), // TODO: enable status when upgrading to PHP v8.3: https://php.watch/versions/8.3/dynamic-class-const-enum-member-syntax-support
113+
ExportColumn::make('status')
114+
->state(function (Result $record) {
115+
return $record->status->getLabel();
116+
}),
111117
ExportColumn::make('scheduled')
112118
->state(function (Result $record): string {
113119
return $record->scheduled ? 'Yes' : 'No';

app/Filament/Pages/Dashboard.php

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace App\Filament\Pages;
44

5-
use App\Actions\Speedtests\RunOoklaSpeedtest;
5+
use App\Actions\Ookla\StartSpeedtest;
66
use App\Filament\Widgets\RecentDownloadChartWidget;
77
use App\Filament\Widgets\RecentDownloadLatencyChartWidget;
88
use App\Filament\Widgets\RecentJitterChartWidget;
@@ -17,7 +17,6 @@
1717
use Filament\Notifications\Notification;
1818
use Filament\Pages\Dashboard as BasePage;
1919
use Filament\Support\Enums\IconPosition;
20-
use Illuminate\Support\Arr;
2120

2221
class Dashboard extends BasePage
2322
{
@@ -27,11 +26,13 @@ class Dashboard extends BasePage
2726

2827
public function getSubheading(): ?string
2928
{
30-
if (blank(config('speedtest.schedule'))) {
29+
$schedule = config('speedtest.schedule');
30+
31+
if (blank($schedule) || $schedule === false) {
3132
return __('No speedtests scheduled.');
3233
}
3334

34-
$cronExpression = new CronExpression(config('speedtest.schedule'));
35+
$cronExpression = new CronExpression($schedule);
3536

3637
$nextRunDate = Carbon::parse($cronExpression->getNextRunDate(timeZone: config('app.display_timezone')))->format(config('app.datetime_format'));
3738

@@ -51,17 +52,7 @@ protected function getHeaderActions(): array
5152
ActionGroup::make([
5253
Action::make('ookla speedtest')
5354
->action(function () {
54-
$servers = array_filter(
55-
explode(',', config('speedtest.servers'))
56-
);
57-
58-
$serverId = null;
59-
60-
if (count($servers)) {
61-
$serverId = Arr::random($servers);
62-
}
63-
64-
RunOoklaSpeedtest::run(serverId: $serverId);
55+
StartSpeedtest::run();
6556

6657
Notification::make()
6758
->title('Ookla speedtest started')

0 commit comments

Comments
 (0)