File: extension-utils.js

package info (click to toggle)
plasma-browser-integration 6.3.4-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 2,044 kB
  • sloc: cpp: 2,989; javascript: 2,444; xml: 142; python: 77; sh: 46; makefile: 16
file content (151 lines) | stat: -rw-r--r-- 4,463 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
    Copyright (C) 2017 Kai Uwe Broulik <kde@privat.broulik.de>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 3 of
    the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

var port;

var callbacks = {}; // TODO rename to "portCallbacks"?
var runtimeCallbacks = {};

let currentMessageSerial = 0;
let pendingMessageReplyResolvers = {};

// Callback is called with following arguments (in that order);
// - The actual message data/payload
// - The name of the action triggered
function addCallback(subsystem, action, callback) // TODO rename to "addPortCallbacks"?
{
    if (Array.isArray(action)) {
        action.forEach(function(item) {
            addCallback(subsystem, item, callback);
        });
        return;
    }

    if (!callbacks[subsystem]) {
        callbacks[subsystem] = {};
    }
    callbacks[subsystem][action] = callback;
}

function sendPortMessage(subsystem, event, payload)
{
    // why do we put stuff on root level here but otherwise have a "payload"? :(
    var message = payload || {}
    message.subsystem = subsystem;
    message.event = event;

    if (port) {
        port.postMessage(message);
    }
}

function sendPortMessageWithReply(subsystem, event, payload)
{
    return new Promise((resolve, reject) => {
        if (!port) {
            return reject("UNSUPPORTED_OS");
        }

        let message = payload || {};
        message.subsystem = subsystem;
        message.event = event;
        ++currentMessageSerial;
        if (currentMessageSerial >= Math.pow(2, 31) - 1) { // INT_MAX
            currentMessageSerial = 0;
        }
        message.serial = currentMessageSerial;

        port.postMessage(message);

        pendingMessageReplyResolvers[message.serial] = resolve;
    });
}

// Callback is called with following arguments (in that order);
// - The actual message data/payload
// - Information about the sender of the message (including tab and frameId)
// - The name of the action triggered
// Return a Promise from the callback if you wish to send a reply to the sender
function addRuntimeCallback(subsystem, action, callback)
{
    if (action.constructor === Array) {
        action.forEach(function(item) {
            addRuntimeCallback(subsystem, item, callback);
        });
        return;
    }

    if (!runtimeCallbacks[subsystem]) {
        runtimeCallbacks[subsystem] = {};
    }
    runtimeCallbacks[subsystem][action] = callback;
}

// returns an Object which only contains values for keys in allowedKeys
function filterObject(obj, allowedKeys) {
    var newObj = {}

    // I bet this can be done in a more efficient way
    for (key in obj) {
        if (obj.hasOwnProperty(key) && allowedKeys.indexOf(key) > -1) {
            newObj[key] = obj[key];
        }
    }

    return newObj;
}

// filters objects within an array so they only contain values for keys in allowedKeys
function filterArrayObjects(arr, allowedKeys) {
    return arr.map(function (item) {
        return filterObject(item, allowedKeys);
    });
}

chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    // TODO check sender for privilege

    var subsystem = message.subsystem;
    var action = message.action;

    if (!subsystem || !action) {
        return false;
    }

    if (runtimeCallbacks[subsystem] && runtimeCallbacks[subsystem][action]) {
        let result = runtimeCallbacks[subsystem][action](message.payload, sender, action);

        // Not a promise
        if (typeof result !== "object" || typeof result.then !== "function") {
            return false;
        }

        result.then((response) => {
            sendResponse(response);
        }, (err) => {
            sendResponse({
                rejected: true,
                message: err
            });
        });

        return true;
    }

    console.warn("Don't know what to do with runtime message", subsystem, action);
    return false;
});