Search code examples
javascriptinternet-explorerbrowser-extensioncrossrider

How can we send big objects from the background to the active tab in CrossRider?


We are using CrossRider to develop an extension for Internet Explorer. Our extension has code that sends a message to the background, and the background sends a reply and calls a callback function. This works in my computer with Internet Explorer 11, but in my Friend Tom's computer (also with Internet Explorer 11) it doesn't work - the callback is not called in his computer. What is the problem and how do we fix it to work in any computer? Here is the relevant code:

_base.js:

alert("[ContentBase::getData] >>>>>"); // This happens in any computer.
var request = {command: 'get', webmail: thisObj.mContentType, param: param, type: type, contentType: contentType};
thisObj.sendRequest(request, function(response) {
    alert("[ContentBase::getData] received data >>>>>"); // This doesn't happen in Tom's computer.
    if (typeof(callback) === 'function') {
        callback(response);
    }
});

utils.js:

this.sendRequest = function(request, callback) {
    if (typeof(callback) !== 'function') {
        callback = function(response) {};
    }

    switch (Sys.platform) {
        case 'crossrider':
            var message = {request: request, message_id: Math.floor((Math.random() * 900000000000000) + 100000000000000)};
            if (typeof thisObj.mCallbackMap === 'undefined') {
                thisObj.mCallbackMap = {};
                appAPI.message.addListener({channel: "message_from_background"}, function(message) {
                    if (typeof thisObj.mCallbackMap[message.message_id] === 'function') {
                        thisObj.mCallbackMap[message.message_id](message.response);
                        delete thisObj.mCallbackMap[message.message_id];
                    }
                });
            }

            (function(callback_inner) {
                thisObj.mCallbackMap[message.message_id] = function(response) {
                    if (typeof(callback_inner) === 'function') {
                        callback_inner(response);
                    }
                };
            })(callback);

            appAPI.message.toBackground(message, {channel: "message_to_background"});
            break;
    }
};

background.js:

appAPI.message.addListener({channel: "message_to_background"}, function(params) {
    MsgHandler.handle(params.request, undefined, function(responseParams) {
        appAPI.message.toActiveTab({'message_id': params.message_id, 'response': responseParams}, {channel: "message_from_background"});
    });
});

msgHandler.js:

this.handle = function(request, sender, callback_out) {
    function callback(response) {
        if (typeof(callback_out) === 'function') {
            callback_out(response);
        }
    }

    switch (request.command) {
        case "get":
            switch (request.type) {
                case "all":
                    var data = Controller.getData();
                    alert("[MsgHandler::handle] get / all, data.length = " + JSON.stringify(data).length + ", data = " + JSON.stringify(data)); // This happens in any computer.
                    callback({data: data});
                    break;
            }
            break;
    }
    return true;    //this return is needed for chrome in order to execute callbacks

};

Sys.platform is always equal to 'crossrider'.

Update: When JSON.stringify(data).length was 5981 bytes the message was received, but when it was 10157 bytes the message was not received by the active tab (with appAPI.message.toActiveTab). What is the limit on the size of objects sent from the background and how do we send big objects to the tabs (up to 100KB)?

Our Extension ID is 43889. I'm using Internet Explorer 11 but this extension should work on all versions of Internet Explorer.

By the way, other calls from the background work, only this specific call doesn't work. We tried several times in Tom's computer and it never works.

Edit: I created a simple extension with the same problem, Extension ID is 67708. Here is the code of the simple extension:

extension.js:

appAPI.ready(function($) {
    alert("appAPI.platform = " + appAPI.platform);
    if (appAPI.platform === 'IE') {

        appAPI.message.addListener({channel: "message_from_background"}, function(message) {
            alert("message_from_background received, message_id = " + message.message_id + ", message.length = " + JSON.stringify(message).length + ", message = " + JSON.stringify(message));
        });

        appAPI.message.toBackground({}, {channel: "init_background"});
    }
});

background.js:

appAPI.ready(function($) {
    alert("appAPI.platform = " + appAPI.platform);
    if (appAPI.platform === 'IE') {
        var ready = false;
        appAPI.message.addListener({channel: "init_background"}, function(params) {
            if (ready === false) {
                alert('init_background, ready = ' + ready);
                ready = true;

                var message_id = 9999;
                var responseParams = {'a': 1, 'b': 2, 'c': 3};
                alert('sending message to active tab, message_id = ' + message_id + ', responseParams.length = ' + JSON.stringify(responseParams).length);
                appAPI.message.toActiveTab({'message_id': message_id, 'response': responseParams}, {channel: "message_from_background"});

                var message_id = 9998;
                var responseParams = {
                    // a big object
                };
                alert('sending message to active tab, message_id = ' + message_id + ', responseParams.length = ' + JSON.stringify(responseParams).length);
                appAPI.message.toActiveTab({'message_id': message_id, 'response': responseParams}, {channel: "message_from_background"});

                alert(appAPI.platform);
            }
        });
    }
});

When JSON.stringify(responseParams).length is 19 bytes, the message is received by the active tab, but when it's 10576 bytes, the message is not received.


Solution

  • OK, since the size of objects in the messages is limited to 8000 bytes, I divided the objects to packets of size up to 5000 bytes. Here is the code of my extension:

    utils.js:

    this.sendRequest = function(request, callback) {
        if (typeof(callback) !== 'function') {
            callback = function(response) {};
        }
    
        switch (Sys.platform) {
            case 'crossrider':
                var message = {request: request, message_id: Math.floor((Math.random() * 900000000000000) + 100000000000000)};
                if (typeof thisObj.mCallbackMap === 'undefined') {
                    thisObj.mCallbackMap = {};
                    thisObj.mResponseObject = {};
                    appAPI.message.addListener({channel: "message_from_background"}, function(message) {
                        alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", checking message...");
                        if ((typeof(message) === 'object') && (!(message === null)) && (typeof(message['divided_object_length']) === 'number')) {
                            if (typeof thisObj.mResponseObject[message.message_id] === 'undefined') {
                                thisObj.mResponseObject[message.message_id] = {}
                            }
                            var limit = message['divided_object_length'];
                            var packet_id = message['packet_id'];
                            var packet = message['packet'];
                            alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", limit = " + limit + ", packet_id = " + packet_id + "...");
                            thisObj.mResponseObject[message.message_id]['packet_' + packet_id] = packet;
                            var message_is_ready = true;
                            for (var packet_id = 0; packet_id < limit; packet_id++) {
                                if (typeof thisObj.mResponseObject[message.message_id]['packet_' + packet_id] === 'undefined') {
                                    var message_is_ready = false;
                                }
                            }
                            if (message_is_ready) {
                                delete message['divided_object_length'];
                                delete message['packet_id'];
                                delete message['packet'];
                                var s = '';
                                for (var packet_id = 0; packet_id < limit; packet_id++) {
                                    s += thisObj.mResponseObject[message.message_id]['packet_' + packet_id];
                                }
                                message.response = JSON.parse(s);
                                delete thisObj.mResponseObject[message.message_id];
                            }
                        } else {
                            var message_is_ready = true;
                        }
                        alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", message_is_ready = " + message_is_ready + "...");
                        if (message_is_ready) {
                            if (typeof thisObj.mCallbackMap[message.message_id] === 'function') {
                                alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", calling function...");
                                thisObj.mCallbackMap[message.message_id](message.response);
                                delete thisObj.mCallbackMap[message.message_id];
                            }
                        }
                    });
                }
    
                (function(callback_inner) {
                    thisObj.mCallbackMap[message.message_id] = function(response) {
                        alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", checking inner function...");
                        if (typeof(callback_inner) === 'function') {
                            alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", calling inner function...");
                            callback_inner(response);
                        }
                    };
                })(callback);
    
                appAPI.message.toBackground(message, {channel: "message_to_background"});
                break;
        }
    };
    

    background.js:

    appAPI.message.addListener({channel: "message_to_background"}, function(params) {
        alert("background.js :: message received, params = " + JSON.stringify(params));
    
        MsgHandler.handle(params.request, undefined, function(responseParams) {
            alert("background.js :: message received callback, message_id = " + params.message_id + ", sending response.");
    
            var s = JSON.stringify(responseParams);
            if ((typeof(s) === "string") && (s.length > 5000)) {
                var limit = Math.floor((s.length - 1) / 5000) + 1;
                alert("background.js :: message received callback, message_id = " + params.message_id + ", sending response, s.length = " + s.length + ", limit = " + limit + ".");
                for (var packet_id = 0; packet_id < limit; packet_id++) {
                    var message = {};
                    message['divided_object_length'] = limit;
                    message['message_id'] = params.message_id;
                    message['packet_id'] = packet_id;
                    message['packet'] = s.substr(packet_id * 5000, 5000);
                    appAPI.message.toActiveTab(message, {channel: "message_from_background"});
                }
            } else {
                appAPI.message.toActiveTab({'message_id': params.message_id, 'response': responseParams}, {channel: "message_from_background"});
            }
        });
    });
    

    The rest of the code is the same like in my question (the alerts are just for debugging, we remove them in production).