Files
Shahoo/docs/02-rango-websocket-plan.md
2026-08-13 20:26:04 +03:30

13 KiB
Raw Permalink Blame History

Rango WebSocket — جایگزینی Polling در Shahoo

تاریخ: 2026-07-19
آخرین به‌روزرسانی پیاده‌سازی: 2026-07-20
وابستگی: 01-dynamic-markets-remediation.md (فاز ۳+ توصیه می‌شود)
مرجع Gereh: Gereh/src/modules/public/ranger/
Infra: Rango 2.6.1 — quay.io/openware/rango:2.6.1

وضعیت کد (۲۰۲۶-۰۷-۲۰): WS-0 → WS-4 پیاده‌سازی شده؛ follow-up: thrashing/refcount، sequence resync، private reconnect، compose shahoo-ranger، setupProxy.
باقی ops: WS0.3/0.4 staging + Cloudflare، WS5.1/5.3 latency/load.
Public: RangerProvider + global.tickers / ob-inc / trades / kline-*.
Private: BFF GET /api/1/ranger/credentials + WS proxy /api/1/ranger/ws → Rango private با cookie session.
Fallback: REACT_APP_RANGER_ENABLED=false یا قطع WS → polling قبلی.


۱. خلاصه اجرایی

Shahoo امروز HTTP polling دارد؛ Gereh از Rango (Ranger) WebSocket استفاده می‌کند. هدف: latency کمتر در order book، tickers، trades و (در فاز بعد) balances/orders.

معیار Polling (فعلی) Rango WS (هدف)
Order book هر ۵s push فوری (ob-inc / update)
Tickers (stats) هر ۵s global.tickers
Recent trades هر ۱۰s {market}.trades
Chart realtime stub (CryptoCompare comment) {market}.kline-{period}
بار سرور N × clients × freq یک WS per client
Auth private order, trade, balances

توصیه: بعد از MarketsContext داینامیک (doc 01 فاز ۳) شروع شود — subscribe به streamها به marketId Peatio (مثلاً btcirt) وابسته است.


۲. وضعیت فعلی Shahoo (Polling Map)

فایل interval API جایگزین Rango
src/features/User/context/index.js 5s GET /api/1/ohlcvs/stats global.tickers
OrderBook/RecentTransactionsList/index.js 5s GET /api/1/orders/orderBook/... {id}.ob-inc یا {id}.update
hook/useGetOdrerBook/useGetOdrerBook.js 8s order book همان
MarketTable/RecentMarketTrades/index.js 10s trades {id}.trades
MarketRecentTransactions/index.js 10s trades {id}.trades
TVChartContainer/datafeeds/streaming.js stub (غیرفعال) {id}.kline-{period}

تنظیمات interval: src/core/utils/IntervalApiTime.js

export const orderBookTime = 5;
export const statsTime = 5;
export const recentMarketTime = 10;

۳. پروتکل Rango (OpenDAX)

۳.۱. URL اتصال

wss://{domain}/api/v2/ranger/public/?stream=global.tickers&stream=btcirt.trades&...
wss://{domain}/api/v2/ranger/private/?stream=order&stream=trade&...

الگوی Gereh (helpers.ts):

generateSocketURI(baseUrl, streams) =>
  `${baseUrl}/?stream=${streams.sort().join('&stream=')}`

۳.۲. کانال‌های public

Stream payload مصرف Shahoo
global.tickers { btcusdt: { last, open, high, low, volume, ... } } StatsContext / sidebar قیمت
{market}.trades { trades: [...] } Recent trades
{market}.update full order book snapshot Order book (legacy)
{market}.ob-snap snapshot incremental OB
{market}.ob-inc incremental + sequence Order book (preferred)
{market}.kline-{period} OHLCV bar TradingView streaming

period: 1h, 4h, 1d, … (مطابق Gereh periodsMapString)

۳.۳. کانال‌های private (JWT / session)

Stream مصرف
order open orders update
trade history push
balances wallet realtime (Finex)
deposit_address آدرس واریز

۳.۴. پیام subscribe/unsubscribe

{ "event": "subscribe", "streams": ["btcirt.trades"] }
{ "event": "unsubscribe", "streams": ["btcirt.trades"] }

پاسخ: { "success": { "message": "subscribed", "streams": [...] } }


۴. شکاف‌های اتصال Shahoo ↔ Rango

G1 — URL runtime ندارد 🔴

Shahoo public/config/env.js فقط app, captcha دارد — rangerUrl نیست.

راه‌حل: اضافه به window.env:

window.env.api = {
  rangerUrl: 'wss://shahoo.fibitex.com/api/v2/ranger',
};

Traefik روی shahoo.* باید /api/v2/ranger → Rango route داشته باشد (مثل Gereh روی www.*).

G2 — Auth model متفاوت 🔴

Gereh Shahoo
Cookie + Envoy JWT BFF opaque token + Barong cookies در server-side
WS private با session مرورگر مرورگر JWT Peatio ندارد

گزینه‌ها:

# رویکرد +
A Public WS مستقیم از browser؛ private همچنان polling/BFF سریع MVP orders/balances realtime نمی‌آید
B BFF: GET /api/1/ranger/credentials → Peatio JWT از gateway private channels endpoint + امنیت
C BFF WebSocket proxy مخفی JWT پیچیدگی ops

توصیه: A برای MVP (public market data) → B برای فاز ۲ (private).

G3 — نگاشت ticker 🔴

Rango: { "btcirt": { last, open, ... } } (market id lowercase)
Shahoo: statMap["BTC_IRT"] (uppercase key)

راه‌حل: mapper مشترک در src/lib/ranger/mapTickers.js (یا reuse BFF marketIdToShahooStatKeys logic در frontend).

G4 — Order book format 🟡

BFF فعلی: { sells: [{unitPrice, size}], buys: [...] }
Rango ob-inc: { asks, bids, sequence } — نیاز adapter مثل Gereh depthDataIncrement.

G5 — Incremental sequence 🟡

Gereh: اگر sequence break شود → disconnect + reconnect + REST prefetch.
Shahoo باید همان pattern را پیاده کند.

G6 — Cloudflare / Traefik 🟡

WebSocket روی staging/production:

  • Cloudflare: WebSocket proxy فعال
  • Traefik: Upgrade header pass-through
  • تست: wscat -c "wss://shahoo.fibitex.com/api/v2/ranger/public/?stream=global.tickers"

۵. معماری هدف

┌─────────────────────────────────────────────────────────┐
│ Shahoo SPA                                              │
│  RangerContext (singleton WS manager)                   │
│    ├─ public:  global.tickers + market streams          │
│    ├─ private: (فاز ۲) order, trade                    │
│    └─ mappers → StatsContext, OrderBook, Trades, Chart  │
└───────────────────────┬─────────────────────────────────┘
                        │ wss://shahoo.fibitex.com/api/v2/ranger
                        ▼
                   Traefik → Rango :8080
                        ▲
                   RabbitMQ ← Dena pushers

Fallback: اگر WS قطع شد → polling قبلی (feature flag REACT_APP_RANGER_ENABLED).


۶. فازبندی اجرایی

فاز WS-0 — زیرساخت (DevOps + config) 🔴

ID تسک repo وضعیت
WS0.1 rangerUrl در public/config/env.js + Alvand-P template shahoo.env.js.erb Shahoo + Alvand-P
WS0.2 Traefik route /api/v2/ranger روی host shahoo.* → rango Alvand-P
WS0.3 تست connectivity: global.tickers از staging QA
WS0.4 Cloudflare WebSocket برای shahoo.fibitex.com DevOps

فاز WS-1 — Core client (Shahoo) 🔴

ID تسک فایل(ها) وضعیت
WS1.1 src/lib/ranger/rangerClient.js — connect, reconnect, heartbeat جدید
WS1.2 generateSocketURI, subscribe/unsubscribe rangerClient.js
WS1.3 RangerContext + useRanger() src/context/rangerContext.js
WS1.4 Feature flag: REACT_APP_RANGER_ENABLED + fallback polling .env, hooks
WS1.5 mapRangerTickersToStatMap src/lib/ranger/mapTickers.js

مرجع پیاده‌سازی: Gereh/src/modules/public/ranger/sagas/rangerSaga.ts (بدون Redux — Context + useReducer).


فاز WS-2 — جایگزینی polling (public) 🔴

ID تسک جایگزین polling حذف‌شده وضعیت
WS2.1 Tickers → StatsContext global.tickers User/context stats loop
WS2.2 Order book {id}.ob-inc + REST prefetch RecentTransactionsList, useGetOdrerBook
WS2.3 Recent trades {id}.trades RecentMarketTrades, MarketRecentTransactions
WS2.4 Market switch → resubscribe rangerSubscribeMarket pattern
WS2.5 Landing tickers (public page) global.tickers Landing/pages getStats

WS2.4: هنگام تغییر route /market/BTC-IRT → unsubscribe ethirt.* → subscribe btcirt.*.


فاز WS-3 — Chart streaming 🟡

ID تسک فایل وضعیت
WS3.1 فعال‌سازی streaming.js با Rango kline datafeeds/streaming.js
WS3.2 subscribe {marketId}.kline-4h (match TV resolution) rangerClient + datafeed
WS3.3 unsubscribe on symbol change / unmount datafeed

فاز WS-4 — Private channels 🟡

ID تسک repo وضعیت
WS4.1 BFF: GET /api/1/ranger/credentials (+ alias /token) + private WS proxy Shahoo-BFF
WS4.2 اتصال private بعد از login (connectPrivate) Shahoo rangerContext
WS4.3 order stream → refresh open orders Market / Orders UI
WS4.4 trade stream → history refresh MarketYourTransaction
WS4.5 balances → wallets refetch Wallets context

فاز WS-5 — QA + Performance 🟢

ID تسک وضعیت
WS5.1 Latency: order book update < 500ms vs polling 5s staging
WS5.2 Reconnect بعد از sleep/tab background (client 1s reconnect)
WS5.3 50+ concurrent WS روی staging (load) ops
WS5.4 Fallback polling وقتی WS down
WS5.5 حذف intervalهای unused از IntervalApiTime.js ⏸️ نگه داشته (fallback)

۷. مسیر بحرانی و وابستگی

doc-01: T3.1 MarketsContext (marketId از catalog)
         ↓
WS0.* (infra + rangerUrl)
         ↓
WS1.* (rangerClient + Context)
         ↓
WS2.1 (tickers) → WS2.2 (orderbook) → WS2.3 (trades)
         ↓
WS3.* (chart) — موازی با WS2.3
         ↓
WS4.* (private) — بعد از تصمیم auth
         ↓
WS5.* (QA)

موازی با doc-01: WS0 می‌تواند همزمان با فاز ۱ doc-01 (نمودار/CAD) شروع شود.
WS2+ بعد از MarketsContext — market id باید از catalog بیاید نه hardcode.


۸. تخمین زمان

فاز تخمین
WS-0 ۰.۵۱ روز (DevOps)
WS-1 ۱–۲ روز
WS-2 ۲–۳ روز
WS-3 ۱ روز
WS-4 ۲–۳ روز
WS-5 ۱ روز
جمع MVP (WS-0→2) ~۵۷ روز

۹. تست

# connectivity (بعد از WS0)
npx wscat -c "wss://shahoo.fibitex.com/api/v2/ranger/public/?stream=global.tickers"

# browser DevTools → Network → WS → frames
# انتظار: JSON با کلید btcirt, btcusdt, ...

چک UI:

  • قیمت sidebar بدون 5s delay به‌روز شود
  • order book بعد از trade دیگران فوری update
  • Network tab: polling /ohlcvs/stats متوقف (با flag روشن)
  • قطع WS → fallback polling کار کند

۱۰. Todo checklist

فاز WS-0 — Infra
[x] WS0.1 rangerUrl در env.js + template
[x] WS0.2 Traefik /api/v2/ranger روی shahoo.*
[ ] WS0.3 تست global.tickers staging
[ ] WS0.4 Cloudflare WebSocket

فاز WS-1 — Core
[x] WS1.1 rangerClient.js
[x] WS1.2 subscribe/unsubscribe
[x] WS1.3 RangerContext + useRanger
[x] WS1.4 REACT_APP_RANGER_ENABLED + fallback
[x] WS1.5 mapRangerTickersToStatMap

فاز WS-2 — Public replace polling
[x] WS2.1 tickers → StatsContext
[x] WS2.2 order book ob-inc
[x] WS2.3 recent trades
[x] WS2.4 market switch resubscribe
[x] WS2.5 landing tickers

فاز WS-3 — Chart
[x] WS3.1 streaming.js + Rango kline
[x] WS3.2 resolution mapping
[x] WS3.3 cleanup on unmount

فاز WS-4 — Private
[x] WS4.1 BFF ranger credentials + private WS proxy
[x] WS4.2 private WS connect after login
[x] WS4.3 order stream → refresh
[x] WS4.4 trade stream → refresh
[x] WS4.5 balances → wallets refresh

فاز WS-5 — QA
[x] WS5.2 reconnect + WS5.4 fallback
[ ] WS5.1 latency / WS5.3 load / Cloudflare

۱۱. commit message convention

WS1.1: add rangerClient with reconnect
WS2.1: replace stats polling with global.tickers
WS2.2: incremental order book via ob-inc