diff --git a/app/Actions/CheckInternetConnection.php b/app/Actions/CheckInternetConnection.php deleted file mode 100644 index 22e26f78d..000000000 --- a/app/Actions/CheckInternetConnection.php +++ /dev/null @@ -1,33 +0,0 @@ -timeout(5) - ->get(config('speedtest.checkinternet_url')); - - if (! $response->ok()) { - return false; - } - - return Str::trim($response->body()); - } catch (Throwable $e) { - Log::error('Failed to connect to the internet.', [$e->getMessage()]); - - return false; - } - } -} diff --git a/app/Actions/GetExternalIpAddress.php b/app/Actions/GetExternalIpAddress.php index 6a4d0b114..d47cc0a6f 100644 --- a/app/Actions/GetExternalIpAddress.php +++ b/app/Actions/GetExternalIpAddress.php @@ -12,18 +12,28 @@ class GetExternalIpAddress { use AsAction; - public function handle(): bool|string + public function handle(?string $url = null): array { + $url = $url ?? config('speedtest.preflight.external_ip_url'); + try { $response = Http::retry(3, 100) ->timeout(5) - ->get(url: 'https://icanhazip.com/'); + ->get(url: $url); } catch (Throwable $e) { - Log::error('Failed to fetch external IP address.', [$e->getMessage()]); + $message = sprintf('Failed to fetch external IP address from "%s". See the logs for more details.', $url); + + Log::error($message, [$e->getMessage()]); - return false; + return [ + 'ok' => false, + 'body' => $message, + ]; } - return Str::trim($response->body()); + return [ + 'ok' => $response->ok(), + 'body' => Str::of($response->body())->trim()->toString(), + ]; } } diff --git a/app/Actions/PingHostname.php b/app/Actions/PingHostname.php new file mode 100644 index 000000000..7707f1abe --- /dev/null +++ b/app/Actions/PingHostname.php @@ -0,0 +1,27 @@ +run(); + + return $ping; + } +} diff --git a/app/Jobs/CheckForInternetConnectionJob.php b/app/Jobs/CheckForInternetConnectionJob.php index 37c5e6f04..c0f39a61f 100644 --- a/app/Jobs/CheckForInternetConnectionJob.php +++ b/app/Jobs/CheckForInternetConnectionJob.php @@ -2,7 +2,7 @@ namespace App\Jobs; -use App\Actions\CheckInternetConnection; +use App\Actions\PingHostname; use App\Enums\ResultStatus; use App\Events\SpeedtestChecking; use App\Events\SpeedtestFailed; @@ -44,14 +44,18 @@ public function handle(): void SpeedtestChecking::dispatch($this->result); - if (CheckInternetConnection::run() !== false) { + $ping = PingHostname::run(); + + if ($ping->isSuccess()) { return; } + $message = sprintf('Failed to connected to hostname "%s". Error received "%s".', $ping->getHost(), $ping->error()?->value); + $this->result->update([ 'data->type' => 'log', 'data->level' => 'error', - 'data->message' => 'Failed to connect to the internet.', + 'data->message' => $message, 'status' => ResultStatus::Failed, ]); diff --git a/app/Jobs/Ookla/SkipSpeedtestJob.php b/app/Jobs/Ookla/SkipSpeedtestJob.php index 13c444133..948fe792d 100644 --- a/app/Jobs/Ookla/SkipSpeedtestJob.php +++ b/app/Jobs/Ookla/SkipSpeedtestJob.php @@ -4,6 +4,7 @@ use App\Actions\GetExternalIpAddress; use App\Enums\ResultStatus; +use App\Events\SpeedtestFailed; use App\Events\SpeedtestSkipped; use App\Helpers\Network; use App\Models\Result; @@ -47,8 +48,23 @@ public function handle(): void $externalIp = GetExternalIpAddress::run(); + if ($externalIp['ok'] === false) { + $this->result->update([ + 'data->type' => 'log', + 'data->level' => 'error', + 'data->message' => $externalIp['body'], + 'status' => ResultStatus::Failed, + ]); + + SpeedtestFailed::dispatch($this->result); + + $this->batch()->cancel(); + + return; + } + $shouldSkip = $this->shouldSkip( - externalIp: $externalIp, + externalIp: $externalIp['body'], ); if ($shouldSkip === false) { @@ -76,11 +92,11 @@ private function shouldSkip(string $externalIp): bool|string $skipIPs = array_filter( array_map( 'trim', - explode(',', config('speedtest.skip_ips')), + explode(',', config('speedtest.preflight.skip_ips')), ), ); - if (count($skipIPs) < 1) { + if (empty($skipIPs)) { return false; } diff --git a/composer.json b/composer.json index 77cf9452a..4fe2349e4 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,6 @@ "dragonmantank/cron-expression": "^3.6.0", "filament/filament": "4.1.0", "filament/spatie-laravel-settings-plugin": "^4.1", - "geerlingguy/ping": "^1.2.1", "influxdata/influxdb-client-php": "^3.8", "laravel-notification-channels/telegram": "^6.0", "laravel/framework": "^12.41.1", @@ -36,6 +35,7 @@ "spatie/laravel-query-builder": "^6.3.6", "spatie/laravel-settings": "^3.6.0", "spatie/laravel-webhook-server": "^3.8.3", + "spatie/ping": "^1.1.1", "zircote/swagger-php": "^5.7.6" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 23ff73cb5..6c492d7d9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "405d221f03e4de1894ce759a9e751448", + "content-hash": "374762e19dbfc99374c14f3f12a4ae3e", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -1779,43 +1779,6 @@ ], "time": "2025-12-03T09:33:47+00:00" }, - { - "name": "geerlingguy/ping", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/geerlingguy/Ping.git", - "reference": "e0206326e23c99e3e8820e24705f8ca517adff93" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/geerlingguy/Ping/zipball/e0206326e23c99e3e8820e24705f8ca517adff93", - "reference": "e0206326e23c99e3e8820e24705f8ca517adff93", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "JJG/Ping.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jeff Geerling", - "email": "jeff@jeffgeerling.com" - } - ], - "description": "A PHP class to ping hosts.", - "support": { - "issues": "https://github.com/geerlingguy/Ping/issues", - "source": "https://github.com/geerlingguy/Ping/tree/1.2.1" - }, - "time": "2019-07-29T21:54:12+00:00" - }, { "name": "graham-campbell/result-type", "version": "v1.1.3", @@ -6919,6 +6882,65 @@ ], "time": "2025-02-14T12:55:41+00:00" }, + { + "name": "spatie/ping", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/ping.git", + "reference": "6123a6209148e8919f58121d256f43c75856ab35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/ping/zipball/6123a6209148e8919f58121d256f43c75856ab35", + "reference": "6123a6209148e8919f58121d256f43c75856ab35", + "shasum": "" + }, + "require": { + "php": "^8.4", + "symfony/process": "^7.0" + }, + "require-dev": { + "laravel/pint": "^1.0", + "pestphp/pest": "^3.0", + "spatie/pest-expectations": "^1.13", + "spatie/ray": "^1.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Ping\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Run an ICMP ping and get structured results", + "homepage": "https://github.com/spatie/ping", + "keywords": [ + "ping", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/ping/issues", + "source": "https://github.com/spatie/ping/tree/1.1.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-08-12T20:58:12+00:00" + }, { "name": "spatie/shiki-php", "version": "2.3.2", diff --git a/config/speedtest.php b/config/speedtest.php index ec4e255a3..b68a6a040 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -6,9 +6,9 @@ /** * General settings. */ - 'build_date' => Carbon::parse('2025-12-15'), + 'build_date' => Carbon::parse('2025-12-16'), - 'build_version' => 'v1.12.4', + 'build_version' => 'v1.13.0', 'content_width' => env('CONTENT_WIDTH', '7xl'), @@ -29,15 +29,17 @@ 'interface' => env('SPEEDTEST_INTERFACE'), - 'checkinternet_url' => env('SPEEDTEST_CHECKINTERNET_URL', 'https://icanhazip.com'), + 'preflight' => [ + 'external_ip_url' => env('SPEEDTEST_CHECKINTERNET_URL') ?? env('SPEEDTEST_EXTERNAL_IP_URL', 'https://icanhazip.com'), + 'internet_check_hostname' => env('SPEEDTEST_CHECKINTERNET_URL') ?? env('SPEEDTEST_INTERNET_CHECK_HOSTNAME', 'icanhazip.com'), + 'skip_ips' => env('SPEEDTEST_SKIP_IPS'), + ], /** * IP filtering settings. */ 'allowed_ips' => env('ALLOWED_IPS'), - 'skip_ips' => env('SPEEDTEST_SKIP_IPS', ''), - /** * Threshold settings. */ diff --git a/resources/views/filament/pages/dashboard.blade.php b/resources/views/filament/pages/dashboard.blade.php index 42a849976..b92cde2a9 100644 --- a/resources/views/filament/pages/dashboard.blade.php +++ b/resources/views/filament/pages/dashboard.blade.php @@ -11,6 +11,7 @@ class="col-span-1" icon="tabler-book" icon-size="md" + :compact="true" > {{ __('general.documentation') }} @@ -35,6 +36,7 @@ class="col-span-1" class="col-span-1" icon="tabler-cash-banknote-heart" icon-size="md" + :compact="true" > {{ __('general.donations') }} @@ -59,6 +61,7 @@ class="col-span-1" class="col-span-1" icon="tabler-brand-github" icon-size="md" + :compact="true" > {{ __('general.speedtest_tracker') }} diff --git a/resources/views/livewire/latest-result-stats.blade.php b/resources/views/livewire/latest-result-stats.blade.php index a3cc2b708..c1c69eeec 100644 --- a/resources/views/livewire/latest-result-stats.blade.php +++ b/resources/views/livewire/latest-result-stats.blade.php @@ -24,7 +24,7 @@ - + {{ __('general.download') }} @@ -63,7 +63,7 @@

- + {{ __('general.upload') }} @@ -102,7 +102,7 @@

- + {{ __('general.ping') }} @@ -135,7 +135,7 @@

- + {{ __('results.packet_loss') }} diff --git a/resources/views/livewire/next-speedtest-banner.blade.php b/resources/views/livewire/next-speedtest-banner.blade.php index ce65f81d7..e66d3c1ee 100644 --- a/resources/views/livewire/next-speedtest-banner.blade.php +++ b/resources/views/livewire/next-speedtest-banner.blade.php @@ -8,7 +8,7 @@

- Next scheduled test at {{ $this->nextSpeedtest->timezone(config('app.display_timezone'))->format('F jS, Y, g:i a') }}. + Next scheduled test at {{ $this->nextSpeedtest->timezone(config('app.display_timezone'))->format(config('app.datetime_format')) }}.

diff --git a/resources/views/livewire/platform-stats.blade.php b/resources/views/livewire/platform-stats.blade.php index 567c1f31a..f8f149e6e 100644 --- a/resources/views/livewire/platform-stats.blade.php +++ b/resources/views/livewire/platform-stats.blade.php @@ -23,7 +23,7 @@
--}} - + Total tests @@ -31,7 +31,7 @@

{{ $this->platformStats['total'] }}

- + Total completed tests @@ -39,7 +39,7 @@

{{ $this->platformStats['completed'] }}

- + Total failed tests