पुश नोटिफ़िकेशन सर्वर बनाना

इस कोडलैब में, पुश नोटिफ़िकेशन सर्वर बनाया जा सकता है. सर्वर पुश सदस्यताओं की सूची मैनेज करेगा और उन्हें सूचनाएं भेजेगा.

क्लाइंट कोड पहले ही पूरा हो चुका है–इस कोडलैब में, आपको सर्वर साइड की सुविधा पर काम करना होगा.

सैंपल ऐप्लिकेशन को रीमिक्स करें और इसे नए टैब में देखें

एम्बेड किए गए Glitch ऐप्लिकेशन पर सूचनाएं पाने की सुविधा अपने-आप ब्लॉक हो जाती है. इसलिए, आपको इस पेज पर ऐप्लिकेशन की झलक नहीं दिखेगी. इसके बजाय, यहां बताया गया है कि क्या करना है:

  1. प्रोजेक्ट में बदलाव करने के लिए, बदलाव करने के लिए रीमिक्स करें पर क्लिक करें.
  2. साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीन फ़ुलस्क्रीन.

लाइव ऐप्लिकेशन, Chrome के नए टैब में खुलता है. एम्बेड किए गए Glitch में, कोड को फिर से दिखाने के लिए सोर्स देखें पर क्लिक करें.

इस कोडलैब पर काम करते समय, इस पेज पर एम्बेड किए गए Glitch के कोड में बदलाव करें. बदलाव देखने के लिए, लाइव ऐप्लिकेशन को नए टैब पर रीफ़्रेश करें.

शुरुआती ऐप्लिकेशन और उसके कोड के बारे में जानें

ऐप्लिकेशन के क्लाइंट यूज़र इंटरफ़ेस (यूआई) पर नज़र डालने से शुरुआत करें.

Chrome के नए टैब में:

  1. DevTools खोलने के लिए, `Control+Shift+J` (या Mac पर `Command+Option+J`) दबाएं. कंसोल टैब पर क्लिक करें.

  2. यूज़र इंटरफ़ेस (यूआई) में बटन पर क्लिक करके देखें (आउटपुट के लिए Chrome डेव कंसोल देखें).

    • सर्विस वर्कर को रजिस्टर करें, आपके Glitch प्रोजेक्ट यूआरएल के स्कोप के लिए सर्विस वर्कर रजिस्टर करता है. सर्विस वर्कर का रजिस्ट्रेशन रद्द करें, सर्विस वर्कर को हटा देता है. अगर इससे पुश सदस्यता अटैच होती है, तो पुश सदस्यता भी बंद हो जाएगी.

    • Subscribe to push, पुश सदस्यता बनाता है. यह सुविधा सिर्फ़ तब उपलब्ध होती है, जब किसी सर्विस वर्कर का रजिस्ट्रेशन हुआ हो और क्लाइंट कोड में VAPID_PUBLIC_KEY कॉन्सटेंट मौजूद हो. इस बारे में ज़्यादा जानकारी बाद में दी जा सकती है. इसलिए, इस पर अभी क्लिक नहीं किया जा सकता.

    • अगर आपने कोई पुश सदस्यता चालू कर रखी है, तो मौजूदा सदस्यता की सूचना दें विकल्प चुनने पर, सर्वर से इसके एंडपॉइंट पर सूचना भेजने का अनुरोध किया जाता है.

    • सभी सदस्यताओं की सूचना भेजें: इससे सर्वर को अपने डेटाबेस में मौजूद, सदस्यता के सभी एंडपॉइंट पर सूचना भेजने का विकल्प मिलता है.

      ध्यान दें कि ऐसा हो सकता है कि इनमें से कुछ एंडपॉइंट बंद हों. हो सकता है कि सदस्यता की सूचना भेजने से पहले ही वह सदस्यता हट जाए.

आइए, देखते हैं कि सर्वर साइड पर क्या चल रहा है. सर्वर कोड से मैसेज देखने के लिए, Glitch इंटरफ़ेस में Node.js लॉग देखें.

  • Glitch ऐप्लिकेशन में, टूल -> पर क्लिक करें लॉग.

    आपको शायद Listening on port 3000 जैसा कोई मैसेज दिखेगा.

    अगर आपने लाइव ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में, मौजूदा सदस्यता की सूचना दें या सभी सदस्यताओं की सूचना दें पर क्लिक करने की कोशिश की है, तो आपको यह मैसेज भी दिखेगा:

    TODO: Implement sendNotifications()
    Endpoints to send to:  []
    

अब कुछ कोड के बारे में जानते हैं.

  • public/index.js में पूरा क्लाइंट कोड मौजूद है. यह सुविधा की पहचान करता है, सर्विस वर्कर को रजिस्टर और अपंजीकृत करता है. साथ ही, यह पुश नोटिफ़िकेशन के लिए उपयोगकर्ता की सदस्यता को नियंत्रित करता है. यह सर्वर पर नई और मिटाई गई सदस्यताओं के बारे में भी जानकारी भेजता है.

    आपकी तरफ़ से सिर्फ़ सर्वर के फ़ंक्शन पर काम किया जाएगा, इसलिए इस फ़ाइल में बदलाव नहीं किया जाएगा. हालांकि, VAPID_PUBLIC_KEY कॉन्सटेंट की जानकारी अपने-आप भरने की सुविधा का इस्तेमाल नहीं किया जाएगा.

  • public/service-worker.js एक सिंपल सर्विस वर्कर है. यह पुश इवेंट कैप्चर करता है और सूचनाएं दिखाता है.

  • /views/index.html में ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) शामिल है.

  • .env में ऐसे एनवायरमेंट वैरिएबल होते हैं जो आपके ऐप्लिकेशन सर्वर के चालू होने पर, Glitch लोड हो जाता है. सूचनाएं भेजने के लिए, .env में पुष्टि करने से जुड़ी जानकारी अपने-आप भर जाएगी.

  • इस कोडलैब के दौरान, आपको अपना ज़्यादातर काम server.js फ़ाइल में करना है.

    शुरुआती कोड, एक आसान एक्सप्रेस वेब सर्वर बनाता है. आपके लिए चार TODO आइटम हैं, जिन्हें TODO: के साथ कोड टिप्पणियों में चिह्नित किया गया है. आपको यह करना होगा:

    इस कोडलैब में, आपको एक-एक करके इन TODO आइटम पर काम करना होगा.

VAPID की जानकारी जनरेट और लोड करना

आपका पहला TODO आइटम VAPID की जानकारी जनरेट करना है, उसे Node.js के एनवायरमेंट वैरिएबल में जोड़ना है, और क्लाइंट और सर्वर कोड को नई वैल्यू के साथ अपडेट करना है.

बैकग्राउंड

जब उपयोगकर्ता सूचनाओं के लिए सदस्यता लेते हैं, तो उन्हें ऐप्लिकेशन और उसके सर्वर की पहचान पर भरोसा करना चाहिए. उपयोगकर्ताओं को यह भी भरोसा होना चाहिए कि जब उन्हें कोई सूचना मिलती है, तो वह उसी ऐप्लिकेशन से है जिसने सदस्यता सेट अप की है. उन्हें यह भरोसा भी करना होगा कि कोई दूसरा व्यक्ति सूचना का कॉन्टेंट नहीं पढ़ सकता.

पुश नोटिफ़िकेशन को सुरक्षित और निजी बनाने वाले प्रोटोकॉल को वॉलंटरी ऐप्लिकेशन सर्वर आइडेंटिफ़िकेशन (वीएपीआईडी) कहते हैं. VAPID, ऐप्लिकेशन, सर्वर, और सदस्यता के एंडपॉइंट की पहचान की पुष्टि करने और सूचना वाले कॉन्टेंट को एन्क्रिप्ट (सुरक्षित) करने के लिए, सार्वजनिक पासकोड क्रिप्टोग्राफ़ी का इस्तेमाल करता है.

इस ऐप्लिकेशन में, VAPID कुंजियां जनरेट करने के साथ-साथ सूचनाओं को एन्क्रिप्ट (सुरक्षित) करने और भेजने के लिए, वेब-पुश npm पैकेज का इस्तेमाल करना होगा.

लागू करना

इस चरण में, अपने ऐप्लिकेशन के लिए VAPID कुंजियों का जोड़ा जनरेट करें और उन्हें एनवायरमेंट वैरिएबल में जोड़ें. सर्वर में एनवायरमेंट वैरिएबल लोड करें और सार्वजनिक पासकोड को क्लाइंट कोड में कॉन्स्टेंट के तौर पर जोड़ें.

  1. VAPID कुंजियों का जोड़ा बनाने के लिए, web-push लाइब्रेरी के generateVAPIDKeys फ़ंक्शन का इस्तेमाल करें.

    server.js में, कोड की नीचे दी गई लाइनों के आस-पास से टिप्पणियां हटाएं:

    server.js

    // Generate VAPID keys (only do this once).
    /*
     * const vapidKeys = webpush.generateVAPIDKeys();
     * console.log(vapidKeys);
     */
    const vapidKeys = webpush.generateVAPIDKeys();
    console.log(vapidKeys);
    
  2. जब Glitch आपके ऐप्लिकेशन को रीस्टार्ट करता है, तो यह जनरेट की गई कुंजियों को Glitch इंटरफ़ेस में मौजूद Node.js लॉग पर डिलीवर करता है (Chrome कंसोल पर नहीं. VAPID कुंजियां देखने के लिए, टूल -> चुनें ग्लिच इंटरफ़ेस में लॉग.

    पक्का करें कि आप एक ही कुंजी के जोड़े से, अपनी सार्वजनिक और निजी कुंजियों को कॉपी करें!

    हर बार कोड में बदलाव करने पर, Glitch आपके ऐप्लिकेशन को रीस्टार्ट करता है. इसलिए, जनरेट की जाने वाली कुंजियों का पहला जोड़ा, स्क्रोल करके बाहर आ सकता है. ऐसा ज़्यादा आउटपुट आने पर किया जाता है.

  3. .env में, VAPID कुंजियों को कॉपी करें और चिपकाएं. कुंजियों को डबल कोट ("...") में रखें.

    VAPID_SUBJECT के लिए, "mailto:test@test.test" डाला जा सकता है.

    .env

    # process.env.SECRET
    VAPID_PUBLIC_KEY=
    VAPID_PRIVATE_KEY=
    VAPID_SUBJECT=
    VAPID_PUBLIC_KEY="BN3tWzHp3L3rBh03lGLlLlsq..."
    VAPID_PRIVATE_KEY="I_lM7JMIXRhOk6HN..."
    VAPID_SUBJECT="mailto:test@test.test"
    
  4. server.js में, कोड की उन दो पंक्तियों को फिर से टिप्पणी करें, क्योंकि आपको VAPID कुंजियां सिर्फ़ एक बार जनरेट करनी होंगी.

    server.js

    // Generate VAPID keys (only do this once).
    /*
    const vapidKeys = webpush.generateVAPIDKeys();
    console.log(vapidKeys);
    */
    const vapidKeys = webpush.generateVAPIDKeys();
    console.log(vapidKeys);
    
  5. server.js में, एनवायरमेंट वैरिएबल से VAPID की जानकारी लोड करें.

    server.js

    const vapidDetails = {
      // TODO: Load VAPID details from environment variables.
      publicKey: process.env.VAPID_PUBLIC_KEY,
      privateKey: process.env.VAPID_PRIVATE_KEY,
      subject: process.env.VAPID_SUBJECT
    }
    
  6. सार्वजनिक कुंजी को कॉपी करके क्लाइंट कोड में भी चिपकाएं.

    public/index.js में VAPID_PUBLIC_KEY के लिए वही मान डालें जिसे आपने .env फ़ाइल में कॉपी किया है:

    public/index.js

    // Copy from .env
    const VAPID_PUBLIC_KEY = '';
    const VAPID_PUBLIC_KEY = 'BN3tWzHp3L3rBh03lGLlLlsq...';
    ````
    

सूचनाएं भेजने से जुड़ी सुविधा लागू करें

बैकग्राउंड

इस ऐप्लिकेशन में, सूचनाएं भेजने के लिए आपको वेब-पुश npm पैकेज का इस्तेमाल करना होगा.

webpush.sendNotification() को कॉल करने पर, यह पैकेज सूचनाओं को अपने-आप एन्क्रिप्ट (सुरक्षित) करता है. इसलिए, आपको इसकी चिंता करने की ज़रूरत नहीं है.

web-push, सूचनाओं के लिए कई विकल्प स्वीकार करता है–उदाहरण के लिए, आप मैसेज में हेडर अटैच कर सकते हैं और कॉन्टेंट एन्कोडिंग तय कर सकते हैं.

इस कोडलैब में, आपको सिर्फ़ दो विकल्पों का इस्तेमाल करना होगा. इन विकल्पों को कोड की इन लाइनों से तय किया जाता है:

let options = {
  TTL: 10000; // Time-to-live. Notifications expire after this.
  vapidDetails: vapidDetails; // VAPID keys from .env
};

TTL (लाइव होने का समय) विकल्प, किसी सूचना के खत्म होने का समय सेट करता है. यह एक ऐसा तरीका है जिससे सर्वर अब किसी उपयोगकर्ता को सूचना भेजने से बच सकता है.

vapidDetails विकल्प में VAPID कुंजियां शामिल होती हैं. इन्हें आपने एनवायरमेंट वैरिएबल से लोड किया है.

लागू करना

server.js में, sendNotifications फ़ंक्शन में इस तरह बदलाव करें:

server.js

function sendNotifications(database, endpoints) {
  // TODO: Implement functionality to send notifications.
  console.log('TODO: Implement sendNotifications()');
  console.log('Endpoints to send to: ', endpoints);
  let notification = JSON.stringify(createNotification());
  let options = {
    TTL: 10000, // Time-to-live. Notifications expire after this.
    vapidDetails: vapidDetails // VAPID keys from .env
  };
  endpoints.map(endpoint => {
    let subscription = database[endpoint];
    webpush.sendNotification(subscription, notification, options);
  });
}

webpush.sendNotification() फ़ंक्शन से प्रॉमिस रिटर्न मिलता है, इसलिए गड़बड़ी को आसानी से मैनेज करने की सुविधा जोड़ी जा सकती है.

server.js में, sendNotifications फ़ंक्शन में फिर से बदलाव करें:

server.js

function sendNotifications(database, endpoints) {
  let notification = JSON.stringify(createNotification());
  let options = {
    TTL: 10000; // Time-to-live. Notifications expire after this.
    vapidDetails: vapidDetails; // VAPID keys from .env
  };
  endpoints.map(endpoint => {
    let subscription = database[endpoint];
    webpush.sendNotification(subscription, notification, options);
    let id = endpoint.substr((endpoint.length - 8), endpoint.length);
    webpush.sendNotification(subscription, notification, options)
    .then(result => {
      console.log(`Endpoint ID: ${id}`);
      console.log(`Result: ${result.statusCode} `);
    })
    .catch(error => {
      console.log(`Endpoint ID: ${id}`);
      console.log(`Error: ${error.body} `);
    });
  });
}

नई सदस्यताएं मैनेज करना

बैकग्राउंड

यहां बताया गया है कि जब उपयोगकर्ता पुश नोटिफ़िकेशन की सदस्यता लेता है, तो क्या होता है:

  1. उपयोगकर्ता पुश की सदस्यता लें पर क्लिक करता है.

  2. क्लाइंट, सर्वर के हिसाब से यूनीक subscription ऑब्जेक्ट जनरेट करने के लिए, VAPID_PUBLIC_KEY कॉन्स्टेंट (सर्वर की सार्वजनिक VAPID कुंजी) का इस्तेमाल करता है. subscription ऑब्जेक्ट ऐसा दिखता है:

       {
         "endpoint": "https://fcm.googleapis.com/fcm/send/cpqAgzGzkzQ:APA9...",
         "expirationTime": null,
         "keys":
         {
           "p256dh": "BNYDjQL9d5PSoeBurHy2e4d4GY0sGJXBN...",
           "auth": "0IyyvUGNJ9RxJc83poo3bA"
         }
       }
    
  3. क्लाइंट, /add-subscription यूआरएल पर POST का अनुरोध भेजता है. इसमें, सदस्यता के मुख्य हिस्से में, स्ट्रिंग वाले JSON फ़ॉर्मैट में सदस्यता भी शामिल होती है.

  4. सर्वर, पोस्ट अनुरोध के मुख्य हिस्से से स्ट्रिंगिफ़ाइड subscription को हासिल करता है, उसे वापस JSON पर पार्स करता है, और उसे सदस्यताओं के डेटाबेस में जोड़ता है.

    डेटाबेस, सदस्यताओं को स्टोर करने के लिए अपने एंडपॉइंट का इस्तेमाल एक कुंजी के तौर पर करता है:

    {
      "https://fcm...1234": {
        endpoint: "https://fcm...1234",
        expirationTime: ...,
        keys: { ... }
      },
      "https://fcm...abcd": {
        endpoint: "https://fcm...abcd",
        expirationTime: ...,
        keys: { ... }
      },
      "https://fcm...zxcv": {
        endpoint: "https://fcm...zxcv",
        expirationTime: ...,
        keys: { ... }
      },
    }

अब सर्वर पर सूचनाएं भेजने के लिए, नई सदस्यता उपलब्ध है.

लागू करना

नई सदस्यताओं के लिए अनुरोध /add-subscription रूट पर आते हैं, जो एक पीओएसटी यूआरएल होता है. आपको server.js में एक स्टब रूट हैंडलर दिखेगा:

server.js

app.post('/add-subscription', (request, response) => {
  // TODO: implement handler for /add-subscription
  console.log('TODO: Implement handler for /add-subscription');
  console.log('Request body: ', request.body);
  response.sendStatus(200);
});

आपके लागू करने के तरीके में, इस हैंडलर के लिए यह ज़रूरी है:

  • अनुरोध के मुख्य हिस्से से नई सदस्यता वापस पाएं.
  • चालू सदस्यताओं का डेटाबेस ऐक्सेस करना.
  • नई सदस्यता को चालू सदस्यताओं की सूची में जोड़ें.

नई सदस्यताएं मैनेज करने के लिए:

  • server.js में, /add-subscription के लिए रूट हैंडलर को इस तरह बदलें:

    server.js

    app.post('/add-subscription', (request, response) => {
      // TODO: implement handler for /add-subscription
      console.log('TODO: Implement handler for /add-subscription');
      console.log('Request body: ', request.body);
      let subscriptions = Object.assign({}, request.session.subscriptions);
      subscriptions[request.body.endpoint] = request.body;
      request.session.subscriptions = subscriptions;
      response.sendStatus(200);
    });

रद्द की गई सदस्यताओं को मैनेज करना

बैकग्राउंड

सर्वर को हमेशा यह जानकारी नहीं मिलेगी कि सदस्यता कब बंद हो जाती है. उदाहरण के लिए, जब ब्राउज़र सर्विस वर्कर को बंद कर देता है, तब सदस्यता वाइप भी की जा सकती है.

हालांकि, सर्वर उन सदस्यताओं के बारे में पता लगा सकता है जिन्हें ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) से रद्द किया गया है. इस चरण में, आपको डेटाबेस से सदस्यता को हटाने की सुविधा लागू करनी होगी.

इस तरह, सर्वर ऐसे एंडपॉइंट पर सूचनाओं को भेजने से बचाता है जो मौजूद नहीं हैं. आसान टेस्ट ऐप्लिकेशन से कोई फ़र्क़ नहीं पड़ता, लेकिन बड़े पैमाने पर यह ज़रूरी हो जाता है.

लागू करना

सदस्यताएं रद्द करने के अनुरोध, /remove-subscription पोस्ट यूआरएल पर आते हैं.

server.js में स्टब रूट हैंडलर

server.js

app.post('/remove-subscription', (request, response) => {
  // TODO: implement handler for /remove-subscription
  console.log('TODO: Implement handler for /remove-subscription');
  console.log('Request body: ', request.body);
  response.sendStatus(200);
});

आपके लागू करने के तरीके में, इस हैंडलर के लिए यह ज़रूरी है:

  • अनुरोध के मुख्य हिस्से से, रद्द की गई सदस्यता का एंडपॉइंट वापस पाएं.
  • चालू सदस्यताओं का डेटाबेस ऐक्सेस करना.
  • चालू सदस्यताओं की सूची से रद्द की गई सदस्यता हटाएं.

क्लाइंट के पोस्ट अनुरोध के मुख्य हिस्से में वह एंडपॉइंट होता है जिसे आपको हटाना होगा:

{
  "endpoint": "https://fcm.googleapis.com/fcm/send/cpqAgzGzkzQ:APA9..."
}

सदस्यता रद्द करने की प्रक्रिया को मैनेज करने के लिए:

  • server.js में, /remove-subscription के लिए रूट हैंडलर को इस तरह बदलें:

    server.js

  app.post('/remove-subscription', (request, response) => {
    // TODO: implement handler for /remove-subscription
    console.log('TODO: Implement handler for /remove-subscription');
    console.log('Request body: ', request.body);
    let subscriptions = Object.assign({}, request.session.subscriptions);
    delete subscriptions[request.body.endpoint];
    request.session.subscriptions = subscriptions;
    response.sendStatus(200);
  });