151 lines
4.5 KiB
PHP
151 lines
4.5 KiB
PHP
<?php
|
||
|
||
namespace App\Services\Wallet;
|
||
|
||
use App\Models\Player;
|
||
use Illuminate\Support\Facades\Http;
|
||
use GuzzleHttp\Exception\ConnectException;
|
||
|
||
/**
|
||
* 通过 HTTP 调用主站钱包 API(路径见 config lottery.main_site.wallet_*_path)。
|
||
*/
|
||
final class HttpMainSiteWalletGateway implements MainSiteWalletGateway
|
||
{
|
||
public function debitMainForLotteryDeposit(
|
||
Player $player,
|
||
string $currencyCode,
|
||
int $amountMinor,
|
||
string $idempotentKey,
|
||
): MainSiteWalletResult {
|
||
return $this->post(
|
||
(string) config('lottery.main_site.wallet_debit_path'),
|
||
$player,
|
||
$currencyCode,
|
||
$amountMinor,
|
||
$idempotentKey,
|
||
);
|
||
}
|
||
|
||
public function creditMainForLotteryWithdraw(
|
||
Player $player,
|
||
string $currencyCode,
|
||
int $amountMinor,
|
||
string $idempotentKey,
|
||
): MainSiteWalletResult {
|
||
return $this->post(
|
||
(string) config('lottery.main_site.wallet_credit_path'),
|
||
$player,
|
||
$currencyCode,
|
||
$amountMinor,
|
||
$idempotentKey,
|
||
);
|
||
}
|
||
|
||
private function post(
|
||
string $path,
|
||
Player $player,
|
||
string $currencyCode,
|
||
int $amountMinor,
|
||
string $idempotentKey,
|
||
): MainSiteWalletResult {
|
||
$base = rtrim((string) config('lottery.main_site.wallet_api_url'), '/');
|
||
$url = $base.'/'.ltrim($path, '/');
|
||
$timeout = (int) config('lottery.main_site.wallet_timeout', 10);
|
||
$apiKey = config('lottery.main_site.wallet_api_key');
|
||
|
||
$requestBody = [
|
||
'site_code' => $player->site_code,
|
||
'site_player_id' => $player->site_player_id,
|
||
'player_id' => $player->id,
|
||
'currency_code' => $currencyCode,
|
||
'amount_minor' => $amountMinor,
|
||
'idempotent_key' => $idempotentKey,
|
||
];
|
||
|
||
$requestSnapshot = array_merge($requestBody, [
|
||
'_meta' => [
|
||
'method' => 'POST',
|
||
'path' => '/'.ltrim($path, '/'),
|
||
],
|
||
]);
|
||
|
||
$headers = [];
|
||
if (is_string($apiKey) && $apiKey !== '') {
|
||
$headers['Authorization'] = 'Bearer '.$apiKey;
|
||
}
|
||
|
||
try {
|
||
$response = Http::withHeaders($headers)
|
||
->timeout($timeout)
|
||
->acceptJson()
|
||
->asJson()
|
||
->post($url, $requestBody);
|
||
} catch (\Throwable $e) {
|
||
return MainSiteWalletResult::failure(
|
||
$e->getMessage(),
|
||
null,
|
||
self::isUncertainTransportFailure($e),
|
||
$requestSnapshot,
|
||
);
|
||
}
|
||
|
||
$payload = $response->json();
|
||
if (! is_array($payload)) {
|
||
$payload = ['raw' => $response->body()];
|
||
}
|
||
|
||
$status = $response->status();
|
||
if ($status === 408 || $status === 504) {
|
||
return MainSiteWalletResult::failure(
|
||
'HTTP '.$status,
|
||
$payload,
|
||
true,
|
||
$requestSnapshot,
|
||
);
|
||
}
|
||
|
||
if (! $response->successful()) {
|
||
return MainSiteWalletResult::failure(
|
||
is_string(data_get($payload, 'message'))
|
||
? (string) data_get($payload, 'message')
|
||
: ('HTTP '.$status),
|
||
$payload,
|
||
false,
|
||
$requestSnapshot,
|
||
);
|
||
}
|
||
|
||
$ok = (bool) data_get($payload, 'success', true);
|
||
if (! $ok) {
|
||
return MainSiteWalletResult::failure(
|
||
is_string(data_get($payload, 'message'))
|
||
? (string) data_get($payload, 'message')
|
||
: 'main_site_rejected',
|
||
$payload,
|
||
false,
|
||
$requestSnapshot,
|
||
);
|
||
}
|
||
|
||
$ref = data_get($payload, 'external_ref_no')
|
||
?? data_get($payload, 'data.external_ref_no')
|
||
?? data_get($payload, 'ref');
|
||
|
||
return MainSiteWalletResult::success(is_string($ref) ? $ref : null, $payload, $requestSnapshot);
|
||
}
|
||
|
||
private static function isUncertainTransportFailure(\Throwable $e): bool
|
||
{
|
||
if ($e instanceof ConnectException) {
|
||
return true;
|
||
}
|
||
|
||
$msg = strtolower($e->getMessage());
|
||
|
||
return str_contains($msg, 'curl error 28')
|
||
|| str_contains($msg, 'connection timed out')
|
||
|| str_contains($msg, 'timed out')
|
||
|| str_contains($msg, 'operation timed out');
|
||
}
|
||
}
|