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