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

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

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

সাধারণ এককালীন অনুরোধ

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

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

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 অ্যাসিঙ্ক্রোনাসভাবে ব্যবহার করতে চান, তাহলে onMessage ইভেন্ট হ্যান্ডলারে return true; যোগ করুন।

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

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

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

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

সংযোগ স্থাপনের সময়, উভয় প্রান্তকে একটি runtime.Port অবজেক্ট দেওয়া হয়, যা সেই সংযোগের মাধ্যমে বার্তা পাঠানো এবং গ্রহণ করার জন্য ব্যবহৃত হয়।

একটি কন্টেন্ট স্ক্রিপ্ট থেকে কীভাবে একটি চ্যানেল খুলবেন এবং মেসেজ পাঠাবেন ও শুনবেন, তা এখানে দেখানো হলো:

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

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

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

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 কল করলে একটি পোর্ট তৈরি হয়। এই পোর্টটি postMessage-এর মাধ্যমে অপর প্রান্তে বার্তা পাঠানোর জন্য অবিলম্বে ব্যবহার করা যেতে পারে।

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

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

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

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

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

আগত অনুরোধ এবং সংযোগ শোনার প্রক্রিয়াটি অভ্যন্তরীণ ক্ষেত্রের মতোই, তবে এক্ষেত্রে 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);
  });

স্থানীয় বার্তা

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

নিরাপত্তা সংক্রান্ত বিবেচনা

কন্টেন্ট স্ক্রিপ্টগুলো কম নির্ভরযোগ্য।

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

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

কোনো কন্টেন্ট স্ক্রিপ্ট বা অন্য কোনো এক্সটেনশন থেকে মেসেজ গ্রহণ করার সময়, আপনার স্ক্রিপ্টগুলোকে ক্রস-সাইট স্ক্রিপ্টিংয়ের শিকার হওয়া থেকে সতর্ক থাকতে হবে। এই পরামর্শটি এক্সটেনশনের ব্যাকগ্রাউন্ড পেজের ভেতরে চলমান স্ক্রিপ্ট এবং অন্যান্য ওয়েব অরিজিনের ভেতরে চলমান কন্টেন্ট স্ক্রিপ্ট—উভয়ের ক্ষেত্রেই প্রযোজ্য। বিশেষত, নিচের মতো বিপজ্জনক এপিআই (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;
});

এর পরিবর্তে, এমন নিরাপদ এপিআই ব্যবহার করুন যা স্ক্রিপ্ট চালায় না:

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

উদাহরণ

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