বার্তা যাচ্ছে

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

এক্সটেনশন এবং তাদের বিষয়বস্তু স্ক্রিপ্টের মধ্যে যোগাযোগ বার্তা পাসিং ব্যবহার করে কাজ করে। উভয় পক্ষ অন্য প্রান্ত থেকে প্রেরিত বার্তা শুনতে এবং একই চ্যানেলে প্রতিক্রিয়া জানাতে পারে। একটি বার্তায় যেকোনো বৈধ JSON অবজেক্ট থাকতে পারে (নাল, বুলিয়ান, সংখ্যা, স্ট্রিং, অ্যারে বা অবজেক্ট)। এককালীন অনুরোধের জন্য একটি সাধারণ API এবং একটি আরও জটিল API রয়েছে যা আপনাকে একটি ভাগ করা প্রসঙ্গে একাধিক বার্তা বিনিময়ের জন্য দীর্ঘস্থায়ী সংযোগ রাখতে দেয়৷ অন্য এক্সটেনশনে একটি বার্তা পাঠানোও সম্ভব যদি আপনি এটির আইডি জানেন, যা ক্রস-এক্সটেনশন বার্তা বিভাগে আচ্ছাদিত।

সহজ এক-বারের অনুরোধ

আপনি যদি আপনার এক্সটেনশনের অন্য অংশে শুধুমাত্র একটি একক বার্তা পাঠাতে চান (এবং ঐচ্ছিকভাবে একটি প্রতিক্রিয়া ফিরে পান), আপনার সরলীকৃত runtime.sendMessage বা tabs.sendMessage ব্যবহার করা উচিত। এটি আপনাকে একটি বিষয়বস্তু স্ক্রিপ্ট থেকে এক্সটেনশনে বা তদ্বিপরীত যথাক্রমে একটি এককালীন JSON-ক্রমিক বার্তা পাঠাতে দেয়৷ একটি ঐচ্ছিক কলব্যাক প্যারামিটার আপনাকে অন্য দিক থেকে প্রতিক্রিয়া পরিচালনা করতে দেয়, যদি একটি থাকে।

একটি বিষয়বস্তু স্ক্রিপ্ট থেকে একটি অনুরোধ পাঠানো এই মত দেখায়:

chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});

এক্সটেনশন থেকে একটি বিষয়বস্তু স্ক্রিপ্টে একটি অনুরোধ পাঠানো খুব অনুরূপ দেখায়, এটি কোন ট্যাবে পাঠাতে হবে তা আপনাকে নির্দিষ্ট করতে হবে৷ এই উদাহরণটি নির্বাচিত ট্যাবে কন্টেন্ট স্ক্রিপ্টে একটি বার্তা পাঠানো প্রদর্শন করে।

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
    console.log(response.farewell);
  });
});

প্রাপ্তির শেষে, বার্তাটি পরিচালনা করার জন্য আপনাকে একটি runtime.onMessage ইভেন্ট লিসেনার সেট আপ করতে হবে। এটি একটি বিষয়বস্তু স্ক্রিপ্ট বা এক্সটেনশন পৃষ্ঠা থেকে একই দেখায়।

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse({farewell: "goodbye"});
  }
);

উপরের উদাহরণে, sendResponse সিঙ্ক্রোনাস বলা হয়েছিল। আপনি যদি অসিঙ্ক্রোনাসভাবে sendResponse ব্যবহার করতে চান, return true; onMessage ইভেন্ট হ্যান্ডলারের কাছে।

দ্রষ্টব্য: যদি একাধিক পৃষ্ঠা onMessage ইভেন্টের জন্য শুনছে, শুধুমাত্র একটি নির্দিষ্ট ইভেন্টের জন্য sendResponse() কে কল করা প্রথম ব্যক্তি প্রতিক্রিয়া পাঠাতে সফল হবে। সেই ইভেন্টের অন্যান্য সমস্ত প্রতিক্রিয়া উপেক্ষা করা হবে৷
দ্রষ্টব্য: sendResponse কলব্যাক শুধুমাত্র তখনই বৈধ যদি সিঙ্ক্রোনাসভাবে ব্যবহার করা হয়, অথবা যদি ইভেন্ট হ্যান্ডলারটি true প্রত্যাবর্তন করে ইঙ্গিত দেয় যে এটি অ্যাসিঙ্ক্রোনাসভাবে প্রতিক্রিয়া জানাবে। sendMessage ফাংশনের কলব্যাক স্বয়ংক্রিয়ভাবে ডাকা হবে যদি কোনো হ্যান্ডলার সত্য না ফেরায় বা sendResponse কলব্যাক আবর্জনা-সংগৃহীত হয়।

দীর্ঘস্থায়ী সংযোগ

কখনও কখনও এটি একটি কথোপকথন করা দরকারী যা একটি একক অনুরোধ এবং প্রতিক্রিয়ার চেয়ে দীর্ঘস্থায়ী হয়৷ এই ক্ষেত্রে, আপনি যথাক্রমে runtime.connect বা tabs.connect ব্যবহার করে আপনার বিষয়বস্তু স্ক্রিপ্ট থেকে একটি এক্সটেনশন পৃষ্ঠায় একটি দীর্ঘস্থায়ী চ্যানেল খুলতে পারেন, বা বিপরীতভাবে। চ্যানেলের ঐচ্ছিকভাবে একটি নাম থাকতে পারে, যা আপনাকে বিভিন্ন ধরনের সংযোগের মধ্যে পার্থক্য করতে দেয়।

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

একটি সংযোগ স্থাপন করার সময়, প্রতিটি প্রান্তে একটি রানটাইম দেওয়া হয়৷ পোর্ট অবজেক্ট যা সেই সংযোগের মাধ্যমে বার্তা প্রেরণ এবং গ্রহণের জন্য ব্যবহৃত হয়৷

এখানে আপনি কিভাবে একটি বিষয়বস্তু স্ক্রিপ্ট থেকে একটি চ্যানেল খুলবেন, এবং বার্তা পাঠান এবং শুনবেন:

var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question == "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question == "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});

এক্সটেনশন থেকে একটি বিষয়বস্তু স্ক্রিপ্টে একটি অনুরোধ পাঠানো খুব অনুরূপ দেখায়, কোন ট্যাবে সংযোগ করতে হবে তা আপনাকে নির্দিষ্ট করতে হবে। উপরের উদাহরণে tabs.connect দিয়ে সংযোগ করতে কলটি কেবল প্রতিস্থাপন করুন।

ইনকামিং সংযোগগুলি পরিচালনা করার জন্য, আপনাকে একটি runtime.onConnect ইভেন্ট লিসেনার সেট আপ করতে হবে৷ এটি একটি বিষয়বস্তু স্ক্রিপ্ট বা একটি এক্সটেনশন পৃষ্ঠা থেকে একই দেখায়৷ যখন আপনার এক্সটেনশনের অন্য একটি অংশ "কানেক্ট()" কল করে, তখন রানটাইম সহ এই ইভেন্টটি বরখাস্ত হয়৷ পোর্ট অবজেক্টটি আপনি সংযোগের মাধ্যমে বার্তা পাঠাতে এবং গ্রহণ করতে ব্যবহার করতে পারেন৷ ইনকামিং কানেকশনে সাড়া দিতে কেমন লাগে তা এখানে:

chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name == "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke == "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer == "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer == "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});

পোর্ট জীবনকাল

পোর্টগুলিকে এক্সটেনশনের বিভিন্ন অংশের মধ্যে একটি দ্বি-মুখী যোগাযোগ পদ্ধতি হিসাবে ডিজাইন করা হয়েছে, যেখানে একটি (শীর্ষ-স্তরের) ফ্রেমটিকে ক্ষুদ্রতম অংশ হিসাবে দেখা হয়। tabs.connect , runtime.connect বা runtime.connectNative এ কল করলে একটি পোর্ট তৈরি হয়। এই পোর্টটি অবিলম্বে পোস্টমেসেজের মাধ্যমে অন্য প্রান্তে বার্তা পাঠানোর জন্য ব্যবহার করা যেতে পারে।

যদি একটি ট্যাবে একাধিক ফ্রেম থাকে, তাহলে tabs.connect কল করার ফলে runtime.onConnect ইভেন্টের একাধিক ইনভোকেশন হয় (ট্যাবের প্রতিটি ফ্রেমের জন্য একবার)। একইভাবে, যদি runtime.connect ব্যবহার করা হয়, তাহলে onConnect ইভেন্টটি একাধিকবার ফায়ার করা হতে পারে (এক্সটেনশন প্রক্রিয়ার প্রতিটি ফ্রেমের জন্য একবার)।

আপনি একটি সংযোগ কখন বন্ধ করা হয় তা জানতে চাইতে পারেন, উদাহরণস্বরূপ যদি আপনি প্রতিটি খোলা পোর্টের জন্য পৃথক অবস্থা বজায় রাখেন। এর জন্য আপনি রানটাইম.পোর্ট.অনডিসকানেক্ট ইভেন্টটি শুনতে পারেন। চ্যানেলের অন্য প্রান্তে কোনো বৈধ পোর্ট না থাকলে এই ইভেন্টটি চালু করা হয়। এটি নিম্নলিখিত পরিস্থিতিতে ঘটে:

  • অন্য প্রান্তে runtime.onConnect- এর জন্য কোনো শ্রোতা নেই।
  • পোর্ট ধারণকারী ট্যাবটি আনলোড করা হয় (যেমন যদি ট্যাবটি নেভিগেট করা হয়)।
  • ফ্রেম যেখান থেকে connect কল করা হয়েছিল সেটি আনলোড করা হয়েছে।
  • সমস্ত ফ্রেম যা পোর্ট পেয়েছে ( runtime.onConnect এর মাধ্যমে) আনলোড হয়েছে৷
  • runtime.Port.disconnect অপর প্রান্তে বলা হয়। মনে রাখবেন যে যদি একটি connect কল রিসিভারের শেষে একাধিক পোর্টে পরিণত হয়, এবং এই পোর্টগুলির যেকোনো একটিতে disconnect() কল করা হয়, তাহলে onDisconnect ইভেন্টটি শুধুমাত্র প্রেরকের পোর্টে ফায়ার করা হয়, অন্য পোর্টে নয়।

ক্রস-এক্সটেনশন মেসেজিং

আপনার এক্সটেনশনের বিভিন্ন উপাদানের মধ্যে বার্তা পাঠানোর পাশাপাশি, আপনি অন্যান্য এক্সটেনশনের সাথে যোগাযোগ করতে মেসেজিং API ব্যবহার করতে পারেন৷ এটি আপনাকে একটি সর্বজনীন API প্রকাশ করতে দেয় যা অন্যান্য এক্সটেনশনগুলি সুবিধা নিতে পারে৷

আপনি runtime.onMessageExternal বা runtime.onConnectExternal পদ্ধতি ব্যবহার না করলে ইনকামিং অনুরোধ এবং সংযোগের জন্য শোনা অভ্যন্তরীণ ক্ষেত্রের মতোই। এখানে প্রতিটির একটি উদাহরণ:

// For simple requests:
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id == blocklistedExtension)
      return;  // don't allow this extension access
    else if (request.getTargetData)
      sendResponse({targetData: targetData});
    else if (request.activateLasers) {
      var success = activateLasers();
      sendResponse({activateLasers: success});
    }
  });

// For long-lived connections:
chrome.runtime.onConnectExternal.addListener(function(port) {
  port.onMessage.addListener(function(msg) {
    // See other examples for sample onMessage handlers.
  });
});

একইভাবে, অন্য এক্সটেনশনে একটি বার্তা পাঠানো আপনার এক্সটেনশনের মধ্যে একটি পাঠানোর অনুরূপ। শুধুমাত্র পার্থক্য হল আপনি যে এক্সটেনশনের সাথে যোগাযোগ করতে চান তার আইডি পাস করতে হবে। উদাহরণ স্বরূপ:

// The ID of the extension we want to talk to.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
  function(response) {
    if (targetInRange(response.targetData))
      chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
  }
);

// Start a long-running conversation:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);

ওয়েব পেজ থেকে বার্তা পাঠানো হচ্ছে

ক্রস-এক্সটেনশন মেসেজিংয়ের মতোই, আপনার অ্যাপ বা এক্সটেনশন নিয়মিত ওয়েব পৃষ্ঠাগুলি থেকে বার্তাগুলি গ্রহণ করতে এবং প্রতিক্রিয়া জানাতে পারে৷ এই বৈশিষ্ট্যটি ব্যবহার করার জন্য, আপনাকে প্রথমে আপনার manifest.json-এ উল্লেখ করতে হবে যে আপনি কোন ওয়েবসাইটগুলির সাথে যোগাযোগ করতে চান৷ উদাহরণ স্বরূপ:

"externally_connectable": {
  "matches": ["*://*.example.com/*"]
}

এটি আপনার নির্দিষ্ট করা URL প্যাটার্নের সাথে মেলে এমন যেকোনো পৃষ্ঠায় মেসেজিং API প্রকাশ করবে। URL প্যাটার্নে কমপক্ষে একটি দ্বিতীয়-স্তরের ডোমেন থাকতে হবে - অর্থাৎ, "*", "*.com", "*.co.uk", এবং "*.appspot.com" এর মতো হোস্টনাম প্যাটার্ন নিষিদ্ধ৷ ওয়েব পৃষ্ঠা থেকে, একটি নির্দিষ্ট অ্যাপ বা এক্সটেনশনে একটি বার্তা পাঠাতে runtime.sendMessage বা runtime.connect API ব্যবহার করুন। উদাহরণ স্বরূপ:

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

আপনার অ্যাপ বা এক্সটেনশন থেকে, আপনি runtime.onMessageExternal বা runtime.onConnectExternal API-এর মাধ্যমে ওয়েব পৃষ্ঠাগুলি থেকে বার্তা শুনতে পারেন, ক্রস-এক্সটেনশন মেসেজিংয়ের মতো। শুধুমাত্র ওয়েব পেজ একটি সংযোগ শুরু করতে পারে. এখানে একটি উদাহরণ:

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url == blocklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });

নেটিভ মেসেজিং

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

নিরাপত্তা বিবেচনা

কন্টেন্ট স্ক্রিপ্ট কম বিশ্বস্ত হয়

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

ক্রস-সাইট স্ক্রিপ্টিং

একটি বিষয়বস্তু স্ক্রিপ্ট বা অন্য এক্সটেনশন থেকে একটি বার্তা গ্রহণ করার সময়, আপনার স্ক্রিপ্টগুলি ক্রস-সাইট স্ক্রিপ্টিংয়ের শিকার না হওয়ার জন্য সতর্ক হওয়া উচিত৷ এই পরামর্শটি এক্সটেনশন ব্যাকগ্রাউন্ড পৃষ্ঠার ভিতরে চলমান স্ক্রিপ্টগুলির পাশাপাশি অন্যান্য ওয়েব অরিজিনগুলির মধ্যে চলমান সামগ্রী স্ক্রিপ্টগুলির ক্ষেত্রে প্রযোজ্য৷ বিশেষত, নিচের মত বিপজ্জনক API ব্যবহার করা এড়িয়ে চলুন:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be evaluating an evil script!
  var resp = eval("(" + response.farewell + ")");
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be injecting a malicious script!
  document.getElementById("resp").innerHTML = response.farewell;
});

পরিবর্তে, নিরাপদ API পছন্দ করুন যা স্ক্রিপ্ট চালায় না:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // JSON.parse does not evaluate the attacker's scripts.
  var resp = JSON.parse(response.farewell);
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // innerText does not let the attacker inject HTML elements.
  document.getElementById("resp").innerText = response.farewell;
});

উদাহরণ

আপনি উদাহরণ/এপিআই/মেসেজিং ডিরেক্টরিতে বার্তাগুলির মাধ্যমে যোগাযোগের সহজ উদাহরণগুলি খুঁজে পেতে পারেন। নেটিভ মেসেজিং নমুনা দেখায় কিভাবে একটি Chrome অ্যাপ একটি নেটিভ অ্যাপের সাথে যোগাযোগ করতে পারে। আরও উদাহরণের জন্য এবং সোর্স কোড দেখতে সাহায্যের জন্য, নমুনা দেখুন।