10.8. Kontrol dua arah dengan WebSockets¶
Server-Sent Events hanya mengirim. Ketika pemilik mengetuk "simpan snapshot sekarang" atau "reset penghitung pemicu" di dasbor, dasbor harus mengirim pesan ke kamera. Itulah WebSockets -- satu soket TCP, pesan yang mengalir ke kedua arah.
10.8.1. Rute /control¶
microdot.websocket.with_websocket() melakukan handshake upgrade WebSocket dan memberikan handler sebuah objek WebSocket. Handler berputar selamanya, membaca perintah dan mengirim pengakuan:
from microdot.websocket import with_websocket
from microdot.websocket import WebSocketError
import json
@app.get('/control')
@with_websocket
async def control(request, ws):
while True:
try:
msg = await ws.receive()
except WebSocketError:
break
try:
cmd = json.loads(msg)
except ValueError:
await ws.send({'error': 'bad json'})
continue
if cmd.get('cmd') == 'snapshot_now':
if latest_jpeg:
path = '/sdcard/snaps/manual-{}.jpg'.format(
int(time.time()))
with open(path, 'wb') as f:
f.write(latest_jpeg)
await ws.send({'ok': True, 'saved': path})
else:
await ws.send({'ok': False, 'reason': 'no frame yet'})
elif cmd.get('cmd') == 'reset':
state['trigger_count'] = 0
await ws.send({'ok': True, 'counters': 'reset'})
else:
await ws.send({'error': 'unknown command'})
receive() mengembalikan string untuk frame teks dan byte untuk frame biner. WebSocket.send(...) di sisi browser mengirim teks secara default, sehingga perintah yang dikodekan JSON adalah pilihan yang alami.
send() menerima string, byte, atau apa pun yang dapat diserialisasi JSON -- dict dikirim sebagai frame teks JSON.
WebSocketError dimunculkan ketika klien memutus sambungan (penutupan bersih, jaringan terputus, atau kesalahan protokol). Handler keluar dari loop dan kembali; microdot membersihkan soket.
10.8.2. Dasbor mengirim perintah¶
Dua tombol dimasukkan ke index.html di samping slider:
<button id="snap-btn">Save snapshot</button>
<button id="reset-btn">Reset counter</button>
dan app.js membuka WebSocket sekali dan menghubungkan kedua tombol ke send:
const proto = location.protocol === 'https:' ? 'wss://' : 'ws://';
const ws = new WebSocket(proto + location.host + '/control');
document.getElementById('snap-btn').addEventListener('click', () =>
ws.send(JSON.stringify({cmd: 'snapshot_now'})));
document.getElementById('reset-btn').addEventListener('click', () =>
ws.send(JSON.stringify({cmd: 'reset'})));
ws.addEventListener('message', (e) => {
console.log('cam:', JSON.parse(e.data));
});
Pilihan ws:// vs wss:// mencerminkan http:// vs https:// -- WebSocket mewarisi penanganan TLS yang sama. Dengan HTTPS aktif, dasbor secara otomatis terhubung melalui wss://.
10.8.3. Kapan memilih SSE vs WebSockets¶
Gunakan SSE ketika kamera mendorong dan browser hanya mendengarkan -- notifikasi, telemetri, perubahan status. Kabelnya adalah HTTP biasa, sisi klien adalah satu baris (new EventSource), dan koneksi ulang otomatis.
Gunakan WebSockets ketika browser juga perlu mendorong -- tombol, slider yang mengirim pembaruan tingkat penekanan tombol, apa pun di mana menunggu permintaan berikutnya akan terlalu lambat. Koneksinya dua arah dan terframing, tetapi API-nya lebih rumit di kedua sisi.
Kamera sekarang adalah hal yang interaktif -- amati, dorong acara keluar, terima perintah masuk.