diff --git a/app/Jobs/Ookla/SelectSpeedtestServerJob.php b/app/Jobs/Ookla/SelectSpeedtestServerJob.php index f86e932f3..11a67468d 100644 --- a/app/Jobs/Ookla/SelectSpeedtestServerJob.php +++ b/app/Jobs/Ookla/SelectSpeedtestServerJob.php @@ -7,6 +7,9 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; use Illuminate\Support\Arr; +use Illuminate\Support\Facades\Log; +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; class SelectSpeedtestServerJob implements ShouldQueue { @@ -28,14 +31,60 @@ public function handle(): void return; } - $serverId = $this->result->server_id - ?? $this->getConfigServer(); + // If the server id is already set, we don't need to do anything. + if (Arr::exists($this->result->data, 'server.id')) { + return; + } - if ($this->result->server_id != $serverId) { - $this->result->update([ - 'data->server->id' => $serverId, + // If preferred servers are set in the config, we can use that. + if (! blank(config('speedtest.servers'))) { + $this->updateServerId( + result: $this->result, + serverId: $this->getConfigServer(), + ); + + return; + } + + // If blocked servers config is blank, we can skip picking a server. + if (blank(config('speedtest.blocked_servers'))) { + return; + } + + $serverId = $this->filterBlockedServers(); + + if (blank($serverId)) { + Log::info('Failed to select a server for Ookla speedtest, skipping blocked server filter.', [ + 'result_id' => $this->result->id, ]); + + return; + } + + $this->updateServerId($this->result, $serverId); + } + + /** + * Get a list of servers from config blocked servers. + */ + private function getConfigBlockedServers(): array + { + $blocked = config('speedtest.blocked_servers'); + + $blocked = array_filter( + array_map( + 'trim', + explode(',', $blocked), + ), + ); + + if (blank($blocked)) { + return []; } + + return collect($blocked)->mapWithKeys(function (int $serverId) { + return [$serverId => $serverId]; + })->toArray(); } /** @@ -56,4 +105,64 @@ private function getConfigServer(): ?string ? Arr::random($servers) : null; } + + /** + * Filter servers from server list. + */ + private function filterBlockedServers(): mixed + { + $blocked = $this->getConfigBlockedServers(); + + $servers = $this->listServers(); + + $filtered = Arr::except($servers, $blocked); + + return Arr::first($filtered); + } + + /** + * Get a list of servers. + */ + private function listServers(): array + { + $command = [ + 'speedtest', + '--accept-license', + '--accept-gdpr', + '--servers', + '--format=json', + ]; + + $process = new Process($command); + + try { + $process->run(); + } catch (ProcessFailedException $e) { + Log::error('Failed listing Ookla speedtest servers.', [ + 'error' => $e->getMessage(), + ]); + + return []; + } + + $servers = Arr::get( + array: json_decode($process->getOutput(), true), + key: 'servers', + default: [], + ); + + return collect($servers)->mapWithKeys(function (array $server) { + return [$server['id'] => $server['id']]; + })->toArray(); + } + + /** + * Update the result with the selected server Id. + */ + private function updateServerId(Result $result, int $serverId): void + { + $result->update([ + 'data->server->id' => $serverId, + ]); + } } diff --git a/config/speedtest.php b/config/speedtest.php index b5b3568f4..084a053f1 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -33,6 +33,8 @@ 'servers' => env('SPEEDTEST_SERVERS'), + 'blocked_servers' => env('SPEEDTEST_BLOCKED_SERVERS'), + /** * IP filtering settings. */