77use Illuminate \Contracts \Queue \ShouldQueue ;
88use Illuminate \Foundation \Queue \Queueable ;
99use Illuminate \Support \Arr ;
10+ use Illuminate \Support \Facades \Log ;
11+ use Symfony \Component \Process \Exception \ProcessFailedException ;
12+ use Symfony \Component \Process \Process ;
1013
1114class SelectSpeedtestServerJob implements ShouldQueue
1215{
@@ -28,14 +31,60 @@ public function handle(): void
2831 return ;
2932 }
3033
31- $ serverId = $ this ->result ->server_id
32- ?? $ this ->getConfigServer ();
34+ // If the server id is already set, we don't need to do anything.
35+ if (Arr::exists ($ this ->result ->data , 'server.id ' )) {
36+ return ;
37+ }
3338
34- if ($ this ->result ->server_id != $ serverId ) {
35- $ this ->result ->update ([
36- 'data->server->id ' => $ serverId ,
39+ // If preferred servers are set in the config, we can use that.
40+ if (! blank (config ('speedtest.servers ' ))) {
41+ $ this ->updateServerId (
42+ result: $ this ->result ,
43+ serverId: $ this ->getConfigServer (),
44+ );
45+
46+ return ;
47+ }
48+
49+ // If blocked servers config is blank, we can skip picking a server.
50+ if (blank (config ('speedtest.blocked_servers ' ))) {
51+ return ;
52+ }
53+
54+ $ serverId = $ this ->filterBlockedServers ();
55+
56+ if (blank ($ serverId )) {
57+ Log::info ('Failed to select a server for Ookla speedtest, skipping blocked server filter. ' , [
58+ 'result_id ' => $ this ->result ->id ,
3759 ]);
60+
61+ return ;
62+ }
63+
64+ $ this ->updateServerId ($ this ->result , $ serverId );
65+ }
66+
67+ /**
68+ * Get a list of servers from config blocked servers.
69+ */
70+ private function getConfigBlockedServers (): array
71+ {
72+ $ blocked = config ('speedtest.blocked_servers ' );
73+
74+ $ blocked = array_filter (
75+ array_map (
76+ 'trim ' ,
77+ explode (', ' , $ blocked ),
78+ ),
79+ );
80+
81+ if (blank ($ blocked )) {
82+ return [];
3883 }
84+
85+ return collect ($ blocked )->mapWithKeys (function (int $ serverId ) {
86+ return [$ serverId => $ serverId ];
87+ })->toArray ();
3988 }
4089
4190 /**
@@ -56,4 +105,64 @@ private function getConfigServer(): ?string
56105 ? Arr::random ($ servers )
57106 : null ;
58107 }
108+
109+ /**
110+ * Filter servers from server list.
111+ */
112+ private function filterBlockedServers (): mixed
113+ {
114+ $ blocked = $ this ->getConfigBlockedServers ();
115+
116+ $ servers = $ this ->listServers ();
117+
118+ $ filtered = Arr::except ($ servers , $ blocked );
119+
120+ return Arr::first ($ filtered );
121+ }
122+
123+ /**
124+ * Get a list of servers.
125+ */
126+ private function listServers (): array
127+ {
128+ $ command = [
129+ 'speedtest ' ,
130+ '--accept-license ' ,
131+ '--accept-gdpr ' ,
132+ '--servers ' ,
133+ '--format=json ' ,
134+ ];
135+
136+ $ process = new Process ($ command );
137+
138+ try {
139+ $ process ->run ();
140+ } catch (ProcessFailedException $ e ) {
141+ Log::error ('Failed listing Ookla speedtest servers. ' , [
142+ 'error ' => $ e ->getMessage (),
143+ ]);
144+
145+ return [];
146+ }
147+
148+ $ servers = Arr::get (
149+ array: json_decode ($ process ->getOutput (), true ),
150+ key: 'servers ' ,
151+ default: [],
152+ );
153+
154+ return collect ($ servers )->mapWithKeys (function (array $ server ) {
155+ return [$ server ['id ' ] => $ server ['id ' ]];
156+ })->toArray ();
157+ }
158+
159+ /**
160+ * Update the result with the selected server Id.
161+ */
162+ private function updateServerId (Result $ result , int $ serverId ): void
163+ {
164+ $ result ->update ([
165+ 'data->server->id ' => $ serverId ,
166+ ]);
167+ }
59168}
0 commit comments