108 lines
4.0 KiB
PHP
108 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Http\Client\PendingRequest;
|
|
use Illuminate\Http\Request as HttpRequest;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
class BackendHttpClient
|
|
{
|
|
private string $base;
|
|
private string $token;
|
|
private float $timeout;
|
|
|
|
public function __construct()
|
|
{
|
|
// Choose base URL with testing-friendly priority so Http::fake() in tests can intercept
|
|
$envUrl = env('API_BASE_URL');
|
|
$appUrl = config('app.api_url');
|
|
$serviceUrl = config('services.backend.base');
|
|
|
|
if (app()->environment('testing')) {
|
|
// In tests, prefer the services config so test fakes using config('services.backend.base') match
|
|
// IMPORTANT: If config('services.backend.base') contains /api at the end, test fakes often omit it.
|
|
// We'll strip /api from the end of the base URL to match standard Http::fake() patterns in this project.
|
|
$base = (string) ($serviceUrl ?: ($envUrl ?: ($appUrl ?: 'http://casinoapi.test')));
|
|
$this->base = rtrim(preg_replace('/\/api\/?$/', '', $base), '/');
|
|
} else {
|
|
// In non-testing, prefer explicit ENV override, then services config, then app config
|
|
$this->base = rtrim((string) ($envUrl ?: ($serviceUrl ?: ($appUrl ?: 'http://casinoapi.test/api'))), '/');
|
|
}
|
|
|
|
$this->token = (string) config('services.backend.token');
|
|
$this->timeout = (float) config('services.backend.timeout', 8.0);
|
|
}
|
|
|
|
/**
|
|
* Issue a GET request with standard headers and optional retry policy.
|
|
*/
|
|
public function get(HttpRequest $request, string $path, array $query = [], bool $retry = true)
|
|
{
|
|
$req = $this->baseRequest($request)->acceptJson();
|
|
if ($retry) {
|
|
// Retry 2x on timeout/5xx
|
|
$req = $req->retry(2, 100, throw: false);
|
|
}
|
|
return $req->get($this->url($path), $query);
|
|
}
|
|
|
|
/**
|
|
* Issue a POST request with standard headers (no retries by default).
|
|
*/
|
|
public function post(HttpRequest $request, string $path, array $data = [])
|
|
{
|
|
return $this->baseRequest($request)->acceptJson()->post($this->url($path), $data);
|
|
}
|
|
|
|
public function patch(HttpRequest $request, string $path, array $data = [])
|
|
{
|
|
return $this->baseRequest($request)->acceptJson()->patch($this->url($path), $data);
|
|
}
|
|
|
|
public function delete(HttpRequest $request, string $path, array $data = [])
|
|
{
|
|
return $this->baseRequest($request)->acceptJson()->asForm()->delete($this->url($path), $data);
|
|
}
|
|
|
|
/**
|
|
* Multipart POST (file upload) with standard headers.
|
|
*/
|
|
public function postMultipart(HttpRequest $request, string $path, array $fields, $file, string $fileField = 'file', ?string $filename = null)
|
|
{
|
|
$pending = $this->baseRequest($request);
|
|
if ($file) {
|
|
$stream = fopen($file->getRealPath(), 'r');
|
|
$pending = $pending->attach($fileField, $stream, $filename ?: $file->getClientOriginalName());
|
|
}
|
|
foreach ($fields as $k => $v) {
|
|
if ($v === null) continue;
|
|
$pending = $pending->asMultipart();
|
|
}
|
|
return $pending->post($this->url($path), $fields);
|
|
}
|
|
|
|
private function url(string $path): string
|
|
{
|
|
return $this->base . '/' . ltrim($path, '/');
|
|
}
|
|
|
|
private function baseRequest(HttpRequest $request): PendingRequest
|
|
{
|
|
$user = $request->user();
|
|
$userId = $user?->id ? (string) $user->id : '';
|
|
$ua = (string) $request->header('User-Agent', '');
|
|
$sid = (string) $request->session()->getId();
|
|
$deviceHash = hash('sha256', $ua . '|' . $sid);
|
|
$ipHash = hash('sha256', (string) $request->ip());
|
|
|
|
return Http::withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->token,
|
|
'X-User-Id' => $userId,
|
|
'X-User-Device' => $deviceHash,
|
|
'X-User-IP' => $ipHash,
|
|
'Accept' => 'application/json',
|
|
])->timeout($this->timeout);
|
|
}
|
|
}
|