13 KiB
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: BFFGET /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:
Upgradeheader 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