برنامه های Firebase حتی اگر برنامه شما به طور موقت اتصال شبکه خود را قطع کند، کار می کنند. ما چندین ابزار برای نظارت بر حضور و همگام سازی حالت محلی با وضعیت سرور ارائه می دهیم که در این سند معرفی شده اند.
مدیریت حضور
در برنامههای بلادرنگ، تشخیص زمان اتصال و قطع ارتباط کلاینتها اغلب مفید است. برای مثال، ممکن است بخواهید زمانی که مشتری قطع می شود، کاربر را به عنوان "آفلاین" علامت گذاری کنید.
کلاینت های پایگاه داده Firebase ابتدایی های ساده ای را ارائه می دهند که می توانید از آنها برای نوشتن در پایگاه داده زمانی که کلاینت از سرورهای پایگاه داده Firebase جدا می شود استفاده کنید. این بهروزرسانیها چه اتصال کلاینت بهطور تمیز قطع شود یا خیر، رخ میدهند، بنابراین میتوانید برای پاکسازی دادهها به آنها اعتماد کنید، حتی اگر اتصال قطع شود یا کلاینت خراب شود. تمام عملیات نوشتن، از جمله تنظیم، به روز رسانی، و حذف، می تواند در صورت قطع اتصال انجام شود.
در اینجا یک مثال ساده از نوشتن داده در هنگام قطع اتصال با استفاده از onDisconnect
ابتدایی آورده شده است:
Web
import { getDatabase, ref, onDisconnect } from "firebase/database"; const db = getDatabase(); const presenceRef = ref(db, "disconnectmessage"); // Write a string when this client loses connection onDisconnect(presenceRef).set("I disconnected!");
Web
var presenceRef = firebase.database().ref("disconnectmessage"); // Write a string when this client loses connection presenceRef.onDisconnect().set("I disconnected!");
چگونه onDisconnect کار می کند
هنگامی که یک عملیات onDisconnect()
ایجاد می کنید، این عملیات در سرور Firebase Realtime Database زندگی می کند. سرور امنیت را بررسی می کند تا مطمئن شود کاربر می تواند رویداد نوشتن درخواستی را انجام دهد و در صورت نامعتبر بودن برنامه شما را به اطلاع می رساند. سپس سرور اتصال را کنترل می کند. اگر در هر نقطه ای زمان اتصال تمام شود، یا به طور فعال توسط سرویس گیرنده Realtime Database بسته شود، سرور برای بار دوم امنیت را بررسی می کند (برای اطمینان از اینکه عملیات همچنان معتبر است) و سپس رویداد را فراخوانی می کند.
برنامه شما میتواند از پاسخ به تماس در عملیات نوشتن استفاده کند تا مطمئن شود onDisconnect
به درستی متصل شده است:
Web
onDisconnect(presenceRef).remove().catch((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
Web
presenceRef.onDisconnect().remove((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
یک رویداد onDisconnect
را نیز می توان با فراخوانی .cancel()
لغو کرد:
Web
const onDisconnectRef = onDisconnect(presenceRef); onDisconnectRef.set("I disconnected"); // some time later when we change our minds onDisconnectRef.cancel();
Web
var onDisconnectRef = presenceRef.onDisconnect(); onDisconnectRef.set("I disconnected"); // some time later when we change our minds onDisconnectRef.cancel();
تشخیص وضعیت اتصال
برای بسیاری از ویژگی های مربوط به حضور، برای برنامه شما مفید است که بداند چه زمانی آنلاین یا آفلاین است. Firebase Realtime Database یک مکان ویژه در /.info/connected
ارائه می دهد که هر بار که وضعیت اتصال سرویس گیرنده Firebase Realtime Database تغییر می کند، به روز می شود. در اینجا یک مثال است:
Web
import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const connectedRef = ref(db, ".info/connected"); onValue(connectedRef, (snap) => { if (snap.val() === true) { console.log("connected"); } else { console.log("not connected"); } });
Web
var connectedRef = firebase.database().ref(".info/connected"); connectedRef.on("value", (snap) => { if (snap.val() === true) { console.log("connected"); } else { console.log("not connected"); } });
/.info/connected
یک مقدار بولی است که بین کلاینتهای Realtime Database همگامسازی نمیشود، زیرا مقدار به وضعیت مشتری بستگی دارد. به عبارت دیگر، اگر یک کلاینت /.info/connected
را به عنوان false بخواند، این تضمینی نیست که یک کلاینت جداگانه نیز false را بخواند.
رسیدگی به تاخیر
مهر زمانی سرور
سرورهای Firebase Realtime Database مکانیزمی را برای درج مُهرهای زمانی تولید شده روی سرور به عنوان داده فراهم می کنند. این ویژگی، همراه با onDisconnect
، راه آسانی را برای یادداشتبرداری مطمئن از زمان قطع ارتباط مشتری Realtime Database ارائه میکند:
Web
import { getDatabase, ref, onDisconnect, serverTimestamp } from "firebase/database"; const db = getDatabase(); const userLastOnlineRef = ref(db, "users/joe/lastOnline"); onDisconnect(userLastOnlineRef).set(serverTimestamp());
Web
var userLastOnlineRef = firebase.database().ref("users/joe/lastOnline"); userLastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP);
کج بودن ساعت
در حالی که firebase.database.ServerValue.TIMESTAMP
بسیار دقیق تر است و برای اکثر عملیات خواندن/نوشتن ارجح است، گاهی اوقات تخمین انحراف ساعت مشتری با توجه به سرورهای Firebase Realtime Database می تواند مفید باشد. میتوانید یک تماس برگشتی را به مکان /.info/serverTimeOffset
متصل کنید تا مقداری را که مشتریان Firebase Realtime Database بر حسب میلیثانیه به زمان گزارش شده محلی (زمان دوره به میلیثانیه) برای تخمین زمان سرور اضافه میکنند، به دست آورید. توجه داشته باشید که دقت این افست میتواند تحتتاثیر تأخیر شبکه قرار گیرد، و بنابراین اساساً برای کشف اختلافات بزرگ (> 1 ثانیه) در زمان ساعت مفید است.
Web
import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const offsetRef = ref(db, ".info/serverTimeOffset"); onValue(offsetRef, (snap) => { const offset = snap.val(); const estimatedServerTimeMs = new Date().getTime() + offset; });
Web
var offsetRef = firebase.database().ref(".info/serverTimeOffset"); offsetRef.on("value", (snap) => { var offset = snap.val(); var estimatedServerTimeMs = new Date().getTime() + offset; });
نمونه برنامه حضور
با ترکیب عملیات قطع اتصال با نظارت بر وضعیت اتصال و مهرهای زمانی سرور، می توانید یک سیستم حضور کاربر بسازید. در این سیستم، هر کاربر دادهها را در یک مکان پایگاه داده ذخیره میکند تا مشخص کند آیا یک سرویس گیرنده Realtime Database آنلاین است یا نه. مشتریان زمانی که آنلاین میشوند، این مکان را روی true و هنگام قطع ارتباط یک مهر زمانی تنظیم میکنند. این مهر زمان آخرین باری را که کاربر مورد نظر آنلاین بوده است نشان می دهد.
توجه داشته باشید که برنامه شما باید قبل از اینکه کاربر به صورت آنلاین علامت گذاری شود، عملیات قطع اتصال را در صف قرار دهد تا در صورت قطع شدن اتصال شبکه مشتری قبل از ارسال هر دو دستور به سرور، از هرگونه شرایط مسابقه جلوگیری شود.
در اینجا یک سیستم حضور کاربر ساده وجود دارد:
Web
import { getDatabase, ref, onValue, push, onDisconnect, set, serverTimestamp } from "firebase/database"; // Since I can connect from multiple devices or browser tabs, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline const db = getDatabase(); const myConnectionsRef = ref(db, 'users/joe/connections'); // stores the timestamp of my last disconnect (the last time I was seen online) const lastOnlineRef = ref(db, 'users/joe/lastOnline'); const connectedRef = ref(db, '.info/connected'); onValue(connectedRef, (snap) => { if (snap.val() === true) { // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) const con = push(myConnectionsRef); // When I disconnect, remove this device onDisconnect(con).remove(); // Add this device to my connections list // this value could contain info about the device or a timestamp too set(con, true); // When I disconnect, update the last time I was seen online onDisconnect(lastOnlineRef).set(serverTimestamp()); } });
Web
// Since I can connect from multiple devices or browser tabs, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline var myConnectionsRef = firebase.database().ref('users/joe/connections'); // stores the timestamp of my last disconnect (the last time I was seen online) var lastOnlineRef = firebase.database().ref('users/joe/lastOnline'); var connectedRef = firebase.database().ref('.info/connected'); connectedRef.on('value', (snap) => { if (snap.val() === true) { // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) var con = myConnectionsRef.push(); // When I disconnect, remove this device con.onDisconnect().remove(); // Add this device to my connections list // this value could contain info about the device or a timestamp too con.set(true); // When I disconnect, update the last time I was seen online lastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP); } });