ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ WebSocket

WebSocket ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для real-time ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ: Π½ΠΎΠ²Ρ‹Π΅ сообщСния, голосовыС Π·Π²ΠΎΠ½ΠΊΠΈ, измСнСния сСрвСров ΠΈ ΠΊΠ°Π½Π°Π»ΠΎΠ².

Endpoint

wss://api.enot.space/ws?token=YOUR_JWT_TOKEN

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ (JavaScript)

const token = localStorage.getItem('token'); const ws = new WebSocket(`wss://api.enot.space/ws?token=${token}`); ws.onopen = () => { console.log('WebSocket connected'); }; ws.onmessage = (event) => { const message = JSON.parse(event.data); console.log('Received:', message); }; ws.onerror = (error) => { console.error('WebSocket error:', error); }; ws.onclose = () => { console.log('WebSocket disconnected'); };

Π’Π°ΠΆΠ½ΠΎ: JWT Ρ‚ΠΎΠΊΠ΅Π½ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ Π²Π°Π»ΠΈΠ΄Π½Ρ‹ΠΌ. ΠŸΡ€ΠΈ истСчСнии Ρ‚ΠΎΠΊΠ΅Π½Π° WebSocket соСдинСниС Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΎ.

Π’ΠΈΠΏΡ‹ сообщСний

ВсС WebSocket сообщСния ΠΈΠΌΠ΅ΡŽΡ‚ ΠΏΠΎΠ»Π΅ type, ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‰Π΅Π΅ Ρ‚ΠΈΠΏ события.

Π’ΠΈΠΏ НаправлСниС ОписаниС
ping Client β†’ Server ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° соСдинСния
pong Server β†’ Client ΠžΡ‚Π²Π΅Ρ‚ Π½Π° ping
subscribe Client β†’ Server Подписка Π½Π° ΠΊΠ°Π½Π°Π»
unsubscribe Client β†’ Server ΠžΡ‚ΠΏΠΈΡΠΊΠ° ΠΎΡ‚ ΠΊΠ°Π½Π°Π»Π°
message_new Server β†’ Client НовоС сообщСниС Π² ΠΊΠ°Π½Π°Π»Π΅
message_update Server β†’ Client Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ
message_delete Server β†’ Client Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΡƒΠ΄Π°Π»Π΅Π½ΠΎ
voice_state_update Client β†’ Server ОбновлСниС голосового состояния
voice_state_add Server β†’ Client ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΡΡ ΠΊ голосовому ΠΊΠ°Π½Π°Π»Ρƒ
voice_state_remove Server β†’ Client ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΡΡ ΠΎΡ‚ голосового ΠΊΠ°Π½Π°Π»Π°
webrtc_signal Bidirectional WebRTC signaling (offer, answer, ICE)

Подписка Π½Π° ΠΊΠ°Π½Π°Π»Ρ‹

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ сообщСния ΠΈΠ· ΠΊΠ°Π½Π°Π»Π°, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΠ΄ΠΏΠΈΡΠ°Ρ‚ΡŒΡΡ Π½Π° Π½Π΅Π³ΠΎ.

Подписка

ws.send(JSON.stringify({ type: 'subscribe', channel_id: 123 }));

ΠžΡ‚ΠΏΠΈΡΠΊΠ°

ws.send(JSON.stringify({ type: 'unsubscribe', channel_id: 123 }));

Π‘ΠΎΠ²Π΅Ρ‚: ΠŸΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°ΠΉΡ‚Π΅ΡΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΊΠ°Π½Π°Π»Ρ‹ для экономии Ρ‚Ρ€Π°Ρ„ΠΈΠΊΠ°.

Бобытия сообщСний

НовоС сообщСниС

{ "type": "message_new", "data": { "id": 456, "channel_id": 123, "user_id": 1, "content": "ΠŸΡ€ΠΈΠ²Π΅Ρ‚!", "created_at": "2026-05-05T18:00:00Z", "author": { "id": 1, "username": "user", "display_name": "User#1234" } } }

Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ

{ "type": "message_update", "data": { "id": 456, "channel_id": 123, "content": "ΠŸΡ€ΠΈΠ²Π΅Ρ‚, ΠΌΠΈΡ€!", "edited_at": "2026-05-05T18:05:00Z" } }

Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΡƒΠ΄Π°Π»Π΅Π½ΠΎ

{ "type": "message_delete", "data": { "id": 456, "channel_id": 123 } }

ГолосовыС события

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ голосовому ΠΊΠ°Π½Π°Π»Ρƒ

ws.send(JSON.stringify({ type: 'voice_state_update', channel_id: 123, muted: false, deafened: false, screen_sharing: false }));

ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΡΡ

{ "type": "voice_state_add", "data": { "user_id": 2, "channel_id": 123, "muted": false, "deafened": false, "screen_sharing": false, "display_name": "User#5678" } }

WebRTC Signaling

// ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° offer ws.send(JSON.stringify({ type: 'webrtc_signal', to_user_id: 2, signal_type: 'offer', data: { sdp: '...', type: 'offer' } })); // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ answer { "type": "webrtc_signal", "from_user_id": 2, "signal_type": "answer", "data": { "sdp": "...", "type": "answer" } }

Rate Limiting

WebSocket сообщСния Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΠ΄Π²Π΅Ρ€ΠΆΠ΅Π½Ρ‹ rate limiting:

  • 60-120 сообщСний Π² ΠΌΠΈΠ½ΡƒΡ‚Ρƒ Π½Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ
  • ΠŸΡ€ΠΈ ΠΏΡ€Π΅Π²Ρ‹ΡˆΠ΅Π½ΠΈΠΈ Π»ΠΈΠΌΠΈΡ‚Π° соСдинСниС Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΎ
  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ debounce для частых ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ

Best Practices

  • Π Π΅Π°Π»ΠΈΠ·ΡƒΠΉΡ‚Π΅ автоматичСскоС ΠΏΠ΅Ρ€Π΅ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ с exponential backoff
  • ΠžΡ‚ΠΏΡ€Π°Π²Π»ΡΠΉΡ‚Π΅ ping ΠΊΠ°ΠΆΠ΄Ρ‹Π΅ 30 сСкунд для поддСрТания соСдинСния
  • ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΠΉΡ‚Π΅ всС Ρ‚ΠΈΠΏΡ‹ событий gracefully
  • ΠŸΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°ΠΉΡ‚Π΅ΡΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΊΠ°Π½Π°Π»Ρ‹
  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ сообщСний Π½Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π΅
  • Π₯Ρ€Π°Π½ΠΈΡ‚Π΅ состояниС локально для offline Ρ€Π΅ΠΆΠΈΠΌΠ°