File indexing completed on 2024-04-28 05:32:50

0001 /*
0002     Copyright (C) 2017 Kai Uwe Broulik <kde@privat.broulik.de>
0003 
0004     This program is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU General Public License as
0006     published by the Free Software Foundation; either version 3 of
0007     the License, or (at your option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 var port;
0019 
0020 var callbacks = {}; // TODO rename to "portCallbacks"?
0021 var runtimeCallbacks = {};
0022 
0023 let currentMessageSerial = 0;
0024 let pendingMessageReplyResolvers = {};
0025 
0026 // Callback is called with following arguments (in that order);
0027 // - The actual message data/payload
0028 // - The name of the action triggered
0029 function addCallback(subsystem, action, callback) // TODO rename to "addPortCallbacks"?
0030 {
0031     if (Array.isArray(action)) {
0032         action.forEach(function(item) {
0033             addCallback(subsystem, item, callback);
0034         });
0035         return;
0036     }
0037 
0038     if (!callbacks[subsystem]) {
0039         callbacks[subsystem] = {};
0040     }
0041     callbacks[subsystem][action] = callback;
0042 }
0043 
0044 function sendPortMessage(subsystem, event, payload)
0045 {
0046     // why do we put stuff on root level here but otherwise have a "payload"? :(
0047     var message = payload || {}
0048     message.subsystem = subsystem;
0049     message.event = event;
0050 
0051     if (port) {
0052         port.postMessage(message);
0053     }
0054 }
0055 
0056 function sendPortMessageWithReply(subsystem, event, payload)
0057 {
0058     return new Promise((resolve, reject) => {
0059         if (!port) {
0060             return reject("UNSUPPORTED_OS");
0061         }
0062 
0063         let message = payload || {};
0064         message.subsystem = subsystem;
0065         message.event = event;
0066         ++currentMessageSerial;
0067         if (currentMessageSerial >= Math.pow(2, 31) - 1) { // INT_MAX
0068             currentMessageSerial = 0;
0069         }
0070         message.serial = currentMessageSerial;
0071 
0072         port.postMessage(message);
0073 
0074         pendingMessageReplyResolvers[message.serial] = resolve;
0075     });
0076 }
0077 
0078 // Callback is called with following arguments (in that order);
0079 // - The actual message data/payload
0080 // - Information about the sender of the message (including tab and frameId)
0081 // - The name of the action triggered
0082 // Return a Promise from the callback if you wish to send a reply to the sender
0083 function addRuntimeCallback(subsystem, action, callback)
0084 {
0085     if (action.constructor === Array) {
0086         action.forEach(function(item) {
0087             addRuntimeCallback(subsystem, item, callback);
0088         });
0089         return;
0090     }
0091 
0092     if (!runtimeCallbacks[subsystem]) {
0093         runtimeCallbacks[subsystem] = {};
0094     }
0095     runtimeCallbacks[subsystem][action] = callback;
0096 }
0097 
0098 // returns an Object which only contains values for keys in allowedKeys
0099 function filterObject(obj, allowedKeys) {
0100     var newObj = {}
0101 
0102     // I bet this can be done in a more efficient way
0103     for (key in obj) {
0104         if (obj.hasOwnProperty(key) && allowedKeys.indexOf(key) > -1) {
0105             newObj[key] = obj[key];
0106         }
0107     }
0108 
0109     return newObj;
0110 }
0111 
0112 // filters objects within an array so they only contain values for keys in allowedKeys
0113 function filterArrayObjects(arr, allowedKeys) {
0114     return arr.map(function (item) {
0115         return filterObject(item, allowedKeys);
0116     });
0117 }
0118 
0119 chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
0120     // TODO check sender for privilege
0121 
0122     var subsystem = message.subsystem;
0123     var action = message.action;
0124 
0125     if (!subsystem || !action) {
0126         return false;
0127     }
0128 
0129     if (runtimeCallbacks[subsystem] && runtimeCallbacks[subsystem][action]) {
0130         let result = runtimeCallbacks[subsystem][action](message.payload, sender, action);
0131 
0132         // Not a promise
0133         if (typeof result !== "object" || typeof result.then !== "function") {
0134             return false;
0135         }
0136 
0137         result.then((response) => {
0138             sendResponse(response);
0139         }, (err) => {
0140             sendResponse({
0141                 rejected: true,
0142                 message: err
0143             });
0144         });
0145 
0146         return true;
0147     }
0148 
0149     console.warn("Don't know what to do with runtime message", subsystem, action);
0150     return false;
0151 });