diff --git a/app/Actions/Influxdb/v2/BuildPointData.php b/app/Actions/Influxdb/v2/BuildPointData.php new file mode 100644 index 000000000..cb8b34d89 --- /dev/null +++ b/app/Actions/Influxdb/v2/BuildPointData.php @@ -0,0 +1,65 @@ +addTag('app_name', config('app.name')) + ->time($result->created_at->timestamp ?? time()); + + // Qualitative tags + $point->addTag('result_id', $result->id) + ->addTag('external_ip', Arr::get($result->data, 'interface.externalIp')) + ->addTag('id', $result->id) + ->addTag('isp', Arr::get($result->data, 'isp')) + ->addTag('service', $result->service->value) + ->addTag('server_id', Arr::get($result->data, 'server.id')) + ->addTag('server_name', Arr::get($result->data, 'server.name')) + ->addTag('server_country', Arr::get($result->data, 'server.country')) + ->addTag('server_location', Arr::get($result->data, 'server.location')) + ->addTag('healthy', $this->evalHealthyTag($result->healthy)) + ->addTag('status', $result->status->value) + ->addTag('scheduled', $result->scheduled ? 'true' : 'false'); + + // Quantitative fields + $point->addField('download', $result->download) + ->addField('upload', $result->upload) + ->addField('ping', $result->ping) + ->addField('download_bits', ! blank($result->download) ? Bitrate::bytesToBits($result->download) : null) + ->addField('upload_bits', ! blank($result->upload) ? Bitrate::bytesToBits($result->upload) : null) + ->addField('download_jitter', Arr::get($result->data, 'download.latency.jitter')) + ->addField('upload_jitter', Arr::get($result->data, 'upload.latency.jitter')) + ->addField('ping_jitter', Arr::get($result->data, 'ping.jitter')) + ->addField('download_latency_avg', Arr::get($result->data, 'download.latency.iqm')) + ->addField('download_latency_high', Arr::get($result->data, 'download.latency.high')) + ->addField('download_latency_low', Arr::get($result->data, 'download.latency.low')) + ->addField('upload_latency_avg', Arr::get($result->data, 'upload.latency.iqm')) + ->addField('upload_latency_high', Arr::get($result->data, 'upload.latency.high')) + ->addField('upload_latency_low', Arr::get($result->data, 'upload.latency.low')) + ->addField('packet_loss', Arr::get($result->data, 'packetLoss')); + + return $point; + } + + private function evalHealthyTag(?bool $value): ?string + { + if (is_null($value)) { + return null; + } + + return $value + ? 'true' + : 'false'; + } +} diff --git a/app/Actions/Influxdb/v2/CreateClient.php b/app/Actions/Influxdb/v2/CreateClient.php new file mode 100644 index 000000000..e0ef2d93a --- /dev/null +++ b/app/Actions/Influxdb/v2/CreateClient.php @@ -0,0 +1,27 @@ + $settings->influxdb_v2_url, + 'token' => $settings->influxdb_v2_token, + 'bucket' => $settings->influxdb_v2_bucket, + 'org' => $settings->influxdb_v2_org, + 'verifySSL' => $settings->influxdb_v2_verify_ssl, + 'precision' => WritePrecision::S, + ]); + } +} diff --git a/app/Console/Commands/TestInfluxDB.php b/app/Console/Commands/TestInfluxDB.php deleted file mode 100644 index 0824fbc8a..000000000 --- a/app/Console/Commands/TestInfluxDB.php +++ /dev/null @@ -1,42 +0,0 @@ - $settings->v2_enabled, - 'url' => $settings?->v2_url, - 'org' => $settings?->v2_org, - 'bucket' => $settings?->v2_bucket, - 'token' => $settings?->v2_token, - ]; - - if ($influxdb['enabled'] == true) { - $result = Result::factory()->create(); - } - } -} diff --git a/app/Enums/ResultService.php b/app/Enums/ResultService.php index 94ee19765..b324633a3 100644 --- a/app/Enums/ResultService.php +++ b/app/Enums/ResultService.php @@ -7,6 +7,7 @@ enum ResultService: string implements HasLabel { + case Faker = 'faker'; case Ookla = 'ookla'; public function getLabel(): ?string diff --git a/app/Filament/Pages/Settings/DataIntegrationPage.php b/app/Filament/Pages/Settings/DataIntegrationPage.php new file mode 100644 index 000000000..d49792ca4 --- /dev/null +++ b/app/Filament/Pages/Settings/DataIntegrationPage.php @@ -0,0 +1,126 @@ +user()->is_admin; + } + + public static function shouldRegisterNavigation(): bool + { + return auth()->user()->is_admin; + } + + public function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\Grid::make([ + 'default' => 1, + 'md' => 3, + ]) + ->schema([ + Forms\Components\Section::make('InfluxDB v2') + ->description('When enabled, all new Speedtest results will also be sent to InfluxDB.') + ->schema([ + Forms\Components\Toggle::make('influxdb_v2_enabled') + ->label('Enable') + ->reactive() + ->columnSpanFull(), + Forms\Components\Grid::make(['default' => 1, 'md' => 3]) + ->hidden(fn (Forms\Get $get) => $get('influxdb_v2_enabled') !== true) + ->schema([ + Forms\Components\TextInput::make('influxdb_v2_url') + ->label('URL') + ->placeholder('http://your-influxdb-instance') + ->maxLength(255) + ->required(fn (Forms\Get $get) => $get('influxdb_v2_enabled') === true) + ->columnSpan(['md' => 1]), + Forms\Components\TextInput::make('influxdb_v2_org') + ->label('Org') + ->maxLength(255) + ->required(fn (Forms\Get $get) => $get('influxdb_v2_enabled') === true) + ->columnSpan(['md' => 1]), + Forms\Components\TextInput::make('influxdb_v2_bucket') + ->placeholder('speedtest-tracker') + ->label('Bucket') + ->maxLength(255) + ->required(fn (Forms\Get $get) => $get('influxdb_v2_enabled') === true) + ->columnSpan(['md' => 2]), + Forms\Components\TextInput::make('influxdb_v2_token') + ->label('Token') + ->maxLength(255) + ->password() + ->required(fn (Forms\Get $get) => $get('influxdb_v2_enabled') === true) + ->disableAutocomplete() + ->columnSpan(['md' => 2]), + Forms\Components\Checkbox::make('influxdb_v2_verify_ssl') + ->label('Verify SSL') + ->columnSpanFull(), + // Button to send old data to InfluxDB + Forms\Components\Actions::make([ + Forms\Components\Actions\Action::make('Export current results') + ->label('Export current results') + ->action(function () { + Notification::make() + ->title('Starting bulk data write to Influxdb') + ->info() + ->send(); + + BulkWriteResults::dispatch(Auth::user()); + }) + ->color('primary') + ->icon('heroicon-o-cloud-arrow-up') + ->visible(fn (): bool => app(DataIntegrationSettings::class)->influxdb_v2_enabled), + ]), + // Button to test InfluxDB connection + Forms\Components\Actions::make([ + Forms\Components\Actions\Action::make('Test connection') + ->label('Test connection') + ->action(function () { + Notification::make() + ->title('Sending test data to Influxdb') + ->info() + ->send(); + + TestConnectionJob::dispatch(Auth::user()); + }) + ->color('primary') + ->icon('heroicon-o-check-circle') + ->visible(fn (): bool => app(DataIntegrationSettings::class)->influxdb_v2_enabled), + ]), + ]), + ]) + ->compact() + ->columns([ + 'default' => 1, + 'md' => 2, + ]), + ]), + ]); + } +} diff --git a/app/Filament/Pages/Settings/InfluxDbPage.php b/app/Filament/Pages/Settings/InfluxDbPage.php deleted file mode 100644 index 1c0d495e7..000000000 --- a/app/Filament/Pages/Settings/InfluxDbPage.php +++ /dev/null @@ -1,92 +0,0 @@ -user()->is_admin; - } - - public static function shouldRegisterNavigation(): bool - { - return auth()->user()->is_admin; - } - - public function form(Form $form): Form - { - return $form - ->schema([ - Forms\Components\Grid::make([ - 'default' => 1, - ]) - ->schema([ - Forms\Components\Section::make('InfluxDB v2 Settings') - ->schema([ - Forms\Components\Toggle::make('v2_enabled') - ->label('Enable') - ->reactive() - ->columnSpan(2), - Forms\Components\Grid::make([ - 'default' => 1, - 'md' => 3, - ]) - ->hidden(fn (Forms\Get $get) => $get('v2_enabled') !== true) - ->schema([ - Forms\Components\TextInput::make('v2_url') - ->label('URL') - ->placeholder('http://your-influxdb-instance') - ->maxLength(255) - ->required(fn (Forms\Get $get) => $get('v2_enabled') == true) - ->columnSpanFull(), - Forms\Components\Checkbox::make('v2_verify_ssl') - ->label('Verify SSL') - ->columnSpanFull(), - Forms\Components\TextInput::make('v2_org') - ->label('Org') - ->maxLength(255) - ->required(fn (Forms\Get $get) => $get('v2_enabled') == true) - ->columnSpan(['md' => 2]), - Forms\Components\TextInput::make('v2_bucket') - ->placeholder('speedtest-tracker') - ->label('Bucket') - ->maxLength(255) - ->required(fn (Forms\Get $get) => $get('v2_enabled') == true) - ->columnSpan(['md' => 1]), - Forms\Components\TextInput::make('v2_token') - ->label('Token') - ->maxLength(255) - ->password() - ->required(fn (Forms\Get $get) => $get('v2_enabled') == true) - ->disableAutocomplete() - ->columnSpanFull(), - ]), - ]) - ->compact() - ->columns([ - 'default' => 1, - 'md' => 2, - ]), - ]) - ->columnSpan('full'), - ]); - } -} diff --git a/app/Jobs/InfluxDBv2/WriteCompletedSpeedtest.php b/app/Jobs/InfluxDBv2/WriteCompletedSpeedtest.php deleted file mode 100644 index c06de4525..000000000 --- a/app/Jobs/InfluxDBv2/WriteCompletedSpeedtest.php +++ /dev/null @@ -1,71 +0,0 @@ - $this->settings->v2_enabled, - 'url' => $this->settings?->v2_url, - 'org' => $this->settings?->v2_org, - 'bucket' => $this->settings?->v2_bucket, - 'token' => $this->settings?->v2_token, - 'verifySSL' => $this->settings->v2_verify_ssl, - ]; - - $client = new Client([ - 'url' => $influxdb['url'], - 'token' => $influxdb['token'], - 'bucket' => $influxdb['bucket'], - 'org' => $influxdb['org'], - 'verifySSL' => $influxdb['verifySSL'], - 'precision' => \InfluxDB2\Model\WritePrecision::S, - ]); - - $writeApi = $client->createWriteApi(); - - $dataArray = [ - 'name' => 'speedtest', - 'tags' => $this->result->formatTagsForInfluxDB2(), - 'fields' => $this->result->formatForInfluxDB2(), - 'time' => strtotime($this->result->created_at), - ]; - - try { - $writeApi->write($dataArray); - } catch (\Exception $e) { - Log::info($e); - - $this->fail(); - } - - $writeApi->close(); - } -} diff --git a/app/Jobs/Influxdb/v2/BulkWriteResults.php b/app/Jobs/Influxdb/v2/BulkWriteResults.php new file mode 100644 index 000000000..f5c8de9a6 --- /dev/null +++ b/app/Jobs/Influxdb/v2/BulkWriteResults.php @@ -0,0 +1,81 @@ +createWriteApi(); + + Result::query() + ->where('status', '=', ResultStatus::Completed) + ->chunkById(100, function (Collection $results) use ($writeApi) { + $points = []; + + foreach ($results as $result) { + $points[] = BuildPointData::run($result); + } + + try { + $writeApi->write($points); + } catch (\Exception $e) { + Log::error('Failed to bulk write to InfluxDB.', [ + 'error' => $e->getMessage(), + ]); + + Notification::make() + ->title('Failed to build write to Influxdb.') + ->body('Check the logs for more details.') + ->danger() + ->sendToDatabase($this->user); + + $this->fail($e); + + $writeApi->close(); + + return; + } + }); + + $writeApi->close(); + + Notification::make() + ->title('Finished bulk data load to Influxdb.') + ->body('Data has been sent to InfluxDB, check if the data was received.') + ->success() + ->sendToDatabase($this->user); + } +} diff --git a/app/Jobs/Influxdb/v2/TestConnectionJob.php b/app/Jobs/Influxdb/v2/TestConnectionJob.php new file mode 100644 index 000000000..1dc24bd69 --- /dev/null +++ b/app/Jobs/Influxdb/v2/TestConnectionJob.php @@ -0,0 +1,65 @@ +make(); + + $client = CreateClient::run(); + + $writeApi = $client->createWriteApi(); + + $point = BuildPointData::run($result); + + try { + $writeApi->write($point); + } catch (ApiException $e) { + Log::error('Failed to write test data to Influxdb.', [ + 'error' => $e->getMessage(), + ]); + + Notification::make() + ->title('Influxdb test failed') + ->body('Check the logs for more details.') + ->danger() + ->sendToDatabase($this->user); + + $writeApi->close(); + + return; + } + + $writeApi->close(); + + Notification::make() + ->title('Successfully sent test data to Influxdb') + ->body('Test data has been sent to InfluxDB, check if the data was received.') + ->success() + ->sendToDatabase($this->user); + } +} diff --git a/app/Jobs/Influxdb/v2/WriteResult.php b/app/Jobs/Influxdb/v2/WriteResult.php new file mode 100644 index 000000000..6d4cf128c --- /dev/null +++ b/app/Jobs/Influxdb/v2/WriteResult.php @@ -0,0 +1,47 @@ +createWriteApi(); + + $point = BuildPointData::run($this->result); + + try { + $writeApi->write($point); + } catch (\Exception $e) { + Log::error('Failed to write to InfluxDB.', [ + 'error' => $e->getMessage(), + 'result_id' => $this->result->id, + ]); + + $this->fail($e); + } + + $writeApi->close(); + } +} diff --git a/app/Listeners/Data/InfluxDb2Listener.php b/app/Listeners/Data/InfluxDb2Listener.php deleted file mode 100644 index 622ec5be6..000000000 --- a/app/Listeners/Data/InfluxDb2Listener.php +++ /dev/null @@ -1,22 +0,0 @@ -v2_enabled) { - WriteCompletedSpeedtest::dispatch($event->result, $influxSettings); - } - } -} diff --git a/app/Listeners/SpeedtestEventSubscriber.php b/app/Listeners/SpeedtestEventSubscriber.php new file mode 100644 index 000000000..3588209c6 --- /dev/null +++ b/app/Listeners/SpeedtestEventSubscriber.php @@ -0,0 +1,45 @@ +influxdb_v2_enabled) { + WriteResult::dispatch($event->result); + } + } + + /** + * Register the listeners for the subscriber. + */ + public function subscribe(Dispatcher $events): void + { + $events->listen( + SpeedtestFailed::class, + [SpeedtestEventSubscriber::class, 'handleSpeedtestFailed'] + ); + + $events->listen( + SpeedtestCompleted::class, + [SpeedtestEventSubscriber::class, 'handleSpeedtestCompleted'] + ); + } +} diff --git a/app/Models/Result.php b/app/Models/Result.php index db5ffcc3c..3ac4caa77 100644 --- a/app/Models/Result.php +++ b/app/Models/Result.php @@ -4,16 +4,15 @@ use App\Enums\ResultService; use App\Enums\ResultStatus; +use App\Models\Traits\ResultDataAttributes; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Prunable; -use Illuminate\Support\Arr; class Result extends Model { - use HasFactory, Prunable; + use HasFactory, Prunable, ResultDataAttributes; /** * The attributes that aren't mass assignable. @@ -33,53 +32,9 @@ protected function casts(): array 'benchmarks' => 'array', 'data' => 'array', 'healthy' => 'boolean', + 'scheduled' => 'boolean', 'service' => ResultService::class, 'status' => ResultStatus::class, - 'scheduled' => 'boolean', - ]; - } - - /** - * The tag attributes to be passed to influxdb - */ - public function formatTagsForInfluxDB2(): array - { - return [ - 'server_id' => (int) $this->server_id, - 'server_host' => $this->server_host, - 'server_name' => $this->server_name, - ]; - } - - /** - * The attributes to be passed to influxdb - */ - public function formatForInfluxDB2() - { - return [ - 'id' => $this->id, - 'ping' => $this?->ping, - 'download' => $this?->download, - 'upload' => $this?->upload, - 'download_bits' => $this->download_bits, - 'upload_bits' => $this->upload_bits, - 'ping_jitter' => $this->ping_jitter, - 'download_jitter' => $this->download_jitter, - 'upload_jitter' => $this->upload_jitter, - 'download_latency_avg' => $this->download_latency_iqm, - 'download_latency_low' => $this->download_latency_low, - 'download_latency_high' => $this->download_latency_high, - 'upload_latency_avg' => $this->upload_latency_iqm, - 'upload_latency_low' => $this->upload_latency_low, - 'upload_latency_high' => $this->upload_latency_high, - 'server_id' => $this?->server_id, - 'isp' => $this?->isp, - 'server_host' => $this?->server_host, - 'server_name' => $this?->server_name, - 'server_location' => $this?->server_location, - 'scheduled' => $this->scheduled, - 'successful' => $this->status === ResultStatus::Completed, - 'packet_loss' => (float) $this->packet_loss, ]; } @@ -90,208 +45,4 @@ public function prunable(): Builder { return static::where('created_at', '<=', now()->subDays(config('speedtest.prune_results_older_than'))); } - - /** - * Get the result's download in bits. - */ - protected function downloadBits(): Attribute - { - return Attribute::make( - get: fn (): ?int => ! blank($this->download) && is_numeric($this->download) - ? number_format(num: $this->download * 8, decimals: 0, thousands_separator: '') - : null, - ); - } - - /** - * Get the result's download jitter in milliseconds. - */ - protected function downloadJitter(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'download.latency.jitter'), - ); - } - - /** - * Get the result's download latency high in milliseconds. - */ - protected function downloadlatencyHigh(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'download.latency.high'), - ); - } - - /** - * Get the result's download latency low in milliseconds. - */ - protected function downloadlatencyLow(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'download.latency.low'), - ); - } - - /** - * Get the result's download latency iqm in milliseconds. - */ - protected function downloadlatencyiqm(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'download.latency.iqm'), - ); - } - - /** - * Get the result's download jitter in milliseconds. - */ - protected function errorMessage(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'message', ''), - ); - } - - /** - * Get the result's external ip address (yours). - */ - protected function ipAddress(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'interface.externalIp'), - ); - } - - /** - * Get the result's isp tied to the external (yours) ip address. - */ - protected function isp(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'isp'), - ); - } - - /** - * Get the result's packet loss as a percentage. - */ - protected function packetLoss(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'packetLoss'), - ); - } - - /** - * Get the result's ping jitter in milliseconds. - */ - protected function pingJitter(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'ping.jitter'), - ); - } - - /** - * Get the result's server ID. - */ - protected function resultUrl(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'result.url'), - ); - } - - /** - * Get the result's server host. - */ - protected function serverHost(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'server.host'), - ); - } - - /** - * Get the result's server ID. - */ - protected function serverId(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'server.id'), - ); - } - - /** - * Get the result's server name. - */ - protected function serverName(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'server.name'), - ); - } - - /** - * Get the result's server location. - */ - protected function serverLocation(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'server.location'), - ); - } - - /** - * Get the result's upload in bits. - */ - protected function uploadBits(): Attribute - { - return Attribute::make( - get: fn (): ?int => ! blank($this->upload) && is_numeric($this->upload) - ? number_format(num: $this->upload * 8, decimals: 0, thousands_separator: '') - : null, - ); - } - - /** - * Get the result's upload jitter in milliseconds. - */ - protected function uploadJitter(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'upload.latency.jitter'), - ); - } - - /** - * Get the result's upload latency high in milliseconds. - */ - protected function uploadlatencyHigh(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'upload.latency.high'), - ); - } - - /** - * Get the result's upload latency low in milliseconds. - */ - protected function uploadlatencyLow(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'upload.latency.low'), - ); - } - - /** - * Get the result's upload latency iqm in milliseconds. - */ - protected function uploadlatencyiqm(): Attribute - { - return Attribute::make( - get: fn () => Arr::get($this->data, 'upload.latency.iqm'), - ); - } } diff --git a/app/Models/Traits/ResultDataAttributes.php b/app/Models/Traits/ResultDataAttributes.php new file mode 100644 index 000000000..c4fe9e26b --- /dev/null +++ b/app/Models/Traits/ResultDataAttributes.php @@ -0,0 +1,210 @@ + ! blank($this->download) ? Bitrate::bytesToBits($this->download) : null, + ); + } + + /** + * Get the result's download jitter in milliseconds. + */ + protected function downloadJitter(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'download.latency.jitter'), + ); + } + + /** + * Get the result's download latency high in milliseconds. + */ + protected function downloadlatencyHigh(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'download.latency.high'), + ); + } + + /** + * Get the result's download latency low in milliseconds. + */ + protected function downloadlatencyLow(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'download.latency.low'), + ); + } + + /** + * Get the result's download latency iqm in milliseconds. + */ + protected function downloadlatencyiqm(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'download.latency.iqm'), + ); + } + + /** + * Get the result's download jitter in milliseconds. + */ + protected function errorMessage(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'message', ''), + ); + } + + /** + * Get the result's external ip address (yours). + */ + protected function ipAddress(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'interface.externalIp'), + ); + } + + /** + * Get the result's isp tied to the external ip address. + */ + protected function isp(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'isp'), + ); + } + + /** + * Get the result's packet loss as a percentage. + */ + protected function packetLoss(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'packetLoss'), + ); + } + + /** + * Get the result's ping jitter in milliseconds. + */ + protected function pingJitter(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'ping.jitter'), + ); + } + + /** + * Get the result's server ID. + */ + protected function resultUrl(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'result.url'), + ); + } + + /** + * Get the result's server host. + */ + protected function serverHost(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'server.host'), + ); + } + + /** + * Get the result's server ID. + */ + protected function serverId(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'server.id'), + ); + } + + /** + * Get the result's server name. + */ + protected function serverName(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'server.name'), + ); + } + + /** + * Get the result's server location. + */ + protected function serverLocation(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'server.location'), + ); + } + + /** + * Get the result's upload in bits. + */ + protected function uploadBits(): Attribute + { + return Attribute::make( + get: fn (): null|int|float => ! blank($this->upload) ? Bitrate::bytesToBits($this->upload) : null, + ); + } + + /** + * Get the result's upload jitter in milliseconds. + */ + protected function uploadJitter(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'upload.latency.jitter'), + ); + } + + /** + * Get the result's upload latency high in milliseconds. + */ + protected function uploadlatencyHigh(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'upload.latency.high'), + ); + } + + /** + * Get the result's upload latency low in milliseconds. + */ + protected function uploadlatencyLow(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'upload.latency.low'), + ); + } + + /** + * Get the result's upload latency iqm in milliseconds. + */ + protected function uploadlatencyiqm(): Attribute + { + return Attribute::make( + get: fn () => Arr::get($this->data, 'upload.latency.iqm'), + ); + } +} diff --git a/app/Settings/DataIntegrationSettings.php b/app/Settings/DataIntegrationSettings.php new file mode 100644 index 000000000..2cc29515e --- /dev/null +++ b/app/Settings/DataIntegrationSettings.php @@ -0,0 +1,25 @@ + 'faker', + 'service' => ResultService::Faker, 'data' => $output, 'status' => ResultStatus::Failed, 'scheduled' => false, @@ -40,7 +41,7 @@ public function definition(): array } return [ - 'service' => 'faker', + 'service' => ResultService::Faker, 'ping' => Arr::get($output, 'ping.latency'), 'download' => Arr::get($output, 'download.bandwidth'), 'upload' => Arr::get($output, 'upload.bandwidth'), diff --git a/database/settings/2024_09_11_094357_rename_influxdb_settings.php.php b/database/settings/2024_09_11_094357_rename_influxdb_settings.php.php new file mode 100644 index 000000000..3bcca09c1 --- /dev/null +++ b/database/settings/2024_09_11_094357_rename_influxdb_settings.php.php @@ -0,0 +1,16 @@ +migrator->rename('influxdb.v2_enabled', 'dataintegration.influxdb_v2_enabled'); + $this->migrator->rename('influxdb.v2_url', 'dataintegration.influxdb_v2_url'); + $this->migrator->rename('influxdb.v2_org', 'dataintegration.influxdb_v2_org'); + $this->migrator->rename('influxdb.v2_bucket', 'dataintegration.influxdb_v2_bucket'); + $this->migrator->rename('influxdb.v2_token', 'dataintegration.influxdb_v2_token'); + $this->migrator->rename('influxdb.v2_verify_ssl', 'dataintegration.influxdb_v2_verify_ssl'); + } +}