Streaming

wss wss://ws.xsignalfeed.com/v1/stream

Menyambung

Stream menerima kunci Anda dengan tiga cara yang sama seperti REST. Dari server, gunakan header; gunakan parameter URL hanya jika header tidak bisa diatur. Jika kunci tidak sampai atau tidak diterima, koneksi terbuka lalu langsung ditutup dengan 4001, dan alasan penutupan menyebutkan sebabnya.

Cara mengirim kunciGunakan saat
Authorization: Bearer xsf_…Disarankan untuk server; header yang sama dengan REST
X-API-Key: xsf_…Setara dengan yang di atas
?api_key=xsf_…Browser, dan klien yang tidak bisa mengatur header handshake. Kunci menjadi bagian dari URL, jadi jauhkan URL semacam itu dari log
python — kunci di header
import websockets

async with websockets.connect("wss://ws.xsignalfeed.com/v1/stream",
                              additional_headers={"Authorization": "Bearer xsf_your_key"}) as ws:
    print(await ws.recv())    # {"t": "system.hello", ...}
Parameter kueriArti
api_keyKunci Anda, saat Anda tidak bisa menyetel header
last_idLanjutkan setelah sid ini. Diabaikan diam-diam kecuali kunci memiliki cakupan replay
import asyncio, json, websockets

async def main():
    url = "wss://ws.xsignalfeed.com/v1/stream?api_key=xsf_your_key"
    async with websockets.connect(url) as ws:
        async for raw in ws:
            ev = json.loads(raw)
            if ev["t"].startswith("system."): continue
            print(ev["t"], ev["target"]["screen_name"], ev["d"].get("text", "")[:60])

asyncio.run(main())

Frame

Tiga frame berasal dari kami, bukan dari X:

FrameKapan
system.helloFrame pertama. targets adalah jumlah akun yang dipantau kunci ini saat ini (akun yang ditambahkan kemudian ikut tanpa menyambung ulang); replay_from mengembalikan last_id yang Anda kirim saat menyambung ulang dan bernilai null bila tidak ada, sehingga tidak ada yang diputar ulang
system.pingDikirim saat hening sebagai keepalive, agar proxy yang menganggur tidak menutup soket
system.errorAda yang salah dengan koneksi; penutupan menyusul

Kode penutupan

Handshake selalu berhasil dan penutupan langsung menyusul, sehingga pustaka klien Anda melihat kode dan alasannya, bukan sekadar error HTTP polos.

Kode penutupanArti
1012Layanan dimulai ulang saat pemeliharaan. Sambungkan ulang dengan backoff dan kirim sid terakhir yang Anda proses sebagai ?last_id=: peristiwa selama jeda diputar ulang, tidak ada yang hilang
4001Kunci tidak diterima. Alasan penutupan menyebutkan sebabnya: missing_api_key (tidak ada kunci yang sampai ke kami: periksa nama header, atau apakah proxy atau pustaka klien Anda meneruskannya), invalid_api_key (kunci itu tidak ada: salah ketik, atau secret yang diganti oleh rotasi), key_revoked (kunci telah dicabut)
4002Terlalu banyak koneksi bersamaan untuk kunci ini; frame system.error mendahului penutupan
4003Kunci tidak memiliki cakupan stream

Menyambung ulang dengan benar

Tulis ini sekali saja, bukan versi naifnya. Dua hal yang penting adalah backoff eksponensial dan menyimpan sid di tempat yang bertahan setelah proses dimulai ulang.

python — bentuk produksi
import asyncio, json, pathlib, random, websockets

STATE = pathlib.Path("xsf.cursor")          # survives restarts; a DB row is better still

async def run(key, handle):
    backoff = 1
    while True:
        last = STATE.read_text().strip() if STATE.exists() else None
        url = f"wss://ws.xsignalfeed.com/v1/stream?api_key={key}" + (f"&last_id={last}" if last else "")
        try:
            async with websockets.connect(url, ping_interval=20, max_size=2**22) as ws:
                backoff = 1
                async for raw in ws:
                    ev = json.loads(raw)
                    if ev["t"].startswith("system."): continue
                    handle(ev)                      # must be idempotent: dedupe on ev["id"]
                    if ev.get("sid"): STATE.write_text(ev["sid"])   # only after handling
        except Exception as e:
            print("disconnected:", e)
        await asyncio.sleep(backoff + random.random())   # jitter, or every client returns at once
        backoff = min(60, backoff * 2)