platform notify

This commit is contained in:
cano
2024-03-27 00:11:26 +08:00
parent 01e93acdd8
commit 4b47fe7250
21 changed files with 462 additions and 18 deletions

View File

@ -0,0 +1,90 @@
<?php
namespace App\Bean\Model\Wallet\Platform;
use App\Bean\Model\Base\BaseBean;
class WalletPlatformBean extends BaseBean
{
protected $id;
protected $name;
protected $code;
protected $appid;
protected $secret;
protected $notify_ip;
protected $created_at;
public function getId()
{
return $this->id;
}
public function setId($id): void
{
$this->id = $id;
}
public function getName()
{
return $this->name;
}
public function setName($name): void
{
$this->name = $name;
}
public function getCode()
{
return $this->code;
}
public function setCode($code): void
{
$this->code = $code;
}
public function getAppid()
{
return $this->appid;
}
public function setAppid($appid): void
{
$this->appid = $appid;
}
public function getSecret()
{
return $this->secret;
}
public function setSecret($secret): void
{
$this->secret = $secret;
}
public function getNotifyIp()
{
return $this->notify_ip;
}
public function setNotifyIp($notify_ip): void
{
$this->notify_ip = $notify_ip;
}
public function getCreatedAt()
{
return $this->created_at;
}
public function setCreatedAt($created_at): void
{
$this->created_at = $created_at;
}
}

View File

@ -5,7 +5,7 @@ use App\Bean\Model\Base\BaseBean;
class QueueBaseBean extends BaseBean
{
const TRY_LIMIT = 3;
protected $try_limt = 3;
protected $try_times = 0;
public function IncrTryTimes($num = 1): void
@ -15,11 +15,21 @@ class QueueBaseBean extends BaseBean
public function checkTryTimes(): bool
{
if($this->try_times >= self::TRY_LIMIT) {
if($this->try_times >= $this->try_limt) {
return false;
}
return true;
}
public function getTryTimes(): int
{
return $this->try_times;
}
function getDelaySeconds($seconds = 30): int
{
return $seconds * $this->try_times;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Bean\Service;
use App\Bean\Model\Base\BaseBean;
class HttpServiceConfigBean extends BaseBean
{
protected bool $is_return_json = true;
public function isIsReturnJson(): bool
{
return $this->is_return_json;
}
public function setIsReturnJson(bool $is_return_json): void
{
$this->is_return_json = $is_return_json;
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Bean\Service;
use App\Bean\Model\Base\BaseBean;
class HttpServiceReturnLogBean extends BaseBean
{
protected $request_url;
protected $request_data;
protected $request_header;
protected $response_body;
protected $response_status_code;
public function getResponseStatusCode()
{
return $this->response_status_code;
}
public function setResponseStatusCode($response_status_code): void
{
$this->response_status_code = $response_status_code;
}
public function getRequestUrl()
{
return $this->request_url;
}
public function setRequestUrl($request_url): void
{
$this->request_url = $request_url;
}
public function getRequestData()
{
return $this->request_data;
}
public function setRequestData($request_data): void
{
$this->request_data = $request_data;
}
public function getRequestHeader()
{
return $this->request_header;
}
public function setRequestHeader($request_header): void
{
$this->request_header = $request_header;
}
public function getResponseBody()
{
return $this->response_body;
}
public function setResponseBody($response_body): void
{
$this->response_body = $response_body;
}
}

View File

@ -39,6 +39,10 @@ abstract class BaseCache
{
return $this->getCacheData($key);
}
function del($key): bool
{
return $this->delCacheData($key);
}
function getCacheData($primary_key = null): array|string|null
{

View File

@ -0,0 +1,26 @@
<?php
namespace App\Cache\Table\Wallet;
use App\Cache\Base\TableBaseCache;
use App\Models\Wallet\Other\WalletSettingModel;
use App\Models\Wallet\Platform\WalletPlatformModel;
//用户缓存用户基础信息结构自己组装不完全等于数据表uid为主键
class TableWalletPlatformCache extends TableBaseCache
{
public string $table_class = WalletPlatformModel::class;
public string $primary_prefix = 'TableWalletPlatformCache:'; //后面跟name
public string $primary_key_column = 'id';
public array $get_columns = [
'id',
'name',
'code',
'appid',
'secret',
'notify_ip',
'created_at',
];
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Console\Commands;
namespace App\Console\Commands\Api;
use App\Models\Api\Customer\CustomerUserExtendModel;
use Illuminate\Console\Command;

View File

@ -1,6 +1,6 @@
<?php
namespace App\Console\Commands;
namespace App\Console\Commands\Api;
use App\Models\Api\Wallet\CustomerWalletBalanceTransactionModel;
use Illuminate\Console\Command;

View File

@ -0,0 +1,35 @@
<?php
namespace App\Console\Commands\Api;
use App\Service\Wallet\Coin\Tron\UsdtTrx20Service;
use Illuminate\Console\Command;
class SecondsWalletBlockCheckCmd extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:seconds-wallet-block-check-cmd';
/**
* The console command description.
*
* @var string
*/
protected $description = '每2秒检查最新链上区块';
/**
* Execute the console command.
*/
public function handle()
{
$this->info('每2秒检查最新链上区块');
$this->info('开始...');
$oUsdtTrx20Service = new UsdtTrx20Service();
$oUsdtTrx20Service->checkNowBlock();
$this->info('结束...');
}
}

View File

@ -15,6 +15,7 @@ class Kernel extends ConsoleKernel
// $schedule->command('inspire')->hourly();
$schedule->command('app:daily-check-user-active-status-cmd')->dailyAt('00:30')->onOneServer();
$schedule->command('app:hour-customer-wallet-trs-delay-pay-cmd')->hourly()->onOneServer();
$schedule->command('app:seconds-wallet-block-check-cmd')->everyTwoSeconds()->onOneServer();
}
/**

View File

@ -0,0 +1,8 @@
<?php
namespace App\Exceptions;
class PlatformNotifyException extends \Exception
{
}

View File

@ -35,8 +35,12 @@ class WalletBlockTransactionQueue implements ShouldQueue
}
}
public static function putToQueue(QueueWalletBlockTransactionBean $bean): \Illuminate\Foundation\Bus\PendingDispatch
public static function putToQueue(QueueWalletBlockTransactionBean $bean, $delaySec = null): \Illuminate\Foundation\Bus\PendingDispatch
{
return self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletBlockTransactionBean::QUEUE_NAME);
$queue = self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletBlockTransactionBean::QUEUE_NAME);
if(!empty($delaySec)){
$queue->delay(now()->addSeconds($delaySec));
}
return $queue;
}
}

View File

@ -3,6 +3,7 @@
namespace App\Jobs\Wallet;
use App\Bean\Queue\Wallet\QueueNotifyToPlatformBean;
use App\Service\Wallet\PlatformNotifyService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
@ -24,13 +25,18 @@ class WalletNotifyToPlatformQueue implements ShouldQueue
/**
* Execute the job.
*/
public function handle(): void
public function handle(array $params): void
{
//
$oPlatformNotifyService = new PlatformNotifyService();
$oPlatformNotifyService->notifyToPlatform(new QueueNotifyToPlatformBean($params));
}
public static function putToQueue(QueueNotifyToPlatformBean $bean): \Illuminate\Foundation\Bus\PendingDispatch
public static function putToQueue(QueueNotifyToPlatformBean $bean, $delaySec = null): \Illuminate\Foundation\Bus\PendingDispatch
{
return self::dispatch($bean->toArrayNotNull())->onQueue(QueueNotifyToPlatformBean::QUEUE_NAME);
$queue = self::dispatch($bean->toArrayNotNull())->onQueue(QueueNotifyToPlatformBean::QUEUE_NAME);
if(!empty($delaySec)){
$queue->delay(now()->addSeconds($delaySec));
}
return $queue;
}
}

View File

@ -47,8 +47,12 @@ class WalletPlatformTransactionQueue implements ShouldQueue
}
}
public static function putToQueue(QueueWalletPlatformTransactionBean $bean): \Illuminate\Foundation\Bus\PendingDispatch
public static function putToQueue(QueueWalletPlatformTransactionBean $bean, $delaySec = null): \Illuminate\Foundation\Bus\PendingDispatch
{
return self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletPlatformTransactionBean::QUEUE_NAME);
$queue = self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletPlatformTransactionBean::QUEUE_NAME);
if(!empty($delaySec)){
$queue->delay(now()->addSeconds($delaySec));
}
return $queue;
}
}

View File

@ -8,6 +8,13 @@ class BaseModel extends Model
{
public $timestamps = false;
const LOCK_TYPE_FOR_UPDATE = 1;
const LOCK_TYPE_FOR_SHARE = 2;
const LOCK_TYPE = [
self::LOCK_TYPE_FOR_UPDATE => '悲观锁',
self::LOCK_TYPE_FOR_SHARE => '乐观锁',
];
function checkColInFill($aItem)
{
foreach ($aItem as $key => $value) {
@ -64,6 +71,17 @@ class BaseModel extends Model
return $this->newQuery()->where($aWhere)->get($col);
}
function setLockByPrimaryKey($id,$lock_type = self::LOCK_TYPE_FOR_UPDATE): Model|\Illuminate\Database\Eloquent\Builder|null
{
$model = $this->newQuery()->where($this->primaryKey, $id);
if($lock_type == self::LOCK_TYPE_FOR_SHARE){
$model = $model->sharedLock();
}elseif ($lock_type == self::LOCK_TYPE_FOR_UPDATE){
$model = $model->lockForUpdate();
}
return $model->first();
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace App\Models\Wallet\Platform;
use App\Cache\Table\Wallet\TableWalletPlatformCache;
use App\Exceptions\ModelException;
use App\Models\Wallet\Base\WalletBaseModel;
use App\Tools\Times;
@ -49,10 +50,19 @@ class WalletPlatformModel extends WalletBaseModel
return $resModel;
}
//@@给平台下发用户信息
static function userTransactionNotifyToPlatform($user_transaction_id)
function updateItem($aItem,$col = null): bool|int
{
$res = parent::updateItem($aItem,$col); // TODO: Change the autogenerated stub
if($res && isset($aItem[$this->primaryKey])) {
$this->delTableCache($aItem[$this->primaryKey]);
}
return $res;
}
function delTableCache($key): bool
{
$oTableWalletPlatformCache = new TableWalletPlatformCache();
return $oTableWalletPlatformCache->del($key);
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace App\Service;
use App\Bean\Service\HttpServiceConfigBean;
use App\Bean\Service\HttpServiceReturnLogBean;
use App\Tools\Logs;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
class HttpService
{
protected Client $client;
const REQ_METHOD_GET = 'GET';
const REQ_METHOD_POST = 'POST';
public function __construct()
{
$this->client = new Client();
}
public function getClient(): Client
{
return $this->client;
}
public function get(string $endpoint, array $data = [], HttpServiceConfigBean $configBean = null)
{
if ($configBean === null) $configBean = new HttpServiceConfigBean();
$oHttpServiceReturnLogBean = $this->request(self::REQ_METHOD_GET, $endpoint, $data, $configBean);
if ($configBean->isIsReturnJson() === true) {
return json_decode($oHttpServiceReturnLogBean->getResponseBody(), false);
}
return $oHttpServiceReturnLogBean->getResponseBody();
}
public function post(string $endpoint, array $data = [], HttpServiceConfigBean $configBean = null)
{
if ($configBean === null) $configBean = new HttpServiceConfigBean();
$oHttpServiceReturnLogBean = $this->request(self::REQ_METHOD_POST, $endpoint, $data, $configBean);
if ($configBean->isIsReturnJson() === true) {
return json_decode($oHttpServiceReturnLogBean->getResponseBody(), false);
}
return $oHttpServiceReturnLogBean->getResponseBody();
}
/**
* @throws GuzzleException
*/
function request($req_method , string $endpoint, array $data = [], HttpServiceConfigBean $configBean = null): HttpServiceReturnLogBean|bool
{
try {
if(!in_array($req_method, [self::REQ_METHOD_GET, self::REQ_METHOD_POST])) {
throw new \Exception('request method not support');
}
if ($configBean === null) $configBean = new HttpServiceConfigBean();
$req_data = [];
if($req_method === self::REQ_METHOD_GET) {
$req_data = ['query' => $data];
}
if($req_method === self::REQ_METHOD_POST) {
$req_data = ['json' => $data];
}
$resp = $this->getClient()->request($req_method,$endpoint, $req_data);
$status_code = $resp->getStatusCode();
$body = $resp->getBody()->getContents();
$resp->getBody()->close();
//记录日志
$oHttpServiceReturnLogBean = new HttpServiceReturnLogBean();
$oHttpServiceReturnLogBean->setRequestData($data);
$oHttpServiceReturnLogBean->setRequestUrl($endpoint);
$oHttpServiceReturnLogBean->setResponseStatusCode($status_code);
$oHttpServiceReturnLogBean->setResponseBody($body);
Logs::InfoLog(__CLASS__ . '-' . __FUNCTION__, $oHttpServiceReturnLogBean->toArrayNotNull());
return $oHttpServiceReturnLogBean;
}catch (\Exception $e) {
Logs::ErrLog(__CLASS__ . '-' . __FUNCTION__, $e, func_get_args());
return false;
}
}
}

View File

@ -113,7 +113,7 @@ class UsdtTrx20Service
$oWalletTronBlockModel->updateItem($updateItem);
} catch (\Exception $e) {
Logs::ErrLog(__FUNCTION__, $e, $oQueueWalletBlockBean->toArray());
Logs::ErrLog(__FUNCTION__, $e, $oQueueWalletBlockBean->toArrayNotNull());
$oQueueWalletBlockBean->IncrTryTimes();
if (!$oQueueWalletBlockBean->checkTryTimes()) { //超出重试次数
$updateItem = [
@ -137,7 +137,7 @@ class UsdtTrx20Service
try {
$this->tronBlockTransaction($oEventBean);
} catch (\Exception $e) {
Logs::ErrLog(__FUNCTION__, $e, $oEventBean->toArray());
Logs::ErrLog(__FUNCTION__, $e, $oEventBean->toArrayNotNull());
}
}
}
@ -158,7 +158,7 @@ class UsdtTrx20Service
$is_to = $oTronWalletAddressSetCache->checkKey($to_addr);
if (!$is_from && !$is_to) return;
//投递到钱包地址账变处理队列
$oQueueEventBean = new QueueEventBean($oEventBean->toArray());
$oQueueEventBean = new QueueEventBean($oEventBean->toArrayNotNull());
WalletAddressTransactionQueue::putToQueue($oQueueEventBean);
return;
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Service\Wallet;
use App\Bean\Model\Wallet\Platform\WalletPlatformBean;
use App\Bean\Queue\Wallet\QueueNotifyToPlatformBean;
use App\Bean\Service\HttpServiceConfigBean;
use App\Cache\Table\Wallet\TableWalletPlatformCache;
use App\Exceptions\PlatformNotifyException;
use App\Jobs\Wallet\WalletNotifyToPlatformQueue;
use App\Tools\Logs;
class PlatformNotifyService
{
const RETURN_SUCCESS = 'success';
function notifyToPlatform(QueueNotifyToPlatformBean $bean): void
{
try {
if(empty($bean->getPlatformId())) return;
$oTableWalletPlatformCache = new TableWalletPlatformCache();
$aWalletPlatform= $oTableWalletPlatformCache->get($bean->getPlatformId());
if(empty($aWalletPlatform)) return;
$oWalletPlatformBean = new WalletPlatformBean($aWalletPlatform);
if(empty($oWalletPlatformBean->getNotifyIp())) return;
//通知到平台
$oHttpService = new \App\Service\HttpService();
$HttpServiceConfigBean = new HttpServiceConfigBean();
$HttpServiceConfigBean->setIsReturnJson(false); //返回不格式化json
$res = $oHttpService->post($oWalletPlatformBean->getNotifyIp(),$bean->toArrayNotNull(),$HttpServiceConfigBean);
if($res !== self::RETURN_SUCCESS){ //通知失败
throw new PlatformNotifyException('notify to platform failed');
}
Logs::SuccLog(__FUNCTION__, $bean->toArrayNotNull());
}catch (\Exception $e) {
Logs::ErrLog(__FUNCTION__, $e, $bean->toArrayNotNull());
$bean->IncrTryTimes();
if (!$bean->checkTryTimes()) { //超出重试次数
return;
}
WalletNotifyToPlatformQueue::putToQueue($bean, $bean->getTryTimes());
}
}
}

View File

@ -16,6 +16,11 @@ class Logs
Log::error(self::getTitle($title,'success:'), $params);
}
static function InfoLog($title, $params = []): void
{
Log::error(self::getTitle($title,'info:'), $params);
}
static function getTitle($title,$prefix=''): string
{
return $title.' '.$prefix;