loading...

แสดงสถานะ user online ด้วย Firebase (1)

ilumin profile image Teerasak Vichadee Updated on ・1 min read

การแสดงสถานะ user online (หรือเรียกอีกอย่างว่า presence) คือการแสดงให้ admin เห็นว่า user A กำลัง online และใช้งาน app ของเราอยู่นะ และทันทีที่ user A ปิด browser หรือ logout ก็อัพเดทสถานะของ user A ทันทีว่า offline ซึ่งส่วนมากจะใช้ในระบบที่ต้องการเห็นสถานะ online/offline ของ user เช่น chat หรือพวก กระดานสนทนา อย่างเช่น discord

โชคดีที่ Firebase สามารถทำ presence ได้ และมีตัวอย่างโค้ดให้ด้วย
ขอลอกมาให้ดูดังนี้

// ดึง uid มาใช้งาน
const uid = firebase.auth().currentUser.uid
// สร้าง RTDB object เอาไว้ใช้งาน
const RTDB = firebase.database().ref()

// node พิเศษ เอามาดูได้ว่า uid ปัจจุบัน connect กับ Firebase อยู่หรือปล่าว
const amOnline = RTDB.child('.info/connected')
// ให้ RTDB ชี้ไปที่ /presence/{uid}
const presenceRef = RTDB.child('presence').child(uid)
// ให้ RTDB ชี้ไปที่ /sessions
const sessionsRef = RTDB.child('sessions')

amOnline.on('value', snapShot => {
  // ถ้ายังไม่ได้ connect กับ Firebase ก็ยังไม่ต้องทำอะไร
  if (!snapShot.val()) return

  // connect ได้แล้วสร้าง presence ได้เลย
  presenceRef.set(true)
  // ถ้า disconnect เมื่อไหร่ก็ลบไปเลย
  presenceRef.onDisconnect().remove()

  // สร้าง session ขึ้นมาใหม่ โดยเก็บ uid และ startedAt
  const session = sessionsRef.push({
    startedAt: firebase.database.ServerValue.TIMESTAMP,
    uid: uid,
  })

  // ในกรณีที่ disconnect ให้เพิ่ม endedAt ใน session ที่เพิ่งสร้างมาเมื่อกี้
  session.child('endedAt')
    .onDisconnect()
    .set(firebase.database.ServerValue.TIMESTAMP)
})

จากโค้ดข้างบน

  • เก็บข้อมูล session ของ user ไว้ใน /sessions โดยให้มี
    • startedAt = เวลาที่สร้าง session (ใช้ firebase.database.ServerValue.TIMESTAMP ก็เหมือนใช้ NOW() ใน MySQL)
    • endedAt = เวลาที่ปิด browser, ปิด tab
    • uid = uid ของ user
  • เก็บข้อมูลสถานะ online/offline ที่ /presence โดยจะใช้ key = uid
  • ทำ subscribe node พิเศษที่ชื่อว่า .info/connected ซึ่งจะเกิด value เมื่อ user connect กับ Firebase
  • เมื่อ connect ได้แล้วก็จะเอา uid ไปสร้าง /sessions และ /presence
  • โดย session ให้ subscribe disconnect event ไว้ว่าถ้าปิด browser เมื่อไหร่ก็อัพเดทเพิ่ม endedAt ลงไป
  • และสำหรับ presence ก็ subscribe disconnect event ไว้ว่าถ้าปิด browser เมื่อไหร่ก็ลบตัวเองทันที

เวลาที่เปิด RTDB จะเห็นข้อมูลประมาณนี้ (สมมุติว่า uid = XXX)

https://app.firebaseio.com/
+- app
   +- presence
      +- XXX: true
   +- sessions
      +- M0m-2FnKgEok1UJRg
         +- startedAt: 1582460581136
         +- uid: XXX

ส่วนการเอาไปใช้งาน
แค่ให้ Firebase ดึงข้อมูลจาก RTDB/presence/{uid}
ถ้าหาเจอก็แสดงว่ากำลัง online อยู่

ยังไม่สมบูรณ์ มีอะไรต้องแก้อีกนะ

แต่สำหรับโค้ดตัวอย่างมีจุดอ่อนดังนี้

  1. กรณีที่ user reload page จะทำให้สถานะหยุด online แป๊ปนึง เพราะ Firebase จะโค้ดจะสร้าง session ใหม่
  2. กรณีที่ user เปิดหลาย tab และปิดไปสัก tab นึง จะทำให้สถานะกลายเป็น offline ทั้งๆที่เปิดบาง tab ค้างไว้
  3. กรณีที่ login หลาย device หรือหลาย browser ก็จะได้คล้ายๆกับข้อ 2.

ไว้รอบหน้าจะมาเล่าให้ฟังว่าแก้ไขอย่างไร :D

Note

Discussion

markdown guide