ওয়েব পুশ লাইব্রেরি দিয়ে বার্তা পাঠানো

ওয়েব পুশের সাথে কাজ করার সময় একটি ব্যথার বিষয় হল যে একটি পুশ মেসেজ ট্রিগার করা অত্যন্ত "নিশ্চিত"। একটি পুশ বার্তা ট্রিগার করতে একটি অ্যাপ্লিকেশনকে ওয়েব পুশ প্রোটোকল অনুসরণ করে একটি পুশ পরিষেবাতে একটি POST অনুরোধ করতে হবে৷ সমস্ত ব্রাউজার জুড়ে পুশ ব্যবহার করার জন্য আপনাকে VAPID (ওরফে অ্যাপ্লিকেশন সার্ভার কী) ব্যবহার করতে হবে যার জন্য মূলত একটি মান সহ একটি শিরোনাম সেট করতে হবে যা প্রমাণ করে যে আপনার অ্যাপ্লিকেশন ব্যবহারকারীকে বার্তা দিতে পারে। একটি পুশ বার্তা সহ ডেটা পাঠাতে, ডেটা এনক্রিপ্ট করা প্রয়োজন এবং নির্দিষ্ট শিরোনাম যোগ করা প্রয়োজন যাতে ব্রাউজারটি বার্তাটি সঠিকভাবে ডিক্রিপ্ট করতে পারে।

ট্রিগারিং পুশের প্রধান সমস্যা হল যে আপনি যদি কোনও সমস্যায় আঘাত করেন তবে সমস্যাটি নির্ণয় করা কঠিন। এটি সময় এবং বৃহত্তর ব্রাউজার সমর্থনের সাথে উন্নতি করছে তবে এটি সহজ থেকে অনেক দূরে। এই কারণে, আমি দৃঢ়ভাবে আপনার পুশ বার্তার এনক্রিপশন, ফর্ম্যাটিং এবং ট্রিগারিং পরিচালনা করার জন্য একটি লাইব্রেরি ব্যবহার করার সুপারিশ করছি।

আপনি যদি সত্যিই লাইব্রেরিগুলি কী করছে সে সম্পর্কে জানতে চান, আমরা পরবর্তী বিভাগে এটি কভার করব। আপাতত, আমরা সাবস্ক্রিপশন পরিচালনা করতে যাচ্ছি এবং পুশ অনুরোধগুলি করতে একটি বিদ্যমান ওয়েব পুশ লাইব্রেরি ব্যবহার করব।

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

আমরা নিম্নলিখিত ধাপগুলি অতিক্রম করব:

  1. আমাদের ব্যাকএন্ডে একটি সাবস্ক্রিপশন পাঠান এবং এটি সংরক্ষণ করুন।
  2. সংরক্ষিত সদস্যতা পুনরুদ্ধার করুন এবং একটি পুশ বার্তা ট্রিগার করুন।

সাবস্ক্রিপশন সংরক্ষণ করা হচ্ছে

একটি ডাটাবেস থেকে PushSubscription সংরক্ষণ এবং অনুসন্ধান করা আপনার সার্ভার সাইড ভাষা এবং ডাটাবেস পছন্দের উপর নির্ভর করে পরিবর্তিত হবে, তবে এটি কীভাবে করা যেতে পারে তার একটি উদাহরণ দেখতে দরকারী হতে পারে৷

ডেমো ওয়েব পৃষ্ঠায়, PushSubscription একটি সাধারণ POST অনুরোধ করে আমাদের ব্যাকএন্ডে পাঠানো হয়:

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

আমাদের ডেমোতে এক্সপ্রেস সার্ভারে /api/save-subscription/ endpoint-এর জন্য একটি মিলে যাওয়া অনুরোধ শ্রোতা রয়েছে:

app.post('/api/save-subscription/', function (req, res) {

এই রুটে আমরা অনুরোধটি ঠিক আছে এবং আবর্জনা পূর্ণ নয় তা নিশ্চিত করার জন্য সদস্যতা যাচাই করি:

const isValidSaveRequest = (req, res) => {
  // Check the request body has at least an endpoint.
  if (!req.body || !req.body.endpoint) {
    // Not a valid subscription.
    res.status(400);
    res.setHeader('Content-Type', 'application/json');
    res.send(
      JSON.stringify({
        error: {
          id: 'no-endpoint',
          message: 'Subscription must have an endpoint.',
        },
      }),
    );
    return false;
  }
  return true;
};

সাবস্ক্রিপশন বৈধ হলে, আমাদের এটি সংরক্ষণ করতে হবে এবং একটি উপযুক্ত JSON প্রতিক্রিয়া ফেরত দিতে হবে:

return saveSubscriptionToDatabase(req.body)
  .then(function (subscriptionId) {
    res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({data: {success: true}}));
  })
  .catch(function (err) {
    res.status(500);
    res.setHeader('Content-Type', 'application/json');
    res.send(
      JSON.stringify({
        error: {
          id: 'unable-to-save-subscription',
          message:
            'The subscription was received but we were unable to save it to our database.',
        },
      }),
    );
  });

এই ডেমোটি সাবস্ক্রিপশনগুলি সঞ্চয় করতে nedb ব্যবহার করে, এটি একটি সাধারণ ফাইল ভিত্তিক ডাটাবেস, তবে আপনি আপনার পছন্দের যে কোনও ডাটাবেস ব্যবহার করতে পারেন। আমরা শুধুমাত্র এটি ব্যবহার করছি কারণ এটির জন্য শূন্য সেট-আপ প্রয়োজন। উত্পাদনের জন্য আপনি আরও নির্ভরযোগ্য কিছু ব্যবহার করতে চান। (আমি ভাল পুরানো MySQL এর সাথে লেগে থাকতে চাই।)

function saveSubscriptionToDatabase(subscription) {
  return new Promise(function (resolve, reject) {
    db.insert(subscription, function (err, newDoc) {
      if (err) {
        reject(err);
        return;
      }

      resolve(newDoc._id);
    });
  });
}

পুশ মেসেজ পাঠানো হচ্ছে

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

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

আমি ডেমো কাজ করার সাথে জড়িত প্রতিটি পদক্ষেপের মধ্য দিয়ে যেতে যাচ্ছি। এগুলি হবে শিশুর পদক্ষেপ যাতে নোডে নতুন যে কেউ সহ সবাই অনুসরণ করতে পারে৷

যখন আমরা একজন ব্যবহারকারীর সদস্যতা নিয়ে আলোচনা করেছি, তখন আমরা subscribe() বিকল্পগুলিতে একটি applicationServerKey যোগ করার বিষয়টি কভার করেছি। এটি পিছনের প্রান্তে যে আমাদের এই ব্যক্তিগত কীটির প্রয়োজন হবে।

ডেমোতে, এই মানগুলি আমাদের নোড অ্যাপে যুক্ত করা হয়েছে (আমি জানি বিরক্তিকর কোড, কিন্তু আপনি জানতে চান যে কোনও জাদু নেই):

const vapidKeys = {
  publicKey:
    'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
  privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};

পরবর্তীতে আমাদের নোড সার্ভারের জন্য web-push মডিউলটি ইনস্টল করতে হবে:

npm install web-push --save

তারপর, আমাদের নোড স্ক্রিপ্টে আমাদের web-push মডিউলটির প্রয়োজন হয়:

const webpush = require('web-push');

এখন আমরা web-push মডিউল ব্যবহার করা শুরু করতে পারি। প্রথমে আমাদের web-push মডিউলকে আমাদের অ্যাপ্লিকেশন সার্ভার কী সম্পর্কে বলতে হবে। (মনে রাখবেন যে এগুলি VAPID কী নামেও পরিচিত কারণ এটি স্পেকের নাম।)

const vapidKeys = {
  publicKey:
    'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
  privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};

webpush.setVapidDetails(
  'mailto:web-push-book@gauntface.com',
  vapidKeys.publicKey,
  vapidKeys.privateKey,
);

মনে রাখবেন যে আমরা একটি "mailto:" স্ট্রিংও অন্তর্ভুক্ত করেছি। এই স্ট্রিংটি একটি URL বা একটি mailto ইমেল ঠিকানা হতে হবে৷ তথ্যের এই অংশটি আসলে একটি পুশ ট্রিগার করার অনুরোধের অংশ হিসাবে ওয়েব পুশ পরিষেবাতে পাঠানো হবে। এটি করার কারণ হল যে যদি কোনও ওয়েব পুশ পরিষেবার প্রেরকের সাথে যোগাযোগের প্রয়োজন হয়, তাদের কাছে কিছু তথ্য রয়েছে যা তাদের সক্ষম করবে৷

এটির সাথে, web-push মডিউলটি ব্যবহারের জন্য প্রস্তুত, পরবর্তী পদক্ষেপটি একটি পুশ বার্তা ট্রিগার করা।

ডেমো পুশ বার্তা ট্রিগার করার জন্য প্রটেন্ড অ্যাডমিন প্যানেল ব্যবহার করে।

অ্যাডমিন পৃষ্ঠার স্ক্রিনশট।

"ট্রিগার পুশ মেসেজ" বোতামে ক্লিক করলে /api/trigger-push-msg/ এ একটি POST অনুরোধ করা হবে, যা আমাদের ব্যাকএন্ডের জন্য পুশ বার্তা পাঠানোর সংকেত, তাই আমরা এই এন্ডপয়েন্টের জন্য এক্সপ্রেসে রুট তৈরি করি:

app.post('/api/trigger-push-msg/', function (req, res) {

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

return getSubscriptionsFromDatabase().then(function (subscriptions) {
  let promiseChain = Promise.resolve();

  for (let i = 0; i < subscriptions.length; i++) {
    const subscription = subscriptions[i];
    promiseChain = promiseChain.then(() => {
      return triggerPushMsg(subscription, dataToSend);
    });
  }

  return promiseChain;
});

ফাংশন triggerPushMsg() তারপর প্রদত্ত সাবস্ক্রিপশনে একটি বার্তা পাঠাতে ওয়েব-পুশ লাইব্রেরি ব্যবহার করতে পারে।

const triggerPushMsg = function (subscription, dataToSend) {
  return webpush.sendNotification(subscription, dataToSend).catch((err) => {
    if (err.statusCode === 404 || err.statusCode === 410) {
      console.log('Subscription has expired or is no longer valid: ', err);
      return deleteSubscriptionFromDatabase(subscription._id);
    } else {
      throw err;
    }
  });
};

webpush.sendNotification() এ কল একটি প্রতিশ্রুতি প্রদান করবে। বার্তাটি সফলভাবে পাঠানো হলে প্রতিশ্রুতিটি সমাধান হবে এবং আমাদের কিছু করার দরকার নেই। প্রতিশ্রুতি প্রত্যাখ্যান করলে, আপনাকে ত্রুটিটি পরীক্ষা করতে হবে কারণ এটি আপনাকে জানিয়ে দেবে যে PushSubscription এখনও বৈধ কিনা।

একটি পুশ পরিষেবা থেকে ত্রুটির ধরন নির্ধারণ করতে স্ট্যাটাস কোডটি দেখা ভাল৷ ত্রুটি বার্তাগুলি পুশ পরিষেবাগুলির মধ্যে পরিবর্তিত হয় এবং কিছু অন্যদের চেয়ে বেশি সহায়ক৷

এই উদাহরণে, এটি স্ট্যাটাস কোড 404 এবং 410 পরীক্ষা করে, যেগুলি 'নট ফাউন্ড' এবং 'গেল'-এর জন্য HTTP স্ট্যাটাস কোড। যদি আমরা এর মধ্যে একটি পাই, তাহলে এর অর্থ সাবস্ক্রিপশনের মেয়াদ শেষ হয়ে গেছে বা আর বৈধ নয়। এই পরিস্থিতিতে, আমাদের ডাটাবেস থেকে সাবস্ক্রিপশনগুলি সরাতে হবে।

অন্য কোনো ত্রুটির ক্ষেত্রে, আমরা শুধু throw err , যা triggerPushMsg() দ্বারা প্রত্যাবর্তিত প্রতিশ্রুতি প্রত্যাখ্যান করবে।

আমরা যখন ওয়েব পুশ প্রোটোকলটি আরও বিস্তারিতভাবে দেখব তখন আমরা পরবর্তী বিভাগে অন্যান্য কিছু স্ট্যাটাস কোড কভার করব।

সাবস্ক্রিপশনের মাধ্যমে লুপ করার পরে, আমাদের একটি JSON প্রতিক্রিয়া ফেরত দিতে হবে।

.then(() => {
res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({ data: { success: true } }));
})
.catch(function(err) {
res.status(500);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({
    error: {
    id: 'unable-to-send-messages',
    message: `We were unable to send messages to all subscriptions : ` +
        `'${err.message}'`
    }
}));
});

আমরা প্রধান বাস্তবায়ন পদক্ষেপগুলি অতিক্রম করেছি:

  1. আমাদের ওয়েব পৃষ্ঠা থেকে আমাদের ব্যাক-এন্ডে সদস্যতা পাঠাতে একটি API তৈরি করুন যাতে এটি একটি ডাটাবেসে সংরক্ষণ করতে পারে।
  2. পুশ বার্তা পাঠানোর ট্রিগার করার জন্য একটি API তৈরি করুন (এই ক্ষেত্রে, প্রিটেড অ্যাডমিন প্যানেল থেকে একটি API বলা হয়)।
  3. আমাদের ব্যাকএন্ড থেকে সমস্ত সাবস্ক্রিপশন পুনরুদ্ধার করুন এবং ওয়েব-পুশ লাইব্রেরিগুলির একটি দিয়ে প্রতিটি সদস্যতায় একটি বার্তা পাঠান৷

আপনার ব্যাকএন্ড (নোড, পিএইচপি, পাইথন, …) নির্বিশেষে, পুশ বাস্তবায়নের পদক্ষেপগুলি একই হতে চলেছে।

পরবর্তীতে, এই ওয়েব-পুশ লাইব্রেরিগুলি আমাদের জন্য ঠিক কী করছে?

পরের দিকে কোথায় যেতে হবে

কোড ল্যাব