added assets into stream
This commit is contained in:
@@ -24,6 +24,7 @@ use App\Models\TransactionsAdmin;
|
|||||||
use App\Services\BalanceReportService;
|
use App\Services\BalanceReportService;
|
||||||
use App\Services\ConfigService;
|
use App\Services\ConfigService;
|
||||||
use App\Services\WalletBalanceService;
|
use App\Services\WalletBalanceService;
|
||||||
|
use App\Services\WalletBroadcastService;
|
||||||
use Hekmatinasser\Verta\Verta;
|
use Hekmatinasser\Verta\Verta;
|
||||||
|
|
||||||
|
|
||||||
@@ -154,6 +155,8 @@ class WalletController extends Controller
|
|||||||
. "\n"
|
. "\n"
|
||||||
. $this->Config('name_fa');
|
. $this->Config('name_fa');
|
||||||
$this->Send($customer->mobile, $message);
|
$this->Send($customer->mobile, $message);
|
||||||
|
$this->broadcastCustomerWalletAssets($customer);
|
||||||
|
|
||||||
return response()->json(true);
|
return response()->json(true);
|
||||||
}
|
}
|
||||||
public function charge_gold(Request $request)
|
public function charge_gold(Request $request)
|
||||||
@@ -224,6 +227,8 @@ class WalletController extends Controller
|
|||||||
. $data['note']
|
. $data['note']
|
||||||
. $this->Config('name_fa');
|
. $this->Config('name_fa');
|
||||||
$this->Send($customer->mobile, $message);
|
$this->Send($customer->mobile, $message);
|
||||||
|
$this->broadcastCustomerWalletAssets($customer);
|
||||||
|
|
||||||
return response()->json(true);
|
return response()->json(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +372,7 @@ class WalletController extends Controller
|
|||||||
. "\n"
|
. "\n"
|
||||||
. $this->Config('name_fa');
|
. $this->Config('name_fa');
|
||||||
$this->Send($customer->mobile, $message);
|
$this->Send($customer->mobile, $message);
|
||||||
|
$this->broadcastCustomerWalletAssets($customer);
|
||||||
|
|
||||||
return response()->json(true);
|
return response()->json(true);
|
||||||
}
|
}
|
||||||
@@ -467,6 +473,10 @@ class WalletController extends Controller
|
|||||||
$transaction->save();
|
$transaction->save();
|
||||||
$message = 'تراکنش با موفقیت بهروزرسانی شد.';
|
$message = 'تراکنش با موفقیت بهروزرسانی شد.';
|
||||||
|
|
||||||
|
$customer = Customer::find($transaction->customer_id);
|
||||||
|
if ($customer) {
|
||||||
|
$this->broadcastCustomerWalletAssets($customer);
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
@@ -660,4 +670,12 @@ class WalletController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function broadcastCustomerWalletAssets(Customer $customer): void
|
||||||
|
{
|
||||||
|
app(WalletBroadcastService::class)->broadcastForCustomer(
|
||||||
|
(int) $customer->id,
|
||||||
|
(int) $customer->type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ use App\Models\Setting;
|
|||||||
use App\Models\Cnt;
|
use App\Models\Cnt;
|
||||||
use App\Services\MontzarService;
|
use App\Services\MontzarService;
|
||||||
use App\Services\ConfigService;
|
use App\Services\ConfigService;
|
||||||
|
use App\Services\WalletBroadcastService;
|
||||||
|
|
||||||
|
|
||||||
class SingleOrderController extends Controller
|
class SingleOrderController extends Controller
|
||||||
@@ -221,6 +222,14 @@ class SingleOrderController extends Controller
|
|||||||
report($e);
|
report($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($customer) {
|
||||||
|
app(WalletBroadcastService::class)->broadcastForCustomer(
|
||||||
|
(int) $customer->id,
|
||||||
|
$ownerType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json([$response, $data]);
|
return response()->json([$response, $data]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers\Site;
|
namespace App\Http\Controllers\Site;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Services\AssetSummaryService;
|
||||||
use App\Services\LivePriceCacheService;
|
use App\Services\LivePriceCacheService;
|
||||||
use App\Services\PriceBroadcastService;
|
use App\Services\PriceBroadcastService;
|
||||||
use App\Services\PriceStreamService;
|
use App\Services\PriceStreamService;
|
||||||
@@ -19,7 +20,11 @@ class PriceStreamController extends Controller
|
|||||||
abort(404);
|
abort(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->stream(function () use ($service) {
|
$customer = auth('customer')->user();
|
||||||
|
$customerId = $customer ? (int) $customer->id : 0;
|
||||||
|
$customerOwnerType = $customer ? (int) $customer->type : 0;
|
||||||
|
|
||||||
|
return response()->stream(function () use ($service, $customerId, $customerOwnerType) {
|
||||||
@set_time_limit(0);
|
@set_time_limit(0);
|
||||||
|
|
||||||
if (function_exists('apache_setenv')) {
|
if (function_exists('apache_setenv')) {
|
||||||
@@ -50,6 +55,18 @@ class PriceStreamController extends Controller
|
|||||||
$send('list', $list);
|
$send('list', $list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$customerLastId = 0;
|
||||||
|
if ($customerId > 0) {
|
||||||
|
$assets = app(AssetSummaryService::class)->buildForCustomer(
|
||||||
|
$customerId,
|
||||||
|
$customerOwnerType > 0 ? $customerOwnerType : 2
|
||||||
|
);
|
||||||
|
if ($assets !== []) {
|
||||||
|
$send('assets', $assets);
|
||||||
|
}
|
||||||
|
$customerLastId = $service->currentCustomerSeq($customerId);
|
||||||
|
}
|
||||||
|
|
||||||
$lastId = $service->currentSeq();
|
$lastId = $service->currentSeq();
|
||||||
$heartbeatTicks = 0;
|
$heartbeatTicks = 0;
|
||||||
|
|
||||||
@@ -62,6 +79,13 @@ class PriceStreamController extends Controller
|
|||||||
$lastId = (int) $event['id'];
|
$lastId = (int) $event['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($customerId > 0) {
|
||||||
|
foreach ($service->consumeCustomerSince($customerId, $customerLastId) as $event) {
|
||||||
|
$send((string) $event['event'], $event['data']);
|
||||||
|
$customerLastId = (int) $event['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$heartbeatTicks++;
|
$heartbeatTicks++;
|
||||||
// هر ۵ ثانیه — LiteSpeed/پروکسی اتصال بیکار را نمیبندد
|
// هر ۵ ثانیه — LiteSpeed/پروکسی اتصال بیکار را نمیبندد
|
||||||
if ($heartbeatTicks >= 10) {
|
if ($heartbeatTicks >= 10) {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ class PriceStreamService
|
|||||||
{
|
{
|
||||||
private const INBOX_PREFIX = 'price_sse_inbox:';
|
private const INBOX_PREFIX = 'price_sse_inbox:';
|
||||||
|
|
||||||
|
private const CUSTOMER_INBOX_PREFIX = 'price_sse_inbox:customer:';
|
||||||
|
|
||||||
private const INBOX_TTL_SECONDS = 300;
|
private const INBOX_TTL_SECONDS = 300;
|
||||||
|
|
||||||
private const MAX_EVENTS = 50;
|
private const MAX_EVENTS = 50;
|
||||||
@@ -70,9 +72,16 @@ class PriceStreamService
|
|||||||
|
|
||||||
public function currentSeq(): int
|
public function currentSeq(): int
|
||||||
{
|
{
|
||||||
$inbox = Cache::get($this->inboxKey(), ['seq' => 0, 'events' => []]);
|
return $this->currentInboxSeq($this->inboxKey());
|
||||||
|
}
|
||||||
|
|
||||||
return (int) ($inbox['seq'] ?? 0);
|
public function currentCustomerSeq(int $customerId): int
|
||||||
|
{
|
||||||
|
if ($customerId <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->currentInboxSeq($this->customerInboxKey($customerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,13 +89,19 @@ class PriceStreamService
|
|||||||
*/
|
*/
|
||||||
public function consumeSince(int $afterId): array
|
public function consumeSince(int $afterId): array
|
||||||
{
|
{
|
||||||
$inbox = Cache::get($this->inboxKey(), ['seq' => 0, 'events' => []]);
|
return $this->consumeInboxSince($this->inboxKey(), $afterId);
|
||||||
$events = is_array($inbox['events'] ?? null) ? $inbox['events'] : [];
|
}
|
||||||
|
|
||||||
return array_values(array_filter(
|
/**
|
||||||
$events,
|
* @return array<int, array{id: int, event: string, data: mixed}>
|
||||||
static fn (array $event): bool => (int) ($event['id'] ?? 0) > $afterId
|
*/
|
||||||
));
|
public function consumeCustomerSince(int $customerId, int $afterId): array
|
||||||
|
{
|
||||||
|
if ($customerId <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->consumeInboxSince($this->customerInboxKey($customerId), $afterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,8 +113,57 @@ class PriceStreamService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = $this->inboxKey();
|
$this->publishToInbox($this->inboxKey(), $event, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed>|array<int, mixed> $data
|
||||||
|
*/
|
||||||
|
public function publishForCustomer(int $customerId, string $event, array $data): void
|
||||||
|
{
|
||||||
|
if (! $this->isEnabled() || $customerId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->publishToInbox($this->customerInboxKey($customerId), $event, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function inboxKey(): string
|
||||||
|
{
|
||||||
|
return self::INBOX_PREFIX.'global';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function customerInboxKey(int $customerId): string
|
||||||
|
{
|
||||||
|
return self::CUSTOMER_INBOX_PREFIX.$customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function currentInboxSeq(string $key): int
|
||||||
|
{
|
||||||
|
$inbox = Cache::get($key, ['seq' => 0, 'events' => []]);
|
||||||
|
|
||||||
|
return (int) ($inbox['seq'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, array{id: int, event: string, data: mixed}>
|
||||||
|
*/
|
||||||
|
private function consumeInboxSince(string $key, int $afterId): array
|
||||||
|
{
|
||||||
|
$inbox = Cache::get($key, ['seq' => 0, 'events' => []]);
|
||||||
|
$events = is_array($inbox['events'] ?? null) ? $inbox['events'] : [];
|
||||||
|
|
||||||
|
return array_values(array_filter(
|
||||||
|
$events,
|
||||||
|
static fn (array $event): bool => (int) ($event['id'] ?? 0) > $afterId
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed>|array<int, mixed> $data
|
||||||
|
*/
|
||||||
|
private function publishToInbox(string $key, string $event, array $data): void
|
||||||
|
{
|
||||||
Cache::lock($key.':lock', 5)->block(3, function () use ($key, $event, $data): void {
|
Cache::lock($key.':lock', 5)->block(3, function () use ($key, $event, $data): void {
|
||||||
$inbox = Cache::get($key, ['seq' => 0, 'events' => []]);
|
$inbox = Cache::get($key, ['seq' => 0, 'events' => []]);
|
||||||
$events = is_array($inbox['events'] ?? null) ? $inbox['events'] : [];
|
$events = is_array($inbox['events'] ?? null) ? $inbox['events'] : [];
|
||||||
@@ -126,11 +190,6 @@ class PriceStreamService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function inboxKey(): string
|
|
||||||
{
|
|
||||||
return self::INBOX_PREFIX.'global';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string, mixed>|array<int, mixed> $data
|
* @param array<string, mixed>|array<int, mixed> $data
|
||||||
*/
|
*/
|
||||||
@@ -148,6 +207,16 @@ class PriceStreamService
|
|||||||
return md5(json_encode(PriceBroadcastService::listIdentity($data), JSON_UNESCAPED_UNICODE));
|
return md5(json_encode(PriceBroadcastService::listIdentity($data), JSON_UNESCAPED_UNICODE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($event === 'assets') {
|
||||||
|
return md5(json_encode([
|
||||||
|
'cash_wallet' => (int) ($data['cash_wallet'] ?? 0),
|
||||||
|
'total_rial_value' => (int) ($data['total_rial_value'] ?? 0),
|
||||||
|
'assets_rial_value' => (int) ($data['assets_rial_value'] ?? 0),
|
||||||
|
'inventory' => md5(json_encode($data['inventory_cards'] ?? [], JSON_UNESCAPED_UNICODE)),
|
||||||
|
'metals' => md5(json_encode($data['metal_totals'] ?? [], JSON_UNESCAPED_UNICODE)),
|
||||||
|
], JSON_UNESCAPED_UNICODE));
|
||||||
|
}
|
||||||
|
|
||||||
return md5(json_encode($data, JSON_UNESCAPED_UNICODE));
|
return md5(json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Customer;
|
||||||
|
|
||||||
|
class WalletBroadcastService
|
||||||
|
{
|
||||||
|
public function broadcastForCustomer(int $customerId, ?int $ownerType = null): void
|
||||||
|
{
|
||||||
|
$stream = app(PriceStreamService::class);
|
||||||
|
if (! $stream->isEnabled() || $customerId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ownerType === null || $ownerType <= 0) {
|
||||||
|
$ownerType = (int) Customer::query()->whereKey($customerId)->value('type');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ownerType <= 0) {
|
||||||
|
$ownerType = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = app(AssetSummaryService::class)->buildForCustomer($customerId, $ownerType);
|
||||||
|
$stream->publishForCustomer($customerId, 'assets', $payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-1
@@ -30,7 +30,14 @@ use App\Http\Controllers\Admin\CategoryController;
|
|||||||
Route::get('/candle',[ReportController::class, 'candleChart']);
|
Route::get('/candle',[ReportController::class, 'candleChart']);
|
||||||
Route::get('/price/up',[ReportController::class, 'upDownPrice']);
|
Route::get('/price/up',[ReportController::class, 'upDownPrice']);
|
||||||
Route::match(['get', 'post'],'/price/last',[ReportController::class, 'lastPrice']);
|
Route::match(['get', 'post'],'/price/last',[ReportController::class, 'lastPrice']);
|
||||||
Route::get('/price/stream', [PriceStreamController::class, 'stream'])->withoutMiddleware(['throttle:api']);
|
|
||||||
|
$priceStreamRoute = Route::get('/price/stream', [PriceStreamController::class, 'stream'])
|
||||||
|
->withoutMiddleware(['throttle:api']);
|
||||||
|
|
||||||
|
if (! app(ConfigService::class)->isStore()) {
|
||||||
|
$priceStreamRoute->middleware('auth:customer');
|
||||||
|
}
|
||||||
|
|
||||||
Route::get('/price/updatePrise',[ReportController::class, 'updatePrise']);
|
Route::get('/price/updatePrise',[ReportController::class, 'updatePrise']);
|
||||||
Route::get('/const/key/{key}',[ConstController::class, 'showValue']);
|
Route::get('/const/key/{key}',[ConstController::class, 'showValue']);
|
||||||
Route::get('/check',[ReportController::class, 'check']);
|
Route::get('/check',[ReportController::class, 'check']);
|
||||||
|
|||||||
Reference in New Issue
Block a user