/** * Repeatedly sending a message to target tab until the response is detected good. * @param {object} tab the table where to send the message * @param {object} req the request data. * @param {function} cond success condition function, r:any=>boolean * @param {number} interval interval for detecting * @param {string} log messages logged to console. * @return {Promise} a promise of the response. */ function sendMessage(tab, req, log, cond, interval) { interval = interval || 500; return new Promise((resolve, reject) => { loop(); async function loop() { // console.log("request for", req.action); let tabAvailable = await getTabByID(tab.id); if (!tabAvailable) { reject("Task interrupted due to the target tab is closed."); return; } chrome.tabs.sendMessage(tab.id, req, r => { // check error but do nothing. // do not interrupt promise chains even if error, or the task always fail when: // a tab is newly created, and the content scripts won't have time to initialize chrome.runtime.lastError; let flag = !cond || cond(r); if (log) console.log(log, flag ? '(OK)' : '(failed)'); if (flag) { resolve(r); } else { setTimeout(() => { loop(); }, interval); } }); } }); } chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { if (!message.action || !message.action.startsWith(EXT_NAME)) { return; } sendResponse("Calling from user pages is not allowed."); return; });