ส่งการแจ้งเตือนสำหรับเว็บแอปโดยใช้ Cloud Messaging และ Cloud Functions

1. ภาพรวม

ใน Codelab นี้ คุณจะได้เรียนรู้วิธีใช้ Cloud Functions for Firebase เพื่อเพิ่มฟังก์ชันไปยังเว็บแอปแชทโดยส่งการแจ้งเตือนไปยังผู้ใช้แอปแชท

3b1284f5144b54f6.png

สิ่งที่คุณจะได้เรียนรู้

  • สร้างฟังก์ชัน Google Cloud โดยใช้ Firebase SDK
  • ทริกเกอร์ Cloud Functions ตามเหตุการณ์การตรวจสอบสิทธิ์, Cloud Storage และ Cloud Firestore
  • เพิ่มการรองรับ Firebase Cloud Messaging ลงในเว็บแอป

สิ่งที่ต้องมี

  • บัตรเครดิต Cloud Functions for Firebase จำเป็นต้องใช้แพ็กเกจ Firebase Blaze ซึ่งหมายความว่าคุณจะต้องเปิดใช้การเรียกเก็บเงินในโปรเจ็กต์ Firebase โดยใช้บัตรเครดิต
  • ตัวแก้ไข IDE/ข้อความที่ต้องการ เช่น WebStorm, Atom หรือ Sublime
  • เทอร์มินัลสำหรับเรียกใช้คำสั่ง Shell ที่ติดตั้ง NodeJS v9
  • เบราว์เซอร์ เช่น Chrome
  • โค้ดตัวอย่าง ดูขั้นตอนถัดไปสำหรับปัญหานี้

2. รับโค้ดตัวอย่าง

โคลนที่เก็บ GitHub จากบรรทัดคำสั่งดังนี้

git clone https://github.com/firebase/friendlychat

นำเข้าแอปเริ่มต้น

เมื่อใช้ IDE ให้เปิดหรือนำเข้าไดเรกทอรี android_studio_โฟลเดอร์.pngcloud-functions-start จากไดเรกทอรีโค้ดตัวอย่าง ไดเรกทอรีนี้มีโค้ดเริ่มต้นสำหรับ Codelab ที่ประกอบด้วยเว็บแอป Chat ที่ทำงานได้อย่างสมบูรณ์

3. สร้างโปรเจ็กต์ Firebase และตั้งค่าแอป

สร้างโปรเจ็กต์

ในคอนโซล Firebase ให้คลิกเพิ่มโปรเจ็กต์ แล้วตั้งชื่อว่า friendlyChat

คลิกสร้างโปรเจ็กต์

อัปเกรดเป็นแพ็กเกจ Blaze

หากต้องการใช้ฟังก์ชันระบบคลาวด์สำหรับ Firebase คุณจะต้องอัปเกรดโปรเจ็กต์ Firebase เป็นแผนการเรียกเก็บเงิน Blaze ซึ่งคุณจะต้องเพิ่มบัตรเครดิตหรือเครื่องมือการเรียกเก็บเงินอื่นๆ ลงในบัญชี Google Cloud

โปรเจ็กต์ Firebase ทั้งหมดรวมถึงโปรเจ็กต์ที่อยู่ในแพ็กเกจ Blaze จะยังคงมีสิทธิ์เข้าถึงโควต้าการใช้งานฟรีสำหรับ Cloud Functions ขั้นตอนที่ระบุไว้ใน Codelab นี้จะอยู่ภายในขีดจำกัดการใช้งานรุ่นฟรี อย่างไรก็ตาม คุณจะเห็นการเรียกเก็บเงินเล็กน้อย (ประมาณ $0.03) จาก Cloud Storage ที่ใช้ในการโฮสต์อิมเมจการสร้าง Cloud Functions

หากไม่มีสิทธิ์เข้าถึงบัตรเครดิตหรือไม่สบายใจที่จะใช้แพ็กเกจ Blaze ลองใช้ชุดโปรแกรมจำลอง Firebase ซึ่งจะให้คุณจำลอง Cloud Functions โดยไม่เสียค่าใช้จ่ายในเครื่องของคุณเอง

เปิดใช้การตรวจสอบสิทธิ์ Google

เพื่อให้ผู้ใช้ลงชื่อเข้าใช้แอปได้ เราจะใช้การตรวจสอบสิทธิ์ Google ซึ่งต้องเปิดใช้

ในคอนโซล Firebase ให้เปิดส่วนสร้าง > การตรวจสอบสิทธิ์ > แท็บวิธีการลงชื่อเข้าใช้ (หรือคลิกที่นี่เพื่อไปยังแท็บนั้น) จากนั้นเปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้ของ Google แล้วคลิกบันทึก การดำเนินการนี้จะอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้เว็บแอปด้วยบัญชี Google ของตนเองได้

นอกจากนี้ คุณยังกำหนดชื่อแอปที่เปิดเผยต่อสาธารณะเป็นแชทที่เป็นกันเองได้ด้วย โดยทำดังนี้

8290061806aacb46.png

เปิดใช้ Cloud Storage

แอปใช้ Cloud Storage เพื่ออัปโหลดรูปภาพ หากต้องการเปิดใช้ Cloud Storage ในโปรเจ็กต์ Firebase ให้ไปที่ส่วนพื้นที่เก็บข้อมูล แล้วคลิกปุ่มเริ่มต้นใช้งาน ทำตามขั้นตอนในส่วนนี้ และสำหรับตำแหน่ง Cloud Storage จะมีค่าเริ่มต้นที่จะใช้ จากนั้นคลิกเสร็จสิ้นหลังจากนั้น

เพิ่มเว็บแอป

เพิ่มเว็บแอปในคอนโซล Firebase โดยไปที่การตั้งค่าโปรเจ็กต์ แล้วเลื่อนลงไปที่เพิ่มแอป เลือกเว็บเป็นแพลตฟอร์มและเลือกช่องการตั้งค่าโฮสติ้งของ Firebase จากนั้นลงทะเบียนแอปและคลิกถัดไปสำหรับขั้นตอนที่เหลือ แล้วคลิกไปยังคอนโซล

4. ติดตั้งอินเทอร์เฟซบรรทัดคำสั่ง Firebase

Firebase Command Line Interface (CLI) จะช่วยให้คุณแสดงเว็บแอปภายในเครื่องและทำให้เว็บแอปและฟังก์ชันระบบคลาวด์ใช้งานได้

หากต้องการติดตั้งหรืออัปเกรด CLI ให้เรียกใช้คำสั่ง npm ต่อไปนี้:

npm -g install firebase-tools

หากต้องการยืนยันว่าได้ติดตั้ง CLI อย่างถูกต้องแล้ว ให้เปิดคอนโซลและเรียกใช้ดังนี้

firebase --version

ตรวจสอบว่าเวอร์ชันของ Firebase CLI สูงกว่า 4.0.0 เพื่อให้มีฟีเจอร์ล่าสุดทั้งหมดที่จำเป็นสำหรับ Cloud Functions หากไม่มี ให้เรียกใช้ npm install -g firebase-tools เพื่ออัปเกรดดังที่แสดงด้านบน

ให้สิทธิ์ Firebase CLI โดยเรียกใช้:

firebase login

ตรวจสอบว่าคุณอยู่ในไดเรกทอรี cloud-functions-start แล้วตั้งค่า Firebase CLI เพื่อใช้โปรเจ็กต์ Firebase ดังนี้

firebase use --add

ถัดไป ให้เลือกรหัสโปรเจ็กต์แล้วทำตามวิธีการ เมื่อมีข้อความแจ้ง คุณสามารถเลือกชื่อแทนใดก็ได้ เช่น codelab

5. ทำให้ใช้งานได้และเรียกใช้เว็บแอป

เมื่อนำเข้าและกำหนดค่าโปรเจ็กต์แล้ว คุณก็พร้อมที่จะเรียกใช้เว็บแอปเป็นครั้งแรกแล้ว เปิดหน้าต่างเทอร์มินัล ไปที่โฟลเดอร์ cloud-functions-start และทำให้เว็บแอปใช้งานได้ในโฮสติ้งของ Firebase โดยใช้

firebase deploy --except functions

นี่คือเอาต์พุตของคอนโซลที่คุณจะเห็น

i deploying database, storage, hosting
  database: rules ready to deploy.
i  storage: checking rules for compilation errors...
  storage: rules file compiled successfully
i  hosting: preparing ./ directory for upload...
  hosting: ./ folder uploaded successfully
 storage: rules file compiled successfully
 hosting: 8 files uploaded successfully
i starting release process (may take several minutes)...

 Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview
Hosting URL: https://friendlychat-1234.firebaseapp.com

เปิดเว็บแอป

บรรทัดสุดท้ายควรแสดง URL ของโฮสติ้ง ตอนนี้เว็บแอปควรให้บริการจาก URL นี้ ซึ่งควรอยู่ในรูปแบบ https://<project-id>.firebaseapp.com เปิด คุณควรเห็น UI ที่ทำงานของแอปแชท

ลงชื่อเข้าใช้แอปโดยใช้ปุ่มลงชื่อเข้าใช้ด้วย Google และเพิ่มข้อความและโพสต์ข้อความได้ตามต้องการ

3b1284f5144b54f6.png

หากคุณลงชื่อเข้าใช้แอปเป็นครั้งแรกในเบราว์เซอร์ใหม่ โปรดตรวจสอบว่าคุณอนุญาตการแจ้งเตือนเมื่อระบบถาม: 8b9d0c66dc36153d.png

เราจะต้องเปิดการแจ้งเตือนในภายหลัง

ถ้าคุณคลิกบล็อกโดยไม่ตั้งใจ คุณสามารถเปลี่ยนการตั้งค่านี้โดยคลิกปุ่ม 🔒 ปลอดภัยทางด้านซ้ายของ URL ในแถบอเนกประสงค์ของ Chrome และเปิดแถบข้างการแจ้งเตือน โดยทำดังนี้

e926868b0546ed71.png

ตอนนี้เราจะเพิ่มฟังก์ชันโดยใช้ Firebase SDK สำหรับ Cloud Functions

6. ไดเรกทอรีฟังก์ชัน

Cloud Functions ช่วยให้คุณมีโค้ดที่ทำงานในระบบคลาวด์ได้ง่ายๆ โดยไม่ต้องตั้งค่าเซิร์ฟเวอร์ เราจะแนะนำวิธีสร้างฟังก์ชันที่ตอบสนองต่อเหตุการณ์ในฐานข้อมูล Firebase, Cloud Storage และ Firebase Firestore เริ่มที่การตรวจสอบสิทธิ์กันก่อน

เมื่อใช้ Firebase SDK สำหรับฟังก์ชันระบบคลาวด์ โค้ดฟังก์ชันจะอยู่ในไดเรกทอรี functions (โดยค่าเริ่มต้น) โค้ดฟังก์ชันก็เป็นแอป Node.js ด้วย ดังนั้นจึงต้องมี package.json ที่ให้ข้อมูลเกี่ยวกับแอปและแสดงรายการทรัพยากร Dependency

เพื่อให้คุณดำเนินการได้ง่ายขึ้น เราได้สร้างไฟล์ functions/index.js ไว้เก็บโค้ดของคุณไว้ โปรดตรวจสอบไฟล์นี้ก่อนดำเนินการต่อ

cd functions
ls

หากคุณไม่คุ้นเคยกับ Node.js ขอแนะนำให้ศึกษาข้อมูลเพิ่มเติมก่อนใช้ Codelab ต่อ

ไฟล์ package.json แสดงรายการทรัพยากร Dependency ที่จำเป็น 2 รายการแล้ว ได้แก่ Firebase SDK สำหรับ Cloud Functions และ Firebase Admin SDK หากต้องการติดตั้งในเครื่อง ให้ไปที่โฟลเดอร์ functions และเรียกใช้

npm install

เรามาดูไฟล์ index.js กัน

ดัชนี.js

/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 * ...
 */

// TODO(DEVELOPER): Import the Cloud Functions for Firebase and the Firebase Admin modules here.

// TODO(DEVELOPER): Write the addWelcomeMessage Function here.

// TODO(DEVELOPER): Write the blurImages Function here.

// TODO(DEVELOPER): Write the sendNotification Function here.

เราจะนำเข้าโมดูลที่จำเป็น จากนั้นเขียนฟังก์ชัน 3 รายการแทนสิ่งที่ต้องทำ เริ่มต้นด้วยการนำเข้าโมดูลโหนดที่จำเป็น

7. นำเข้าโมดูล Cloud Functions และ Firebase Admin

ระหว่าง Codelab จำเป็นต้องมีโมดูล 2 รายการ โดย firebase-functions จะเปิดใช้การเขียนทริกเกอร์และบันทึก Cloud Functions ขณะที่ firebase-admin เปิดใช้แพลตฟอร์ม Firebase บนเซิร์ฟเวอร์ที่มีสิทธิ์เข้าถึงระดับผู้ดูแลระบบเพื่อดำเนินการต่างๆ เช่น การเขียนไปยัง Cloud Firestore หรือส่งการแจ้งเตือน FCM

ในไฟล์ index.js ให้แทนที่ TODO แรกด้วยข้อมูลต่อไปนี้

ดัชนี.js

/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 * ...
 */

// Import the Firebase SDK for Google Cloud Functions.
const functions = require('firebase-functions');
// Import and initialize the Firebase Admin SDK.
const admin = require('firebase-admin');
admin.initializeApp();

// TODO(DEVELOPER): Write the addWelcomeMessage Function here.

// TODO(DEVELOPER): Write the blurImages Function here.

// TODO(DEVELOPER): Write the sendNotification Function here.

คุณสามารถกำหนดค่า Firebase Admin SDK โดยอัตโนมัติเมื่อทำให้ใช้งานได้กับสภาพแวดล้อม Cloud Functions หรือคอนเทนเนอร์ Google Cloud Platform อื่นๆ ซึ่งจะเกิดขึ้นเมื่อเราเรียกใช้ admin.initializeApp() โดยไม่มีอาร์กิวเมนต์

ทีนี้เรามาเพิ่มฟังก์ชันที่จะทำงานเมื่อผู้ใช้ลงชื่อเข้าใช้เป็นครั้งแรกในแอปแชท และเราจะเพิ่มข้อความแชทเพื่อต้อนรับผู้ใช้

8. ต้อนรับผู้ใช้ใหม่

โครงสร้างข้อความ Chat

ข้อความที่โพสต์ไปยังฟีดแชท friendlyChat จะเก็บอยู่ใน Cloud Firestore มาดูโครงสร้างข้อมูลที่เราใช้สำหรับข้อความกัน โดยโพสต์ข้อความใหม่ในแชทที่ระบุว่า "สวัสดีทุกคน" ดังนี้

11f5a676fbb1a69a.png

ชื่อนี้ควรปรากฏในรูปแบบต่อไปนี้

fe6d1c020d0744cf.png

ในคอนโซล Firebase ให้คลิก Firestore Database ในส่วน Build คุณจะเห็นคอลเล็กชันข้อความและเอกสาร 1 ฉบับที่มีข้อความที่คุณเขียนดังนี้

442c9c10b5e2b245.png

คุณจะเห็นได้ว่าข้อความแชทจัดเก็บอยู่ใน Cloud Firestore เป็นเอกสารโดยเพิ่มแอตทริบิวต์ name, profilePicUrl, text และ timestamp ในคอลเล็กชัน messages

การเพิ่มข้อความต้อนรับ

Cloud Function แรกจะเพิ่มข้อความต้อนรับผู้ใช้ใหม่เข้ามาในแชท สำหรับกรณีนี้ เราสามารถใช้ทริกเกอร์ functions.auth().onCreate ซึ่งจะเรียกใช้ฟังก์ชันทุกครั้งที่ผู้ใช้ลงชื่อเข้าใช้เป็นครั้งแรกในแอป Firebase เพิ่มฟังก์ชัน addWelcomeMessages ลงในไฟล์ index.js ดังนี้

ดัชนี.js

// Adds a message that welcomes new users into the chat.
exports.addWelcomeMessages = functions.auth.user().onCreate(async (user) => {
  functions.logger.log('A new user signed in for the first time.');
  const fullName = user.displayName || 'Anonymous';

  // Saves the new welcome message into the database
  // which then displays it in the FriendlyChat clients.
  await admin.firestore().collection('messages').add({
    name: 'Firebase Bot',
    profilePicUrl: '/images/firebase-logo.png', // Firebase logo
    text: `${fullName} signed in for the first time! Welcome!`,
    timestamp: admin.firestore.FieldValue.serverTimestamp(),
  });
  functions.logger.log('Welcome message written to database.');
});

การเพิ่มฟังก์ชันนี้ลงในออบเจ็กต์ exports พิเศษคือวิธีที่โหนดทำให้ฟังก์ชันเข้าถึงได้นอกไฟล์ปัจจุบันและจำเป็นสำหรับ Cloud Functions

ในฟังก์ชันข้างต้น เราจะเพิ่มข้อความต้อนรับใหม่ที่โพสต์โดย "บ็อต Firebase" ในรายการข้อความแชท โดยใช้เมธอด add ในคอลเล็กชัน messages ใน Cloud Firestore ซึ่งเป็นที่เก็บข้อความของแชท

เนื่องจากการดำเนินการนี้เป็นการดำเนินการแบบไม่พร้อมกัน เราจึงต้องแสดงผล Promise ซึ่งระบุว่าเมื่อ Cloud Firestore เขียนเสร็จแล้ว เพื่อให้ Cloud Functions ไม่ดำเนินการเร็วเกินไป

ทำให้ Cloud Functions ใช้งานได้

Cloud Functions จะทำงานหลังจากที่คุณทำให้ใช้งานได้แล้วเท่านั้น โดยให้เรียกใช้คำสั่งต่อไปนี้ในบรรทัดคำสั่ง

firebase deploy --only functions

นี่คือเอาต์พุตของคอนโซลที่คุณจะเห็น

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
  functions: missing necessary APIs. Enabling now...
i  env: ensuring necessary APIs are enabled...
  env: missing necessary APIs. Enabling now...
i  functions: waiting for APIs to activate...
i  env: waiting for APIs to activate...
  env: all necessary APIs are enabled
  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: creating function addWelcomeMessages...
  functions[addWelcomeMessages]: Successful create operation. 
  functions: all functions deployed successfully!

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlypchat-1234/overview

ทดสอบฟังก์ชัน

เมื่อทำให้ฟังก์ชันใช้งานได้เรียบร้อยแล้ว คุณจะต้องมีผู้ใช้ที่ลงชื่อเข้าใช้เป็นครั้งแรก

  1. เปิดแอปในเบราว์เซอร์โดยใช้ URL โฮสติ้ง (ในรูปแบบ https://<project-id>.firebaseapp.com)
  2. สำหรับผู้ใช้ใหม่ ให้ลงชื่อเข้าใช้ในแอปเป็นครั้งแรกโดยใช้ปุ่มลงชื่อเข้าใช้

262535d1b1223c65.png

  1. หลังจากลงชื่อเข้าใช้ ข้อความต้อนรับควรจะแสดงโดยอัตโนมัติ:

1c70e0d64b23525b.png

9. การดูแลรูปภาพ

ผู้ใช้จะอัปโหลดรูปภาพทุกประเภทในแชทได้และสิ่งสำคัญคือต้องตรวจสอบรูปภาพที่ไม่เหมาะสมอยู่เสมอ โดยเฉพาะในแพลตฟอร์มโซเชียลสาธารณะ ใน friendlyChat ระบบจะจัดเก็บรูปภาพที่เผยแพร่ในแชทไว้ใน Google Cloud Storage

Cloud Functions จะช่วยให้คุณตรวจหาการอัปโหลดรูปภาพใหม่ได้โดยใช้ทริกเกอร์ functions.storage().onFinalize การดำเนินการนี้จะทำงานทุกครั้งที่มีการอัปโหลดหรือแก้ไขไฟล์ใหม่ใน Cloud Storage

ในการกลั่นกรองรูปภาพ เราจะทำตามขั้นตอนต่อไปนี้

  1. ตรวจสอบว่ารูปภาพได้รับการแจ้งว่ารูปภาพเป็นรูปภาพสำหรับผู้ใหญ่หรือมีความรุนแรงโดยใช้ Cloud Vision API หรือไม่
  2. หากมีการแจ้งว่ารูปภาพไม่เหมาะสม ให้ดาวน์โหลดในอินสแตนซ์ Functions ที่กำลังทำงาน
  3. เบลอรูปภาพโดยใช้ ImageMagick
  4. อัปโหลดรูปภาพที่เบลอไปยัง Cloud Storage

เปิดใช้ Cloud Vision API

เนื่องจากเราจะใช้ Google Cloud Vision API ในฟังก์ชันนี้ คุณจึงต้องเปิดใช้ API ในโปรเจ็กต์ Firebase ทำตามลิงก์นี้ จากนั้นเลือกโปรเจ็กต์ Firebase และเปิดใช้ API

5c77fee51ec5de49.png

ติดตั้งทรัพยากร Dependency

ในการกลั่นกรองรูปภาพ เราจะใช้ไลบรารีของไคลเอ็นต์ Google Cloud Vision สำหรับ Node.js, @google-cloud/vision เพื่อเรียกใช้อิมเมจผ่าน Cloud Vision API ในการตรวจหารูปภาพที่ไม่เหมาะสม

หากต้องการติดตั้งแพ็กเกจนี้ในแอป Cloud Functions ให้เรียกใช้คำสั่ง npm install --save ต่อไปนี้ โปรดตรวจสอบว่าคุณได้ดำเนินการนี้จากไดเรกทอรี functions

npm install --save @google-cloud/vision@2.4.0

การดำเนินการนี้จะติดตั้งแพ็กเกจในเครื่องและเพิ่มเป็นทรัพยากร Dependency ที่ประกาศไว้ในไฟล์ package.json

นำเข้าและกำหนดค่าทรัพยากร Dependency

หากต้องการนำเข้าทรัพยากร Dependency ที่ติดตั้งไว้และโมดูลหลัก Node.js บางรายการ (path, os และ fs) ที่เราจำเป็นต้องใช้ในส่วนนี้ ให้เพิ่มบรรทัดต่อไปนี้ที่ด้านบนของไฟล์ index.js

ดัชนี.js

const Vision = require('@google-cloud/vision');
const vision = new Vision.ImageAnnotatorClient();
const {promisify} = require('util');
const exec = promisify(require('child_process').exec);

const path = require('path');
const os = require('os');
const fs = require('fs');

เนื่องจากฟังก์ชันจะทำงานภายในสภาพแวดล้อม Google Cloud จึงไม่จำเป็นต้องกำหนดค่าไลบรารี Cloud Storage และ Cloud Vision เนื่องจากฟังก์ชันจะได้รับการกำหนดค่าโดยอัตโนมัติเพื่อใช้โปรเจ็กต์

การตรวจจับรูปภาพที่ไม่เหมาะสม

คุณจะใช้ทริกเกอร์ Cloud Functions ของ functions.storage.onChange ซึ่งจะเรียกใช้โค้ดทันทีที่สร้างหรือแก้ไขไฟล์หรือโฟลเดอร์ในที่เก็บข้อมูล Cloud Storage เพิ่มฟังก์ชัน blurOffensiveImages ลงในไฟล์ index.js ดังนี้

ดัชนี.js

// Checks if uploaded images are flagged as Adult or Violence and if so blurs them.
exports.blurOffensiveImages = functions.runWith({memory: '2GB'}).storage.object().onFinalize(
    async (object) => {
      const imageUri = `gs://${object.bucket}/${object.name}`;
      // Check the image content using the Cloud Vision API.
      const batchAnnotateImagesResponse = await vision.safeSearchDetection(imageUri);
      const safeSearchResult = batchAnnotateImagesResponse[0].safeSearchAnnotation;
      const Likelihood = Vision.protos.google.cloud.vision.v1.Likelihood;
      if (Likelihood[safeSearchResult.adult] >= Likelihood.LIKELY ||
          Likelihood[safeSearchResult.violence] >= Likelihood.LIKELY) {
        functions.logger.log('The image', object.name, 'has been detected as inappropriate.');
        return blurImage(object.name);
      }
      functions.logger.log('The image', object.name, 'has been detected as OK.');
    });

โปรดทราบว่าเราได้เพิ่มการกำหนดค่าบางอย่างของอินสแตนซ์ Cloud Functions ที่จะเรียกใช้ฟังก์ชัน เมื่อใช้ .runWith({memory: '2GB'}) เราขอให้อินสแตนซ์ได้รับหน่วยความจำ 2 GB แทนค่าเริ่มต้น เนื่องจากฟังก์ชันนี้ใช้หน่วยความจำมาก

เมื่อมีการทริกเกอร์ฟังก์ชัน ระบบจะเรียกใช้รูปภาพผ่าน Cloud Vision API เพื่อตรวจหาว่ามีการแจ้งว่ารูปภาพเป็นรูปภาพสำหรับผู้ใหญ่หรือมีความรุนแรง หากมีการตรวจพบว่ารูปภาพไม่เหมาะสมเมื่อพิจารณาจากเกณฑ์เหล่านี้ เราจะเบลอรูปภาพดังกล่าว ซึ่งทำในฟังก์ชัน blurImage ซึ่งเราจะเห็นเป็นลำดับถัดไป

การเบลอรูปภาพ

เพิ่มฟังก์ชัน blurImage ต่อไปนี้ในไฟล์ index.js

ดัชนี.js

// Blurs the given image located in the given bucket using ImageMagick.
async function blurImage(filePath) {
  const tempLocalFile = path.join(os.tmpdir(), path.basename(filePath));
  const messageId = filePath.split(path.sep)[1];
  const bucket = admin.storage().bucket();

  // Download file from bucket.
  await bucket.file(filePath).download({destination: tempLocalFile});
  functions.logger.log('Image has been downloaded to', tempLocalFile);
  // Blur the image using ImageMagick.
  await exec(`convert "${tempLocalFile}" -channel RGBA -blur 0x24 "${tempLocalFile}"`);
  functions.logger.log('Image has been blurred');
  // Uploading the Blurred image back into the bucket.
  await bucket.upload(tempLocalFile, {destination: filePath});
  functions.logger.log('Blurred image has been uploaded to', filePath);
  // Deleting the local file to free up disk space.
  fs.unlinkSync(tempLocalFile);
  functions.logger.log('Deleted local file.');
  // Indicate that the message has been moderated.
  await admin.firestore().collection('messages').doc(messageId).update({moderated: true});
  functions.logger.log('Marked the image as moderated in the database.');
}

ในฟังก์ชันข้างต้น ระบบจะดาวน์โหลดไบนารีของรูปภาพจาก Cloud Storage จากนั้นระบบจะเบลอรูปภาพโดยใช้เครื่องมือ convert ของ ImageMagick และอัปโหลดเวอร์ชันเบลออีกครั้งในที่เก็บข้อมูล Storage ต่อไป เราจะลบไฟล์บนอินสแตนซ์ Cloud Functions เพื่อเพิ่มพื้นที่ว่างในดิสก์ แล้วดำเนินการดังกล่าวเนื่องจากอินสแตนซ์ Cloud Functions เดียวกันสามารถนำกลับมาใช้ซ้ำได้ และหากไฟล์ไม่ได้รับการล้าง พื้นที่ดิสก์ก็อาจเต็ม สุดท้าย เราเพิ่มบูลีนลงในข้อความแชทที่ระบุว่ารูปภาพมีการกลั่นกรอง ซึ่งจะส่งผลให้มีการรีเฟรชข้อความบนไคลเอ็นต์

ทำให้ฟังก์ชันใช้งานได้

ฟังก์ชันนี้จะใช้งานได้หลังจากที่คุณทำให้ใช้งานได้แล้วเท่านั้น ในบรรทัดคำสั่ง ให้เรียกใช้ firebase deploy --only functions

firebase deploy --only functions

นี่คือเอาต์พุตของคอนโซลที่คุณจะเห็น

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: updating function addWelcomeMessages...
i  functions: creating function blurOffensiveImages...
  functions[addWelcomeMessages]: Successful update operation.
  functions[blurOffensiveImages]: Successful create operation.
  functions: all functions deployed successfully!

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview

ทดสอบฟังก์ชัน

เมื่อทำให้ฟังก์ชันใช้งานได้เรียบร้อยแล้ว ให้ทำดังนี้

  1. เปิดแอปในเบราว์เซอร์โดยใช้ URL โฮสติ้ง (ในรูปแบบ https://<project-id>.firebaseapp.com)
  2. เมื่อลงชื่อเข้าใช้แอปแล้ว ให้อัปโหลดรูปภาพ: 4db9fdab56703e4a.png
  3. เลือกรูปภาพที่ไม่เหมาะสมที่สุดเพื่ออัปโหลด (หรือจะใช้ซอมบี้กินเนื้อนี้ก็ได้!) และหลังจากผ่านไปสักครู่ คุณจะเห็นโพสต์รีเฟรชพร้อมรูปภาพเวอร์ชันเบลอ: 83dd904fbaf97d2b.png

10. การแจ้งเตือนข้อความใหม่

ในส่วนนี้ คุณจะเพิ่ม Cloud Function ที่ส่งการแจ้งเตือนไปยังผู้เข้าร่วมแชทเมื่อมีการโพสต์ข้อความใหม่

เมื่อใช้ Firebase Cloud Messaging (FCM) คุณจะส่งการแจ้งเตือนไปยังผู้ใช้ข้ามแพลตฟอร์มได้อย่างน่าเชื่อถือ หากต้องการส่งการแจ้งเตือนไปยังผู้ใช้ คุณต้องมีโทเค็นอุปกรณ์ FCM ของผู้ใช้ดังกล่าว เว็บแอปแชทที่เราใช้อยู่จะรวบรวมโทเค็นของอุปกรณ์จากผู้ใช้อยู่แล้วเมื่อผู้ใช้เปิดแอปเป็นครั้งแรกในเบราว์เซอร์หรืออุปกรณ์ใหม่ โทเค็นเหล่านี้จะจัดเก็บอยู่ใน Cloud Firestore ในคอลเล็กชัน fcmTokens

หากต้องการดูวิธีรับโทเค็นอุปกรณ์ FCM ในเว็บแอป ให้ไปที่ Firebase Web Codelab

ส่งการแจ้งเตือน

หากต้องการตรวจจับเมื่อมีการโพสต์ข้อความใหม่ คุณจะใช้ทริกเกอร์ functions.firestore.document().onCreate Cloud Functions ซึ่งจะเรียกใช้โค้ดเมื่อมีการสร้างออบเจ็กต์ใหม่ในเส้นทางที่กำหนดของ Cloud Firestore เพิ่มฟังก์ชัน sendNotifications ลงในไฟล์ index.js ดังนี้

ดัชนี.js

// Sends a notifications to all users when a new message is posted.
exports.sendNotifications = functions.firestore.document('messages/{messageId}').onCreate(
  async (snapshot) => {
    // Notification details.
    const text = snapshot.data().text;
    const payload = {
      notification: {
        title: `${snapshot.data().name} posted ${text ? 'a message' : 'an image'}`,
        body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
        icon: snapshot.data().profilePicUrl || '/images/profile_placeholder.png',
        click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`,
      }
    };

    // Get the list of device tokens.
    const allTokens = await admin.firestore().collection('fcmTokens').get();
    const tokens = [];
    allTokens.forEach((tokenDoc) => {
      tokens.push(tokenDoc.id);
    });

    if (tokens.length > 0) {
      // Send notifications to all tokens.
      const response = await admin.messaging().sendToDevice(tokens, payload);
      await cleanupTokens(response, tokens);
      functions.logger.log('Notifications have been sent and tokens cleaned up.');
    }
  });

ในฟังก์ชันข้างต้น เรากำลังรวบรวมผู้ใช้ทั้งหมด โทเค็นของอุปกรณ์จากฐานข้อมูล Cloud Firestore และส่งการแจ้งเตือนไปยังโทเค็นแต่ละรายการโดยใช้ฟังก์ชัน admin.messaging().sendToDevice

ล้างโทเค็น

สุดท้าย เราต้องการนำโทเค็นที่ใช้ไม่ได้แล้วออก กรณีนี้จะเกิดขึ้นเมื่อเบราว์เซอร์หรืออุปกรณ์ไม่ได้ใช้โทเค็นที่เราเคยได้รับจากผู้ใช้อีกต่อไป ตัวอย่างเช่น เหตุการณ์นี้จะเกิดขึ้นเมื่อผู้ใช้เพิกถอนสิทธิ์การแจ้งเตือนสำหรับเซสชันของเบราว์เซอร์ โดยเพิ่มฟังก์ชัน cleanupTokens ต่อไปนี้ในไฟล์ index.js

ดัชนี.js

// Cleans up the tokens that are no longer valid.
function cleanupTokens(response, tokens) {
 // For each notification we check if there was an error.
 const tokensDelete = [];
 response.results.forEach((result, index) => {
   const error = result.error;
   if (error) {
     functions.logger.error('Failure sending notification to', tokens[index], error);
     // Cleanup the tokens that are not registered anymore.
     if (error.code === 'messaging/invalid-registration-token' ||
         error.code === 'messaging/registration-token-not-registered') {
       const deleteTask = admin.firestore().collection('fcmTokens').doc(tokens[index]).delete();
       tokensDelete.push(deleteTask);
     }
   }
 });
 return Promise.all(tokensDelete);
}

ทำให้ฟังก์ชันใช้งานได้

ฟังก์ชันจะทำงานหลังจากที่คุณทำให้ใช้งานได้แล้ว และหากต้องการทำให้ใช้งานได้ ให้เรียกใช้ฟังก์ชันในบรรทัดคำสั่ง

firebase deploy --only functions

นี่คือเอาต์พุตของคอนโซลที่คุณจะเห็น

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: updating function addWelcomeMessages...
i  functions: updating function blurOffensiveImages...
i  functions: creating function sendNotifications...
  functions[addWelcomeMessages]: Successful update operation.
  functions[blurOffensiveImages]: Successful updating operation.
  functions[sendNotifications]: Successful create operation.
  functions: all functions deployed successfully!

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview

ทดสอบฟังก์ชัน

  1. เมื่อทำให้ฟังก์ชันใช้งานได้เรียบร้อยแล้ว ให้เปิดแอปในเบราว์เซอร์โดยใช้ URL โฮสติ้ง (ในรูปแบบ https://<project-id>.firebaseapp.com)
  2. หากคุณลงชื่อเข้าใช้แอปเป็นครั้งแรก ให้อนุญาตการแจ้งเตือนเมื่อได้รับแจ้ง: 8b9d0c66dc36153d.png
  3. ปิดแท็บแอปแชทหรือแสดงแท็บอื่น: การแจ้งเตือนจะปรากฏเฉพาะเมื่อแอปทํางานอยู่เบื้องหลัง หากต้องการดูวิธีรับข้อความขณะที่แอปทำงานอยู่เบื้องหน้า โปรดดูเอกสารประกอบของเรา
  4. ลงชื่อเข้าใช้แอปและโพสต์ข้อความโดยใช้เบราว์เซอร์อื่น (หรือหน้าต่างที่ไม่ระบุตัวตน) คุณควรเห็นการแจ้งเตือนที่แสดงโดยเบราว์เซอร์แรก: 45282ab12b28b926.png

11. ยินดีด้วย

คุณได้ใช้ Firebase SDK สำหรับ Cloud Functions และเพิ่มคอมโพเนนต์ฝั่งเซิร์ฟเวอร์ลงในแอปแชท

หัวข้อที่ครอบคลุม

  • การเขียน Cloud Functions โดยใช้ Firebase SDK สำหรับ Cloud Functions
  • ทริกเกอร์ Cloud Functions ตามเหตุการณ์การตรวจสอบสิทธิ์, Cloud Storage และ Cloud Firestore
  • เพิ่มการรองรับ Firebase Cloud Messaging ลงในเว็บแอป
  • ทำให้ Cloud Functions ใช้งานได้โดยใช้ Firebase CLI

ขั้นตอนถัดไป

ดูข้อมูลเพิ่มเติม