Files
lotteryLaravel/app/Services/Wallet/HttpMainSiteWalletGateway.php
kang a10135d6ee feat: 增强玩家管理功能,集成接入站点权限控制
在多个玩家相关控制器中引入 AdminSiteScope,确保管理员在执行操作前具备相应的接入站点权限。更新 Player 相关请求以支持 site_code 参数,增强权限验证逻辑,确保系统安全性与灵活性。同时,新增 AdminUser 模型方法以获取可访问的站点 ID 列表,优化权限管理。
2026-05-27 13:36:23 +08:00

175 lines
5.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Services\Wallet;
use App\Models\Player;
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Exception\ConnectException;
use App\Services\Integration\PartnerSiteConfigResolver;
/**
* 通过 HTTP 调用主站钱包 API路径见 config lottery.main_site.wallet_*_path
*/
final class HttpMainSiteWalletGateway implements MainSiteWalletGateway
{
public function __construct(
private readonly PartnerSiteConfigResolver $partnerSiteConfigResolver,
) {}
public function debitMainForLotteryDeposit(
Player $player,
string $currencyCode,
int $amountMinor,
string $idempotentKey,
): MainSiteWalletResult {
$config = $this->partnerSiteConfigResolver->resolveForPlayer($player);
return $this->post(
$config->walletDebitPath,
$player,
$currencyCode,
$amountMinor,
$idempotentKey,
$config,
);
}
public function creditMainForLotteryWithdraw(
Player $player,
string $currencyCode,
int $amountMinor,
string $idempotentKey,
): MainSiteWalletResult {
$config = $this->partnerSiteConfigResolver->resolveForPlayer($player);
return $this->post(
$config->walletCreditPath,
$player,
$currencyCode,
$amountMinor,
$idempotentKey,
$config,
);
}
private function post(
string $path,
Player $player,
string $currencyCode,
int $amountMinor,
string $idempotentKey,
\App\Services\Integration\PartnerSiteConfig $config,
): MainSiteWalletResult {
if (! $config->hasWalletApi()) {
return MainSiteWalletResult::success(null, ['stub' => true, 'reason' => 'wallet_api_not_configured'], [
'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,
'_meta' => ['stub' => true],
]);
}
$base = rtrim((string) $config->walletApiUrl, '/');
$url = $base.'/'.ltrim($path, '/');
$timeout = $config->walletTimeoutSeconds;
$apiKey = $config->walletApiKey;
$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');
}
}