Realtime

StorageDB Realtime - PostgreSQL o'zgarishlarini, mijozlar orasidagi xabar almashishni va foydalanuvchi holatini real vaqtda kuzatish.

Kirish

Realtime funksiyasi PostgreSQL ma'lumotlar bazasidagi o'zgarishlarni, broadcast xabarlarini va foydalanuvchilar holati (presence) haqida ma'lumotni real vaqtda olish imkoniyatini beradi.

Uchtа asosiy turdagi voqealar mavjud: (1) Postgres Changes — jadvallar o'zgarishi uchun, RLS hurmat qilinadi; (2) Broadcast — mijozlar orasidagi bevosita xabar almashishi; (3) Presence — qaysi foydalanuvchilar faol ekanligini kuzatish.

WebSocket Ulanish

Realtime xizmatiga WebSocket orqali ulanish kerak. URLda project reference (<REF>) va API key (<ANON_KEY> yoki <SERVICE_KEY>) o'tkaziladi.

Ulanishdan so'ng server ready xabari yuboradi, shunda siz subscribe, join, va boshqa komandalarni yuborshingiz mumkin.

WebSocket URL tuzish
wss://storage.identify.uz/v1/<REF>/realtime/v1/websocket?apikey=<ANON_KEY>
TypeScript SDK orqali ulanish
import StorageDB from '@storagedb/client';

const db = new StorageDB({
  url: 'https://storage.identify.uz',
  apiKey: '<ANON_KEY>',
  ref: '<REF>',
});

const channel = db.channel('my-channel');
channel.subscribe();

Postgres Changes

Jadvaldagi INSERT, UPDATE, yoki DELETE operatsiyalarini kuzatish uchun avval SQL'da realtime.enable('jadvalnomi') chaqiring, keyin WebSocket'da o'sha jadvalgа subscribe qiling.

RLS (Row Level Security) siyosatlari hurmat qilinadi — har foydalanuvchi faqat o'ziga ko'rinishi mumkin bo'lgan qatorlarni oladi. Service role esa barcha qatorlarni oladi.

UPDATE va DELETE voqealarida old_record (eski qiymatlar) keladi, lekin RLS ostidagi foydalanuvchilar uchun faqat primary key ustunlari jo'natiladi (ma'lumot sirraligi uchun).

Jadvalni Realtime-ga tayyorlash (SQL)
-- Service role sifatida bajariladi
SELECT realtime.enable('todos');
curl orqali subscribe
wscat -c 'wss://storage.identify.uz/v1/<REF>/realtime/v1/websocket?apikey=<ANON_KEY>'

# Ulanishdan so'ng, quyidagini yuboring:
{"type": "subscribe", "table": "todos"}

# Javob:
{"type": "subscribed", "table": "todos"}

# INSERT voqeasini olish:
{"type": "change", "event": "INSERT", "table": "todos", "record": {"id": 1, "title": "Task 1"}}
TypeScript SDK orqali Postgres Changes
const channel = db.channel('todos')
  .on('INSERT', (payload) => {
    console.log('Yangi qator qo\'shildi:', payload.record);
  })
  .on('UPDATE', (payload) => {
    console.log('Qator yangilandi:', payload.record);
    console.log('Eski qiymatlar:', payload.old_record);
  })
  .on('DELETE', (payload) => {
    console.log('Qator o\'chirildi (PK):', payload.old_record);
  })
  .on('*', (payload) => {
    // Barcha o'zgarishlar
    console.log('O\'zgarish:', payload.event);
  })
  .subscribe();

Broadcast — Mijozlar Orasidagi Xabarlar

Broadcast xizmatida ma'lumotlar bazasi bilan bog'lanmagan holda, foydalanuvchilar bir-biriga xabar yuborishlari mumkin (masalan, o'yinchililar o'rtasida, real vaqtda kursorlari ko'rsatish uchun).

Topic'ga join qiling, keyin broadcast buyrug'i bilan xabar yuboring. Bir xil topic'dagi boshqa foydalanuvchilar bu xabarni oladi.

Broadcast serverda saqlanmaydi — faqat faol ulanishlargа jo'natiladi.

curl orqali broadcast
# Ulanish va topic'ga qo'shilish
wscat -c 'wss://storage.identify.uz/v1/<REF>/realtime/v1/websocket?apikey=<ANON_KEY>'

{"type": "join", "topic": "gaming-room"}
# Javob:
{"type": "joined", "topic": "gaming-room"}

# Xabar yuborish
{"type": "broadcast", "topic": "gaming-room", "event": "cursor_move", "payload": {"x": 100, "y": 200}}

# Boshqa mijozlar quyidagini oladi:
{"type": "broadcast", "topic": "gaming-room", "event": "cursor_move", "payload": {"x": 100, "y": 200}}
TypeScript SDK orqali Broadcast
const channel = db.channel('gaming-room')
  .onBroadcast('cursor_move', (message) => {
    console.log('Boshqa foydalanuvchi kursori:', message.payload);
  })
  .subscribe();

// Xabar yuborish
channel.send('cursor_move', { x: 100, y: 200 });
channel.send('player_action', { action: 'jump' });

Presence — Kim Onlayn

Presence orqali foydalanuvchilar o'zlarining holatini (status, ma'lumot) tarqata oladi va boshqalarning holatlarini kuzata oladi.

track(state) bilan o'z holatni belgilang, presenceState() orqali boshqalarning holatlarini oling. Bir key uchun bir nechta state bo'lishi mumkin (masalan, bir foydalanuvchi bir nechta tabdan ulanishi).

Foydalanuvchi jo'nalganda avtomatik ravishda presence_leave xabari jo'natiladi.

curl orqali Presence
# Ulanish
wscat -c 'wss://storage.identify.uz/v1/<REF>/realtime/v1/websocket?apikey=<ANON_KEY>'

# Topic'ga qo'shilish
{"type": "join", "topic": "chatroom"}

# O'z holatni belgilash
{"type": "presence_track", "topic": "chatroom", "key": "user-123", "state": {"username": "Ali", "status": "online"}}

# Javob (barcha foydalanuvchilar):
{"type": "presence_sync", "topic": "chatroom", "state": {"user-123": [{"username": "Ali", "status": "online"}]}}

# Boshqa foydalanuvchi kelmasa:
{"type": "presence_join", "topic": "chatroom", "key": "user-456", "state": {"username": "Bob"}}
TypeScript SDK orqali Presence
const channel = db.channel('chatroom')
  .onPresenceSync(() => {
    const state = channel.presenceState();
    console.log('Onlayn foydalanuvchilar:', state);
    // state: { 'user-123': [{username: 'Ali', status: 'online'}] }
  })
  .onPresenceJoin((event) => {
    console.log('Yangi foydalanuvchi:', event.key, event.state);
  })
  .onPresenceLeave((event) => {
    console.log('Foydalanuvchi ketdi:', event.key);
  })
  .subscribe();

// O'z holatni belgilash
channel.track({ username: 'Ali', status: 'online' });

// Holatni yangilash (track qayta chaqirish)
setTimeout(() => {
  channel.track({ username: 'Ali', status: 'idle' });
}, 5000);

// Holatni olib tashlash
channel.untrack();

RLS va Xavfsizlik

Postgres Changes avtomatik ravishda RLS siyosatlarini hurmat qiladi. Anon key (ochiq) ishlatuvchi faqat o'ziga ko'rinishi mumkin bo'lgan qatorlarni oladi.

Service key (maxfiy) rola BYPASSRLS ni qo'lladi, shuning uchun barcha qatorlarni oladi.

Har voqea har obunachi uchun alohida tekshiriladi. DELETE voqeasida qator yo'qolgan bo'lgani sababli faqat primary key ustunlari jo'natiladi.