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' ] ]; } } }