| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- <?php
- namespace App\Game\Services;
- use App\Game\GlobalUserInfo;
- use App\Http\helper\NumConfig;
- use App\Models\AccountsInfo;
- use App\Notification\TelegramBot;
- use App\Util;
- use GuzzleHttp\Client;
- use GuzzleHttp\Exception\RequestException;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Redis;
- class EvoplayService
- {
- protected $client;
- protected $currency;
- protected $apiUrl;
- protected $projectId;
- protected $secretKey;
- protected $version;
- protected $systemId;
- public function __construct()
- {
- $this->client = new Client();
- $this->currency = env('CONFIG_24680_CURRENCY');
- $this->apiUrl = env('EVOPLAY_API_URL', 'https://api.evoplay.games');
- $this->projectId = env('EVOPLAY_PROJECT_ID', '11800');
- $this->secretKey = env('EVOPLAY_SECRET_KEY', '68e071e88a198e25d847c30d0724eb2c');
- $this->version = env('EVOPLAY_API_VERSION', '1');
- $this->systemId = env('EVOPLAY_SYSTEM_ID', '24680-com-test');
- }
- /**
- * 调用子API
- *
- * @param string $username
- * @param \Illuminate\Http\Request $request
- * @return \Illuminate\Http\JsonResponse
- */
- public function callSubApi($username, $request)
- {
- Util::WriteLog('evoplay', 'callsubapi');
- $apiurl = ServerService::GetApiByGUID($username);
- try {
- $postData = $request->post();
- $response = $this->client->post($apiurl . $_SERVER['REQUEST_URI'], [
- 'verify' => false,
- 'form_params' => $postData,
- ]);
- $res = json_decode($response->getBody(), true);
- Util::WriteLog('evoplay', $res);
- return $res;
- } catch (RequestException $e) {
- return $this->handleRequestException($e);
- }
- }
- /**
- * 处理请求异常
- *
- * @param \Exception $e
- * @return array
- */
- private function handleRequestException(\Exception $e)
- {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'INTERNAL_ERROR',
- 'message' => 'Internal server error'
- ]
- ];
- }
- /**
- * 生成签名
- *
- * @param array $data 请求数据
- * @return string 签名
- */
- public function generateSignature($data)
- {
- // 按字母顺序排序参数
- ksort($data);
- // 将参数转换为查询字符串
- $query = http_build_query($data);
- // 生成签名
- return hash_hmac('sha256', $query, $this->secretKey);
- }
- /**
- * 获取游戏列表
- *
- * @return array
- */
- public function getGamesList()
- {
- try {
- $data = [
- 'project' => $this->projectId,
- 'version' => $this->version,
- 'need_extra_data' => 1,
- ];
- // 生成签名
- $data['signature'] = $this->generateSignature($data);
- // 调用游戏列表API
- $response = $this->client->post($this->apiUrl . '/Game/getList', [
- 'verify' => false,
- 'form_params' => $data
- ]);
- return json_decode($response->getBody(), true);
- } catch (\Exception $e) {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return ['error' => $e->getMessage()];
- }
- }
- /**
- * 获取游戏启动URL
- *
- * @param string $gameId 游戏ID
- * @param string $userId 用户ID
- * @param string $language 语言
- * @param string $currency 货币
- * @param bool $demo 是否为试玩模式
- * @return string|null
- */
- public function getGameUrl($gameId, $userId, $language = 'en', $currency = null, $demo = false)
- {
- try {
- if (!$currency) {
- $currency = $this->currency;
- }
- $data = [
- 'project_id' => $this->projectId,
- 'version' => $this->version,
- 'system_id' => $this->systemId,
- 'user_id' => $userId,
- 'game_id' => $gameId,
- 'currency' => $currency,
- 'language' => $language,
- 'denomination' => 1,
- 'return_url' => url('/'),
- 'callback_url' => url('/api/callback/evoplay'),
- 'callback_version' => 2,
- 'signature' => ''
- ];
- if ($demo) {
- $data['demo'] = 1;
- }
- // 生成签名
- $data['signature'] = $this->generateSignature($data);
- // 调用游戏启动API
- $response = $this->client->post($this->apiUrl . '/game/geturl', [
- 'verify' => false,
- 'form_params' => $data
- ]);
- $result = json_decode($response->getBody(), true);
- if (isset($result['status']) && $result['status'] === 'ok' && isset($result['url'])) {
- return $result['url'];
- }
- Util::WriteLog('evoplay_error', 'Failed to get game URL: ' . json_encode($result));
- return null;
- } catch (\Exception $e) {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return null;
- }
- }
- /**
- * 玩家验证
- *
- * @param string $userId 用户ID
- * @return array 用户信息
- */
- public function validateUser($userId)
- {
- try {
- // 获取用户信息
- $user = GlobalUserInfo::getGameUserInfo('GlobalUID', $userId);
- if (!$user) {
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'USER_NOT_FOUND',
- 'message' => 'User not found'
- ]
- ];
- }
- // 获取用户余额
- $balance = GlobalUserInfo::getScoreByUserID($user->UserID);
- return [
- 'status' => 'ok',
- 'data' => [
- 'id' => $userId,
- 'name' => $user->NickName,
- 'balance' => $balance,
- 'currency' => $this->currency
- ]
- ];
- } catch (\Exception $e) {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'INTERNAL_ERROR',
- 'message' => 'Internal server error'
- ]
- ];
- }
- }
- /**
- * 处理余额查询
- *
- * @param string $userId 用户ID
- * @return array 余额信息
- */
- public function getBalance($userId)
- {
- try {
- // 获取用户信息
- $user = GlobalUserInfo::getGameUserInfo('GlobalUID', $userId);
- if (!$user) {
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'USER_NOT_FOUND',
- 'message' => 'User not found'
- ]
- ];
- }
- // 获取用户余额
- $balance = GlobalUserInfo::getScoreByUserID($user->UserID);
- return [
- 'status' => 'ok',
- 'data' => [
- 'balance' => $balance,
- 'currency' => $this->currency
- ]
- ];
- } catch (\Exception $e) {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'INTERNAL_ERROR',
- 'message' => 'Internal server error'
- ]
- ];
- }
- }
- /**
- * 处理下注请求
- *
- * @param string $userId 用户ID
- * @param string $gameId 游戏ID
- * @param float $amount 金额
- * @param string $transactionId 交易ID
- * @param string $roundId 回合ID
- * @return array 处理结果
- */
- public function bet($userId, $gameId, $amount, $transactionId, $roundId)
- {
- try {
- // 获取用户信息
- $user = GlobalUserInfo::getGameUserInfo('GlobalUID', $userId);
- if (!$user) {
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'USER_NOT_FOUND',
- 'message' => 'User not found'
- ]
- ];
- }
- $userId = $user->UserID;
- // 检查交易是否已处理
- $transactionKey = 'evoplay_tx_' . $transactionId;
- if (Redis::exists($transactionKey)) {
- // 交易已处理,返回上次的结果
- $previousResult = json_decode(Redis::get($transactionKey), true);
- return $previousResult;
- }
- // 获取当前余额
- $currentBalance = GlobalUserInfo::getScoreByUserID($userId) * NumConfig::NUM_VALUE;
- $amountInCents = intval($amount * NumConfig::NUM_VALUE);
- // 检查余额是否足够
- if ($currentBalance < $amountInCents) {
- $errorResponse = [
- 'status' => 'error',
- 'error' => [
- 'code' => 'INSUFFICIENT_FUNDS',
- 'message' => 'Insufficient funds'
- ]
- ];
- return $errorResponse;
- }
- // 获取独占锁确保事务安全
- $res = SetNXLock::getExclusiveLock('evoplay_bet_' . $transactionId, 86400);
- if (!$res) {
- // 已经处理过,返回之前的结果
- return $this->getBalance($userId);
- }
- // 扣除余额
- DB::connection('write')->table('QPTreasureDB.dbo.GameScoreInfo')
- ->where('UserID', $userId)
- ->decrement('Score', $amountInCents);
- // 记录下注
- PlatformService::platformBet('evoplay', $gameId, $amountInCents, $userId);
- // 保存交易数据用于可能的取消
- Redis::set('evoplay_bet_' . $transactionId, $gameId . '_' . $amountInCents . '_' . $roundId);
- Redis::expire('evoplay_bet_' . $transactionId, 86400);
- // 更新当前余额
- $currentBalance -= $amountInCents;
- // 构造成功响应
- $response = [
- 'status' => 'ok',
- 'data' => [
- 'balance' => $currentBalance / NumConfig::NUM_VALUE,
- 'currency' => $this->currency,
- 'transaction_id' => $transactionId
- ]
- ];
- // 缓存交易结果
- Redis::set($transactionKey, json_encode($response));
- Redis::expire($transactionKey, 86400);
- return $response;
- } catch (\Exception $e) {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'INTERNAL_ERROR',
- 'message' => 'Internal server error'
- ]
- ];
- }
- }
- /**
- * 处理赢钱请求
- *
- * @param string $userId 用户ID
- * @param string $gameId 游戏ID
- * @param float $amount 金额
- * @param string $transactionId 交易ID
- * @param string $roundId 回合ID
- * @param string $betTransactionId 下注交易ID
- * @return array 处理结果
- */
- public function win($userId, $gameId, $amount, $transactionId, $roundId, $betTransactionId = null)
- {
- try {
- // 获取用户信息
- $user = GlobalUserInfo::getGameUserInfo('GlobalUID', $userId);
- if (!$user) {
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'USER_NOT_FOUND',
- 'message' => 'User not found'
- ]
- ];
- }
- $userId = $user->UserID;
- // 检查交易是否已处理
- $transactionKey = 'evoplay_tx_' . $transactionId;
- if (Redis::exists($transactionKey)) {
- // 交易已处理,返回上次的结果
- $previousResult = json_decode(Redis::get($transactionKey), true);
- return $previousResult;
- }
- // 获取当前余额
- $currentBalance = GlobalUserInfo::getScoreByUserID($userId) * NumConfig::NUM_VALUE;
- $amountInCents = intval($amount * NumConfig::NUM_VALUE);
- // 获取独占锁确保事务安全
- $res = SetNXLock::getExclusiveLock('evoplay_win_' . $transactionId, 86400);
- if (!$res) {
- // 已经处理过,返回之前的结果
- return $this->getBalance($userId);
- }
- // 检查投注记录
- $originalBet = 0;
- if ($betTransactionId) {
- $betKey = 'evoplay_bet_' . $betTransactionId;
- if (Redis::exists($betKey)) {
- $betInfo = Redis::get($betKey);
- $parts = explode('_', $betInfo);
- $originalBet = isset($parts[1]) ? intval($parts[1]) : 0;
- }
- }
- // 增加余额
- DB::connection('write')->table('QPTreasureDB.dbo.GameScoreInfo')
- ->where('UserID', $userId)
- ->increment('Score', $amountInCents);
- // 记录赢取
- PlatformService::platformWin(
- $userId,
- 'evoplay',
- $gameId,
- $amountInCents,
- $originalBet,
- $currentBalance + $amountInCents
- );
- // 更新当前余额
- $currentBalance += $amountInCents;
- // 构造成功响应
- $response = [
- 'status' => 'ok',
- 'data' => [
- 'balance' => $currentBalance / NumConfig::NUM_VALUE,
- 'currency' => $this->currency,
- 'transaction_id' => $transactionId
- ]
- ];
- // 缓存交易结果
- Redis::set($transactionKey, json_encode($response));
- Redis::expire($transactionKey, 86400);
- return $response;
- } catch (\Exception $e) {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'INTERNAL_ERROR',
- 'message' => 'Internal server error'
- ]
- ];
- }
- }
- /**
- * 处理交易回滚请求
- *
- * @param string $userId 用户ID
- * @param string $transactionId 要回滚的交易ID
- * @param string $rollbackTransactionId 回滚交易ID
- * @return array 处理结果
- */
- public function rollback($userId, $transactionId, $rollbackTransactionId)
- {
- try {
- // 获取用户信息
- $user = GlobalUserInfo::getGameUserInfo('GlobalUID', $userId);
- if (!$user) {
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'USER_NOT_FOUND',
- 'message' => 'User not found'
- ]
- ];
- }
- $userId = $user->UserID;
- // 检查回滚交易是否已处理
- $rollbackKey = 'evoplay_rollback_' . $rollbackTransactionId;
- if (Redis::exists($rollbackKey)) {
- // 回滚已处理,返回上次的结果
- $previousResult = json_decode(Redis::get($rollbackKey), true);
- return $previousResult;
- }
- // 检查原始交易
- $transactionKey = 'evoplay_tx_' . $transactionId;
- if (!Redis::exists($transactionKey)) {
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'TRANSACTION_NOT_FOUND',
- 'message' => 'Original transaction not found'
- ]
- ];
- }
- // 获取原始交易信息
- $originalTransaction = json_decode(Redis::get($transactionKey), true);
- // 检查是否是投注交易
- $betKey = 'evoplay_bet_' . $transactionId;
- if (Redis::exists($betKey)) {
- $betInfo = Redis::get($betKey);
- $parts = explode('_', $betInfo);
- $gameId = $parts[0] ?? '';
- $amount = isset($parts[1]) ? intval($parts[1]) : 0;
- // 获取独占锁确保事务安全
- $res = SetNXLock::getExclusiveLock($rollbackKey, 86400);
- if (!$res) {
- // 已经处理过,返回之前的结果
- return $this->getBalance($userId);
- }
- // 获取当前余额
- $currentBalance = GlobalUserInfo::getScoreByUserID($userId) * NumConfig::NUM_VALUE;
- // 退还金额
- DB::connection('write')->table('QPTreasureDB.dbo.GameScoreInfo')
- ->where('UserID', $userId)
- ->increment('Score', $amount);
- // 记录取消交易
- PlatformService::platformBet('evoplay', $gameId, -$amount, $userId);
- // 更新当前余额
- $currentBalance += $amount;
- // 构造成功响应
- $response = [
- 'status' => 'ok',
- 'data' => [
- 'balance' => $currentBalance / NumConfig::NUM_VALUE,
- 'currency' => $this->currency,
- 'transaction_id' => $rollbackTransactionId
- ]
- ];
- // 缓存回滚结果
- Redis::set($rollbackKey, json_encode($response));
- Redis::expire($rollbackKey, 86400);
- return $response;
- } else {
- // 如果不是投注交易,则可能是赢钱交易,处理方式类似
- // 这里简化处理,实际应该根据Evoplay的具体要求实现
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'UNSUPPORTED_OPERATION',
- 'message' => 'Only bet transactions can be rolled back'
- ]
- ];
- }
- } catch (\Exception $e) {
- Util::WriteLog('evoplay_error', $e->getMessage());
- return [
- 'status' => 'error',
- 'error' => [
- 'code' => 'INTERNAL_ERROR',
- 'message' => 'Internal server error'
- ]
- ];
- }
- }
- }
|