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

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

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

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

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

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

इस कोडलैब में काम करते समय, इस पेज पर एम्बेड किए गए 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 वह फ़ाइल है जिसमें इस कोडलैब के दौरान ज़्यादातर काम किया जाएगा.

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

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

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

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

बैकग्राउंड

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

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

इस ऐप्लिकेशन में, VAPID पासकोड जनरेट करने के साथ-साथ सूचनाओं को एन्क्रिप्ट (सुरक्षित) करने और भेजने के लिए, web-push 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 इंटरफ़ेस में टूल -> लॉग चुनें.

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

    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...';
    ````

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

बैकग्राउंड

इस ऐप्लिकेशन में, सूचनाएं भेजने के लिए web-push 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 रूट पर आते हैं. यह एक POST यूआरएल है. आपको 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);
});

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

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

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

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