راهنمای WebSocket

APIهای بی‌درنگ وب‌سوکت برای اعلان‌ها، گفت‌وگو و جریان هوش تهدید. اتصال‌های پایدار دوسویه با اتصال دوبارهٔ خودکار.

۳ نقطهٔ پایانی WebSocket

APIهای بی‌درنگ WebSocket

اتصال‌های پایدار دوسویه برای اعلان‌های زنده، پیام‌رسانی گفت‌وگو و جریان هوش تهدید. کم‌تأخیر، رویدادمحور و آمادهٔ تولید.

0
نقطهٔ پایانی WebSocket
0
گونهٔ رویداد
0
تأخیر رویداد
0
آپ‌تایم اتصال

نمای کلی

OrbVPN سه نقطهٔ پایانی وب‌سوکت در دو سرویس فراهم می‌کند. اتصال‌های وب‌سوکت کانال‌هایی پایدار و کاملاً دوسویه‌اند که به سرور امکان می‌دهند بدون نظرخواهی مکرر، رویدادها را بی‌درنگ به کلاینت شما بفرستد.

معماری رویدادمحور

در کانال‌های رویداد مشخصی مشترک شوید و پیام‌های قالب‌بندی‌شده با JSON را همان لحظهٔ رخ دادن بگیرید. بدون نظرخواهی مکرر، بدون هدر رفتن پهنای باند.

اتصال دوبارهٔ خودکار

کیت‌ها اتصال دوباره را با عقب‌نشینی نمایی مدیریت می‌کنند. پیاده‌سازی‌های دستی باید راهبرد اتصال دوبارهٔ مستندشده در ادامه را دنبال کنند.

ضربان / زنده‌نگه‌داشتن

قاب‌های پینگ-پنگ اتصال‌ها را از میان پروکسی‌ها و توزیع‌کننده‌های بار زنده نگه می‌دارند. کلاینت‌ها باید ظرف ۳۰ ثانیه به پینگ سرور پاسخ دهند.


جریان اتصال

هر اتصال وب‌سوکت، فارغ از نقطهٔ پایانی، از همان چرخهٔ زندگی پیروی می‌کند.

کلاینت
سرور
اتصال
تأیید دریافت
اشتراک
جریان رویدادها
پینگ
پنگ

نقاط پایانی

۱. اعلان‌های OrbNET

اعلان‌های بی‌درنگ برای رویدادهای حساب، به‌روزرسانی اشتراک، تغییر وضعیت دستگاه و هشدارهای سرور.

WebSocketwss://api.orbai.world/ws/notifications

اعلان‌های بی‌درنگ حساب OrbVPN خود را بگیرید. به رمزینهٔ دسترسی معتبر JWT نیاز دارد که به‌عنوان رمزینهٔ حامل در دست‌دهی اولیهٔ اتصال داده می‌شود.

احراز هویت: Bearer
رویدادها
notification
سرور ← کلاینت
subscription_update
سرور ← کلاینت
device_status
سرور ← کلاینت
server_alert
سرور ← کلاینت

ماندگاری اعلان

اعلان‌ها سمت سرور نگه داشته می‌شوند. اگر کلاینت شما قطع شود، اعلان‌های از دست رفته هنگام اتصال دوباره به‌صورت گروهی تحویل می‌شوند (تا ۱۰۰ رویداد از ۲۴ ساعت گذشته).


۲. گفت‌وگوی OrbNET

پیام‌رسانی بی‌درنگ برای گفت‌وگوی پشتیبانی، ارتباط با فروشندگان و پیام‌رسانی درون‌اپی.

WebSocketwss://api.orbai.world/ws/chat

پیام‌رسانی دوسویهٔ گفت‌وگو برای پشتیبانی OrbVPN و ارتباط درون‌اپی. به رمزینهٔ دسترسی معتبر JWT نیاز دارد.

احراز هویت: Bearer
رویدادها
message
دوطرفه
typing
دوطرفه
read_receipt
دوطرفه

۳. جریان تهدید OrbGuard

خوراک زندهٔ هوش تهدید برای تشخیص بی‌درنگ تهدید و پایش امنیتی.

WebSocketwss://guard.orbai.world/ws/threats

جریان بی‌درنگ هوش تهدید از OrbGuard Labs. به کلید API نیاز دارد که از راه سرآیند X-API-Key یا به‌عنوان پارامتر پرس‌وجو داده می‌شود.

احراز هویت: API-Key
رویدادها
threat_detected
سرور ← کلاینت
scan_complete
سرور ← کلاینت
alert
سرور ← کلاینت

حجم جریان تهدید

جریان تهدید OrbGuard می‌تواند حجم بالایی از رویداد تولید کند (بیش از ۱۰۰ رویداد در دقیقه هنگام کارزارهای فعال). در مصرف‌کنندهٔ خود بافر و محدودسازی نرخ پیاده کنید تا برنامه‌تان زیر بار نرود.


نمونه‌های اتصال

جاوااسکریپت

// OrbNET Notifications WebSocket
const token = 'eyJhbGciOiJIUzI1NiIs...';

const ws = new WebSocket(
  `wss://api.orbai.world/ws/notifications?token=${token}`
);

ws.onopen = () => {
  console.log('Connected to OrbNET notifications');

  // Subscribe to specific channels
  ws.send(JSON.stringify({
    type: 'subscribe',
    channels: ['notification', 'device_status', 'subscription_update'],
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  switch (data.type) {
    case 'connection_ack':
      console.log(`Session: ${data.sessionId}`);
      break;
    case 'notification':
      console.log(`[Notification] ${data.payload.title}: ${data.payload.message}`);
      break;
    case 'device_status':
      console.log(`[Device] ${data.payload.deviceId}: ${data.payload.status}`);
      break;
    case 'subscription_update':
      console.log(`[Subscription] ${data.payload.event}: ${data.payload.planName}`);
      break;
    case 'server_alert':
      console.log(`[Alert] ${data.payload.severity}: ${data.payload.message}`);
      break;
    default:
      console.log('Unknown event:', data);
  }
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

ws.onclose = (event) => {
  console.log(`Connection closed: ${event.code} ${event.reason}`);
  // Implement reconnection logic (see below)
};

پایتون

import asyncio
import json
import websockets

async def connect_notifications():
    token = "eyJhbGciOiJIUzI1NiIs..."
    uri = f"wss://api.orbai.world/ws/notifications?token={token}"

    async for websocket in websockets.connect(uri):
        try:
            # Subscribe to channels
            await websocket.send(json.dumps({
                "type": "subscribe",
                "channels": ["notification", "device_status"],
            }))

            async for raw_message in websocket:
                event = json.loads(raw_message)

                if event["type"] == "connection_ack":
                    print(f"Connected. Session: {event['sessionId']}")
                elif event["type"] == "notification":
                    payload = event["payload"]
                    print(f"[Notification] {payload['title']}: {payload['message']}")
                elif event["type"] == "device_status":
                    payload = event["payload"]
                    print(f"[Device] {payload['deviceId']}: {payload['status']}")
                elif event["type"] == "ping":
                    await websocket.pong()

        except websockets.ConnectionClosed:
            print("Connection lost. Reconnecting...")
            continue  # websockets.connect handles reconnection

asyncio.run(connect_notifications())

Go

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/url"
    "os"
    "os/signal"
    "time"

    "github.com/gorilla/websocket"
)

type Event struct {
    Type      string          `json:"type"`
    SessionID string          `json:"sessionId,omitempty"`
    Payload   json.RawMessage `json:"payload,omitempty"`
    Timestamp string          `json:"timestamp,omitempty"`
}

func main() {
    token := "eyJhbGciOiJIUzI1NiIs..."
    u := url.URL{
        Scheme:   "wss",
        Host:     "api.orbai.world",
        Path:     "/ws/notifications",
        RawQuery: fmt.Sprintf("token=%s", token),
    }

    conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
    if err != nil {
        log.Fatal("Connection failed:", err)
    }
    defer conn.Close()

    // Subscribe to channels
    subscribe := map[string]interface{}{
        "type":     "subscribe",
        "channels": []string{"notification", "device_status", "server_alert"},
    }
    conn.WriteJSON(subscribe)

    // Handle ping/pong
    conn.SetPongHandler(func(appData string) error {
        conn.SetReadDeadline(time.Now().Add(60 * time.Second))
        return nil
    })

    // Graceful shutdown
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    done := make(chan struct{})
    go func() {
        defer close(done)
        for {
            var event Event
            err := conn.ReadJSON(&event)
            if err != nil {
                log.Println("Read error:", err)
                return
            }

            switch event.Type {
            case "connection_ack":
                fmt.Printf("Connected. Session: %s\n", event.SessionID)
            case "notification":
                fmt.Printf("[Notification] %s\n", string(event.Payload))
            case "device_status":
                fmt.Printf("[Device] %s\n", string(event.Payload))
            case "server_alert":
                fmt.Printf("[Alert] %s\n", string(event.Payload))
            }
        }
    }()

    select {
    case <-done:
    case <-interrupt:
        log.Println("Shutting down...")
        conn.WriteMessage(
            websocket.CloseMessage,
            websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""),
        )
        select {
        case <-done:
        case <-time.After(time.Second):
        }
    }
}

نمونهٔ جریان تهدید OrbGuard

اتصال به جریان هوش تهدید OrbGuard به‌جای JWT از احراز هویت با کلید API استفاده می‌کند.

// OrbGuard Threat Stream WebSocket
const apiKey = 'ogk_live_abc123...';

const ws = new WebSocket(
  `wss://guard.orbai.world/ws/threats?api_key=${apiKey}`
);

ws.onopen = () => {
  console.log('Connected to OrbGuard threat stream');

  // Subscribe to specific threat categories
  ws.send(JSON.stringify({
    type: 'subscribe',
    channels: ['threat_detected', 'alert'],
    filters: {
      severity: ['critical', 'high'],
      categories: ['malware', 'phishing', 'c2'],
    },
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === 'threat_detected') {
    const threat = data.payload;
    console.log(`[THREAT] ${threat.severity.toUpperCase()}`);
    console.log(`  Indicator: ${threat.indicator}`);
    console.log(`  Type: ${threat.indicatorType}`);
    console.log(`  Category: ${threat.category}`);
    console.log(`  Score: ${threat.score}/100`);
  }

  if (data.type === 'alert') {
    const alert = data.payload;
    console.log(`[ALERT] ${alert.title}`);
    console.log(`  ${alert.message}`);
    console.log(`  Action: ${alert.recommendedAction}`);
  }
};

راهبرد اتصال دوباره

گسست شبکه ناگزیر است. برای اتصال دوبارهٔ بی‌دردسر، عقب‌نشینی نمایی همراه با نوسان تصادفی پیاده کنید.

class ReconnectingWebSocket {
  constructor(url, options = {}) {
    this.url = url;
    this.maxRetries = options.maxRetries || 10;
    this.baseDelay = options.baseDelay || 1000;   // 1 second
    this.maxDelay = options.maxDelay || 30000;     // 30 seconds
    this.retryCount = 0;
    this.handlers = {};
    this.connect();
  }

  connect() {
    this.ws = new WebSocket(this.url);

    this.ws.onopen = () => {
      console.log('Connected');
      this.retryCount = 0; // Reset on successful connection
      this.handlers.open?.();
    };

    this.ws.onmessage = (event) => {
      this.handlers.message?.(JSON.parse(event.data));
    };

    this.ws.onclose = (event) => {
      if (event.code === 1000) return; // Normal closure

      if (this.retryCount < this.maxRetries) {
        const delay = Math.min(
          this.baseDelay * Math.pow(2, this.retryCount) + Math.random() * 1000,
          this.maxDelay
        );
        console.log(`Reconnecting in ${Math.round(delay)}ms (attempt ${this.retryCount + 1})`);
        this.retryCount++;
        setTimeout(() => this.connect(), delay);
      } else {
        console.error('Max reconnection attempts reached');
        this.handlers.maxRetriesReached?.();
      }
    };
  }

  on(event, handler) {
    this.handlers[event] = handler;
    return this;
  }

  send(data) {
    if (this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(data));
    }
  }

  close() {
    this.ws.close(1000, 'Client closing');
  }
}

// Usage
const ws = new ReconnectingWebSocket(
  `wss://api.orbai.world/ws/notifications?token=${token}`,
  { maxRetries: 10, baseDelay: 1000 }
);

ws.on('open', () => {
  ws.send({ type: 'subscribe', channels: ['notification'] });
});

ws.on('message', (data) => {
  console.log('Event:', data);
});

ضربان / پینگ-پنگ

سرور هر ۳۰ ثانیه قاب پینگ وب‌سوکت می‌فرستد. کلاینت‌ها باید با قاب پنگ پاسخ دهند. اگر ظرف ۳۰ ثانیه پنگی نرسد، سرور اتصال را می‌بندد.

پارامترمقدار
فاصلهٔ پینگ۳۰ ثانیه
مهلت پنگ۳۰ ثانیه
بیشینه پینگ ازدست‌رفته۱ (اتصال پس از ۱ پنگ ازدست‌رفته بسته می‌شود)
پینگ آغازشده از سوی کلاینتپشتیبانی می‌شود (سرور با پنگ پاسخ می‌دهد)

وب‌سوکت مرورگر

بیشتر پیاده‌سازی‌های وب‌سوکت در مرورگرها قاب‌های پینگ-پنگ را خودکار در سطح پروتکل مدیریت می‌کنند. تنها هنگام استفاده از کتابخانه‌های سطح‌پایین وب‌سوکت در زبان‌های سمت سرور لازم است این را صریح مدیریت کنید.


قالب پیام رویداد

همهٔ رویدادهای وب‌سوکت از قالب یکسان JSON پیروی می‌کنند:

{
  "type": "notification",
  "id": "evt_abc123def456",
  "timestamp": "2026-02-08T12:00:00.000Z",
  "payload": {
    "title": "Subscription Renewed",
    "message": "Your OrbVPN Premium plan has been renewed for 12 months.",
    "category": "billing",
    "priority": "normal",
    "metadata": {
      "planName": "Premium",
      "amount": 99.99,
      "currency": "USD"
    }
  }
}
فیلدنوعتوضیح
typestringگونهٔ رویداد (با نام کانال مشترک‌شده جور است)
idstringشناسهٔ یکتای رویداد برای حذف تکراری‌ها
timestampstringمُهر زمانی ISO 8601 لحظهٔ ساخته شدن رویداد
payloadobjectدادهٔ ویژهٔ رویداد (بسته به گونهٔ رویداد متفاوت است)

سقف اتصال‌ها

سقف اتصال‌ها

اتصال‌های وب‌سوکت برای هر حساب و هر نقطهٔ پایانی محدودند:

  • اعلان‌ها: ۵ اتصال هم‌زمان برای هر کاربر
  • گفت‌وگو: ۳ اتصال هم‌زمان برای هر کاربر
  • جریان تهدید: ۲ اتصال هم‌زمان برای هر کلید API
  • مجموع هر حساب: ۱۰ اتصال هم‌زمان وب‌سوکت

گذر از این سقف‌ها قاب بستن 4008 Connection Limit Reached را برمی‌گرداند. اتصال‌های موجود متأثر نمی‌شوند.


کدهای بستن با خطا

اتصال‌های وب‌سوکت ممکن است با کدهای زیر بسته شوند:

کددلیلاقدام
1000بستن عادیاقدامی لازم نیست
1001سرور در حال کنار رفتنبا عقب‌نشینی دوباره وصل شوید
1008نقض سیاستگواهی‌های احراز هویت را بررسی کنید
1011خطای داخلی سروربا عقب‌نشینی دوباره وصل شوید
4001احراز هویت ناکام ماندرمزینه را تازه کنید و دوباره وصل شوید
4003ممنوعمجوزهای کانال درخواست‌شده را بررسی کنید
4008رسیدن به سقف اتصالپیش از اتصال دوباره یکی از اتصال‌های موجود را ببندید
4029محدودشده به دلیل نرخبه اندازهٔ مدت مشخص‌شده در دلیل بستن صبر کنید، سپس دوباره وصل شوید

بهترین شیوه‌ها

همیشه نخست احراز هویت کنید

رمزینهٔ خود را در نشانی اتصال یا پیام اولیه بدهید. هرگز پیش از رویداد connection_ack دادهٔ حساس نفرستید.

گزینشی مشترک شوید

تنها در کانال‌هایی مشترک شوید که لازم دارید. اشتراک‌های گسترده پهنای باند و سربار پردازش را بالا می‌برند.

رویدادهای تکراری را حذف کنید

برای حذف تکراری‌ها از فیلد شناسهٔ رویداد استفاده کنید. هنگام اتصال دوباره ممکن است رویدادهایی بگیرید که پیش‌تر تحویل شده‌اند.

فشار برگشتی را مدیریت کنید

رویدادهای ورودی را بافر کنید و ناهم‌زمان پردازششان کنید. رسیدگی‌کنندهٔ پیام وب‌سوکت را با عملیات کند مسدود نکنید.


بی‌درنگ شوید

با APIهای وب‌سوکت اوربی‌وی‌پی‌ان، اعلان‌های زنده، گفت‌وگو و هوش تهدید را در برنامهٔ خود یکپارچه کنید. تأخیر کم، قابلیت اتکای بالا و معماری سادهٔ رویدادمحور.

دیدن کیت‌ها