[Feature] Stats API endpoint (#1994)

This commit is contained in:
Alex Justesen
2025-01-15 21:43:40 -05:00
committed by GitHub
parent e1efde65c7
commit 840e87fed0
5 changed files with 97 additions and 2 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ class Bitrate
}
// 1 byte = 8 bits
return $bytes * 8;
return round($bytes * 8);
}
/**
@@ -17,10 +17,11 @@ abstract class ApiController
* @param int $code
* @return \Illuminate\Http\JsonResponse
*/
public static function sendResponse($data, $message = 'ok', $code = 200)
public static function sendResponse($data, $filters = [], $message = 'ok', $code = 200)
{
$response = array_filter([
'data' => $data,
'filters' => $filters,
'message' => $message,
]);
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Resources\V1\StatResource;
use App\Models\Result;
use Illuminate\Http\Request;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\Enums\FilterOperator;
use Spatie\QueryBuilder\QueryBuilder;
class Stats extends ApiController
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request)
{
$stats = QueryBuilder::for(Result::class)
->selectRaw('count(*) as total_results')
->selectRaw('avg(ping) as avg_ping')
->selectRaw('avg(download) as avg_download')
->selectRaw('avg(upload) as avg_upload')
->selectRaw('min(ping) as min_ping')
->selectRaw('min(download) as min_download')
->selectRaw('min(upload) as min_upload')
->selectRaw('max(ping) as max_ping')
->selectRaw('max(download) as max_download')
->selectRaw('max(upload) as max_upload')
->AllowedFilters([
AllowedFilter::operator(name: 'start_at', internalName: 'created_at', filterOperator: FilterOperator::DYNAMIC),
AllowedFilter::operator(name: 'end_at', internalName: 'created_at', filterOperator: FilterOperator::DYNAMIC),
])
->first();
return self::sendResponse(
data: new StatResource($stats),
filters: $request->input('filter'),
);
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace App\Http\Resources\V1;
use App\Helpers\Bitrate;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class StatResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'ping' => [
'avg' => round($this->avg_ping, 2),
'min' => round($this->min_ping, 2),
'max' => round($this->max_ping, 2),
],
'download' => [
'avg' => round($this->avg_download),
'avg_bits' => $this->when($this->avg_download, fn (): int|float => Bitrate::bytesToBits($this->avg_download)),
'avg_bits_human' => $this->when($this->avg_download, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->avg_download)).'ps'),
'min' => round($this->min_download),
'min_bits' => $this->when($this->min_download, fn (): int|float => Bitrate::bytesToBits($this->min_download)),
'min_bits_human' => $this->when($this->min_download, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->min_download)).'ps'),
'max' => round($this->max_download),
'max_bits' => $this->when($this->max_download, fn (): int|float => Bitrate::bytesToBits($this->max_download)),
'max_bits_human' => $this->when($this->max_download, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->max_download)).'ps'),
],
'upload' => [
'avg' => round($this->avg_upload),
'avg_bits' => $this->when($this->avg_upload, fn (): int|float => Bitrate::bytesToBits($this->avg_upload)),
'avg_bits_human' => $this->when($this->avg_upload, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->avg_upload)).'ps'),
'min' => round($this->min_upload),
'min_bits' => $this->when($this->min_upload, fn (): int|float => Bitrate::bytesToBits($this->min_upload)),
'min_bits_human' => $this->when($this->min_upload, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->min_upload)).'ps'),
'max' => round($this->max_upload),
'max_bits' => $this->when($this->max_upload, fn (): int|float => Bitrate::bytesToBits($this->max_upload)),
'max_bits_human' => $this->when($this->max_upload, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->max_upload)).'ps'),
],
'total_results' => $this->total_results,
];
}
}
+4
View File
@@ -3,6 +3,7 @@
use App\Http\Controllers\Api\V1\LatestResult;
use App\Http\Controllers\Api\V1\ListResults;
use App\Http\Controllers\Api\V1\ShowResult;
use App\Http\Controllers\Api\V1\Stats;
use Illuminate\Support\Facades\Route;
Route::prefix('v1')->name('api.v1.')->group(function () {
@@ -14,4 +15,7 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
Route::get('/results/{result}', ShowResult::class)
->name('results.show');
Route::get('/stats', Stats::class)
->name('stats');
});