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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • पुश सदस्यता के लिए सदस्यता से पुश सदस्यता बन जाती है. यह सिर्फ़ तब उपलब्ध होता है, जब किसी सर्विस वर्कर के लिए रजिस्ट्रेशन हो चुका हो और क्लाइंट कोड में 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: के साथ कोड टिप्पणियों में चिह्नित किया गया है. आपको यह करना होगा:

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

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

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

बैकग्राउंड

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

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

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

लागू करने का तरीका

इस चरण में, अपने ऐप्लिकेशन के लिए 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 इंटरफ़ेस में टूल -> लॉग चुनें.

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

    हर बार कोड में बदलाव करने पर, 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 कुंजी को कॉपी करके क्लाइंट कोड में भी चिपकाएं.

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

    public/index.js

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

सूचनाएं भेजने के लिए फ़ंक्शन लागू करें

बैकग्राउंड

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

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

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

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

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);
  });