একটি পুশ বিজ্ঞপ্তি সার্ভার তৈরি করুন

এই কোডল্যাবে, আপনি একটি পুশ বিজ্ঞপ্তি সার্ভার তৈরি করবেন। সার্ভার পুশ সাবস্ক্রিপশনের একটি তালিকা পরিচালনা করবে এবং তাদের কাছে বিজ্ঞপ্তি পাঠাবে।

ক্লায়েন্ট কোড ইতিমধ্যেই সম্পূর্ণ হয়েছে-এই কোডল্যাবে, আপনি সার্ভার-সাইড কার্যকারিতা নিয়ে কাজ করবেন।

নমুনা অ্যাপটি রিমিক্স করুন এবং একটি নতুন ট্যাবে দেখুন

এমবেডেড গ্লিচ অ্যাপ থেকে বিজ্ঞপ্তিগুলি স্বয়ংক্রিয়ভাবে ব্লক করা হয়েছে, তাই আপনি এই পৃষ্ঠায় অ্যাপটির পূর্বরূপ দেখতে পারবেন না। পরিবর্তে, এখানে কি করতে হবে:

  1. প্রকল্পটিকে সম্পাদনাযোগ্য করতে সম্পাদনা করতে রিমিক্সে ক্লিক করুন৷
  2. সাইটের পূর্বরূপ দেখতে, অ্যাপ দেখুন টিপুন। তারপর ফুলস্ক্রিন টিপুন পূর্ণ পর্দা .

লাইভ অ্যাপটি একটি নতুন Chrome ট্যাবে খোলে৷ এমবেড করা ত্রুটিতে, কোডটি আবার দেখানোর জন্য উৎস দেখুন ক্লিক করুন।

আপনি এই কোডল্যাবের মাধ্যমে কাজ করার সময়, এই পৃষ্ঠায় এমবেড করা ত্রুটির কোডে পরিবর্তন করুন। পরিবর্তনগুলি দেখতে আপনার লাইভ অ্যাপের সাথে নতুন ট্যাবটি রিফ্রেশ করুন৷

প্রারম্ভিক অ্যাপ এবং এর কোডের সাথে পরিচিত হন

অ্যাপের ক্লায়েন্ট UI দেখে শুরু করুন।

নতুন Chrome ট্যাবে:

  1. DevTools খুলতে `Control+Shift+J` (বা Mac এ `Command+Option+J`) টিপুন। কনসোল ট্যাবে ক্লিক করুন।

  2. UI-তে বোতামে ক্লিক করার চেষ্টা করুন (আউটপুটের জন্য Chrome dev কনসোল চেক করুন)।

    • নিবন্ধন পরিষেবা কর্মী আপনার ত্রুটি প্রকল্প URL এর সুযোগের জন্য একজন পরিষেবা কর্মীকে নিবন্ধন করে৷ নিবন্ধনহীন সেবা কর্মী সেবা কর্মীকে সরিয়ে দেয়। যদি এটির সাথে একটি পুশ সাবস্ক্রিপশন সংযুক্ত থাকে তবে পুশ সাবস্ক্রিপশনটিও নিষ্ক্রিয় করা হবে।

    • ধাক্কা সাবস্ক্রাইব করে একটি পুশ সাবস্ক্রিপশন তৈরি করে। এটি শুধুমাত্র তখনই উপলব্ধ হয় যখন একজন পরিষেবা কর্মী নিবন্ধিত হয়ে থাকে এবং ক্লায়েন্ট কোডে একটি VAPID_PUBLIC_KEY ধ্রুবক উপস্থিত থাকে (এটি সম্পর্কে আরও পরে), তাই আপনি এখনও এটিতে ক্লিক করতে পারবেন না৷

    • যখন আপনার একটি সক্রিয় পুশ সাবস্ক্রিপশন থাকে, তখন বর্তমান সাবস্ক্রিপশনের অনুরোধ জানান যে সার্ভার তার এন্ডপয়েন্টে একটি বিজ্ঞপ্তি পাঠায়।

    • সমস্ত সাবস্ক্রিপশনকে অবহিত করুন সার্ভারকে তার ডাটাবেসের সমস্ত সাবস্ক্রিপশন এন্ডপয়েন্টে একটি বিজ্ঞপ্তি পাঠাতে বলে।

      মনে রাখবেন যে এই শেষ পয়েন্টগুলির মধ্যে কিছু নিষ্ক্রিয় হতে পারে৷ এটি সর্বদা সম্ভব যে একটি সাবস্ক্রিপশন অদৃশ্য হয়ে যাবে যখন সার্ভার এটিতে একটি বিজ্ঞপ্তি পাঠাবে।

সার্ভার-সাইডে কী চলছে তা দেখা যাক। সার্ভার কোড থেকে বার্তা দেখতে, Glitch ইন্টারফেসের মধ্যে Node.js লগ দেখুন।

  • Glitch অ্যাপে, Tools -> Logs-এ ক্লিক করুন।

    আপনি সম্ভবত Listening on port 3000 এর মত একটি বার্তা দেখতে পাবেন।

    আপনি যদি বর্তমান সাবস্ক্রিপশন অবহিত করার বা লাইভ অ্যাপ UI-তে সমস্ত সদস্যতা অবহিত করার চেষ্টা করেন, আপনি নিম্নলিখিত বার্তাটিও দেখতে পাবেন:

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

এখন কিছু কোড তাকান.

  • public/index.js এ সম্পূর্ণ ক্লায়েন্ট কোড রয়েছে। এটি বৈশিষ্ট্য সনাক্তকরণ সঞ্চালন করে, পরিষেবা কর্মীকে নিবন্ধন এবং নিবন্ধনমুক্ত করে এবং বিজ্ঞপ্তিগুলি পুশ করার জন্য ব্যবহারকারীর সদস্যতা নিয়ন্ত্রণ করে। এটি সার্ভারে নতুন এবং মুছে ফেলা সদস্যতা সম্পর্কে তথ্য পাঠায়।

    যেহেতু আপনি শুধুমাত্র সার্ভার কার্যকারিতা নিয়ে কাজ করতে যাচ্ছেন, তাই আপনি এই ফাইলটি সম্পাদনা করতে পারবেন না ( VAPID_PUBLIC_KEY ধ্রুবককে পপুলেট করা ছাড়াও)।

  • public/service-worker.js হল একটি সাধারণ পরিষেবা কর্মী যা পুশ ইভেন্টগুলি ক্যাপচার করে এবং বিজ্ঞপ্তিগুলি প্রদর্শন করে৷

  • /views/index.html অ্যাপ UI ধারণ করে।

  • .env পরিবেশের ভেরিয়েবল রয়েছে যা Glitch আপনার অ্যাপ সার্ভারে লোড হয় যখন এটি শুরু হয়। আপনি বিজ্ঞপ্তি পাঠানোর জন্য প্রমাণীকরণ বিবরণ সহ .env পূরণ করবেন।

  • server.js হল সেই ফাইল যা আপনি এই কোডল্যাবের সময় আপনার বেশিরভাগ কাজ করবেন।

    প্রারম্ভিক কোড একটি সাধারণ এক্সপ্রেস ওয়েব সার্ভার তৈরি করে। আপনার জন্য চারটি TODO আইটেম রয়েছে, যা TODO: তোমার দরকার:

    এই কোডল্যাবে, আপনি একবারে এই TODO আইটেমগুলির মাধ্যমে কাজ করবেন।

VAPID বিবরণ তৈরি এবং লোড করুন

আপনার প্রথম TODO আইটেমটি হল VAPID বিবরণ তৈরি করা, সেগুলিকে Node.js এনভায়রনমেন্ট ভেরিয়েবলে যুক্ত করা এবং নতুন মান সহ ক্লায়েন্ট এবং সার্ভার কোড আপডেট করা।

পটভূমি

ব্যবহারকারীরা যখন বিজ্ঞপ্তিগুলিতে সাবস্ক্রাইব করেন, তখন তাদের অ্যাপের পরিচয় এবং এর সার্ভারের উপর আস্থা রাখতে হবে। ব্যবহারকারীদেরও আত্মবিশ্বাসী হতে হবে যে, যখন তারা একটি বিজ্ঞপ্তি পায়, এটি একই অ্যাপ থেকে যা সাবস্ক্রিপশন সেট আপ করে। তাদের বিশ্বাস করতে হবে যে বিজ্ঞপ্তির বিষয়বস্তু অন্য কেউ পড়তে পারবে না।

যে প্রোটোকলটি পুশ বিজ্ঞপ্তিগুলিকে সুরক্ষিত এবং ব্যক্তিগত করে তাকে ওয়েব পুশের জন্য স্বেচ্ছাসেবী অ্যাপ্লিকেশন সার্ভার আইডেন্টিফিকেশন (VAPID) বলা হয়। 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 লগে জেনারেট করা কীগুলি আউটপুট করে (ক্রোম কনসোলে নয় )। VAPID কী দেখতে, টুল -> লগ ইন দ্য গ্লিচ ইন্টারফেস নির্বাচন করুন।

    নিশ্চিত করুন যে আপনি একই কী জোড়া থেকে আপনার সর্বজনীন এবং ব্যক্তিগত কীগুলি অনুলিপি করেছেন!

    আপনি যখনই আপনার কোডটি সম্পাদনা করেন তখনই গ্লিচ আপনার অ্যাপটি পুনরায় চালু করে, তাই আপনার তৈরি করা প্রথম জোড়া কীগুলি আরও আউটপুট অনুসরণ করার সাথে সাথে দৃশ্যের বাইরে স্ক্রোল করতে পারে।

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

বিজ্ঞপ্তি পাঠাতে কার্যকারিতা প্রয়োগ করুন

পটভূমি

এই অ্যাপে, আপনি বিজ্ঞপ্তি পাঠাতে ওয়েব-পুশ এনপিএম প্যাকেজ ব্যবহার করবেন।

যখন 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 URL-এ একটি POST অনুরোধ পাঠায়, যার মধ্যে সাবস্ক্রিপশনটি বডিতে স্ট্রিংফাইড JSON হিসাবে রয়েছে।

  4. সার্ভার POST অনুরোধের মূল অংশ থেকে স্ট্রিংফাইড 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 URL। আপনি 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);
    });

সাবস্ক্রিপশন বাতিল হ্যান্ডেল

পটভূমি

একটি সাবস্ক্রিপশন নিষ্ক্রিয় হয়ে গেলে সার্ভার সবসময় জানতে পারে না-উদাহরণস্বরূপ, ব্রাউজার পরিষেবা কর্মীকে বন্ধ করে দিলে একটি সাবস্ক্রিপশন মুছে ফেলা হতে পারে।

সার্ভার অবশ্য অ্যাপ UI এর মাধ্যমে বাতিল হওয়া সাবস্ক্রিপশন সম্পর্কে জানতে পারে। এই ধাপে, আপনি ডাটাবেস থেকে একটি সাবস্ক্রিপশন সরাতে কার্যকারিতা প্রয়োগ করবেন।

এইভাবে, সার্ভার অস্তিত্বহীন এন্ডপয়েন্টে একগুচ্ছ বিজ্ঞপ্তি পাঠানো এড়িয়ে যায়। স্পষ্টতই এটি একটি সাধারণ পরীক্ষার অ্যাপের সাথে সত্যিই গুরুত্বপূর্ণ নয়, তবে এটি একটি বৃহত্তর স্কেলে গুরুত্বপূর্ণ হয়ে ওঠে।

বাস্তবায়ন

সদস্যতা বাতিল করার অনুরোধগুলি /remove-subscription POST URL-এ আসে।

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