All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.rpc.brutusin-rpc.js Maven / Gradle / Ivy

/*
 * Copyright 2015 brutusin.org
 *
 * Licensed under the Apache License, Version 2.0 (the "SuperLicense");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *  
 * @author Ignacio del Valle Alles [email protected]
 */

if (typeof brutusin === "undefined") {
    window.brutusin = new Object();
} else if (typeof brutusin !== "object") {
    throw "brutusin global variable already exists";
}
(function () {
    if (!String.prototype.startsWith) {
        String.prototype.startsWith = function (searchString, position) {
            position = position || 0;
            return this.indexOf(searchString, position) === position;
        };
    }
    if (!String.prototype.endsWith) {
        String.prototype.endsWith = function (searchString, position) {
            var subjectString = this.toString();
            if (position === undefined || position > subjectString.length) {
                position = subjectString.length;
            }
            position -= searchString.length;
            var lastIndex = subjectString.indexOf(searchString, position);
            return lastIndex !== -1 && lastIndex === position;
        };
    }
    if (!String.prototype.includes) {
        String.prototype.includes = function () {
            'use strict';
            return String.prototype.indexOf.apply(this, arguments) !== -1;
        };
    }
    if (!String.prototype.format) {
        String.prototype.format = function () {
            var formatted = this;
            for (var i = 0; i < arguments.length; i++) {
                var regexp = new RegExp('\\{' + i + '\\}', 'gi');
                formatted = formatted.replace(regexp, arguments[i]);
            }
            return formatted;
        };
    }

    var rpc = new Object();
    brutusin["rpc"] = rpc;
    var crsfToken = getMeta("_csrf");
    var crsfHeader = getMeta("_csrf_header");

    function getMeta(name) {
        var metaTags = document.getElementsByTagName("meta");
        for (var i = 0; i < metaTags.length; i++) {
            if (metaTags[i].getAttribute("name") === name) {
                return metaTags[i].getAttribute("content");
            }
        }
        return null;
    }

    function createRpcRequest(service, input, id) {
        var req = new Object();
        req.jsonrpc = "2.0";
        if (typeof id !== 'undefined') {
            req.id = id;
        }
        req.params = input;
        req.method = service;
        return req;
    }

    rpc.initHttpEndpoint = function (endpoint, ping) {
        var proxy = new Object();
        rpc.getHttpEndpoint = function () {
            return proxy;
        };
        var queue = [];
        var services;

        ajax(function (response, status) {
            if (status === 200) {
                services = new Object();
                for (var i = 0; i < response.result.length; i++) {
                    services[response.result[i].id] = response.result[i];
                }
                for (var i = 0; i < queue.length; i++) {
                    var ajaxParam = queue[i];
                    proxy.ajax(ajaxParam);
                }
                queue = [];
            } else {
                throw JSON.stringify(response);
            }
        }, "rpc.http.services", null, null, "GET", "json");


        setInterval(function () {
            ajax(function (response, status) {
                if (status !== 200) {
                    throw JSON.stringify(response);
                }
            }, "rpc.http.ping", null, null, "GET", "json");
        }, ping ? ping : 60000);


        proxy.ajax = function (ajaxParam) {
            if (ajaxParam === null || typeof ajaxParam !== "object") {
                throw "ajax() parameter has to be an object";
            }
            if (services) {
                var httpMethod, responseType;
                if (ajaxParam.service) {
                    var service = services[ajaxParam.service];
                    if (!service) {
                        throw "Service not found: '" + ajaxParam.service + "'";
                    }
                    var httpMethod;
                    if (service.safe) {
                        httpMethod = "GET";
                    } else {
                        if (service.idempotent) {
                            httpMethod = "PUT";
                        } else {
                            httpMethod = "POST";
                        }
                    }
                    var responseType;
                    if (service.binaryResponse) {
                        responseType = "blob";
                    } else {
                        responseType = "json";
                    }
                } else {
                    httpMethod = "GET";
                    responseType = "json";
                }
                ajax(ajaxParam.load, ajaxParam.service, ajaxParam.input, ajaxParam.files, httpMethod, responseType, ajaxParam.progress);
            } else {
                queue[queue.length] = ajaxParam;
            }
        };
        return proxy;

        /**
         * Returns the upload order for the files by ascending size. This way the last one, that can be 
         * streamed directly in the server without going to disk, is the larger one.
         * @param {type} files
         * @returns {undefined}
         */
        function getOrder(files) {
            var keys = Object.keys(files).slice(0);
            keys.sort(
                    function (a, b) {
                        return files[a].size - files[b].size;
                    }
            );
            return keys;
        }

        function getAttachmentFileName(contentDisposition) {
            var filename;
            if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
                var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                var matches = filenameRegex.exec(contentDisposition);
                if (matches !== null && matches[1])
                    filename = matches[1].replace(/['"]/g, '');
            }
            return filename;
        }

        function ajax(load, service, input, files, httpMethod, responseType, progress) {
            var req = createRpcRequest(service, input);
            if (files) {
                httpMethod = "POST";
            }
            if (!responseType) {
                responseType = 'json';
            }
            var data;
            var xhr = new XMLHttpRequest();
            if (progress) {
                xhr.upload.addEventListener("progress", progress);
            }
            if (httpMethod === "GET") {
                var urlparam = "?jsonrpc=" + JSON.stringify(req);
                xhr.open(httpMethod, endpoint + urlparam, true);
            } else {
                data = new FormData();
                data.append("jsonrpc", JSON.stringify(req));
                if (files) {
                    var order = getOrder(files);
                    for (var i = 0; i < order.length; i++) {
                        var p = order[i];
                        data.append(p, files[p]);
                    }
                }
                xhr.open(httpMethod, endpoint, true);
                if (crsfToken && crsfHeader) {
                    xhr.setRequestHeader(crsfHeader, crsfToken);
                }
            }

            xhr.onload = function () {
                if (responseType === "blob" && this.status === 200) {
                    var type = xhr.getResponseHeader('Content-Type');
                    var blob = new Blob([this.response], {type: type});
                    if (load) {
                        load(blob, this.status, this.statusText);
                    } else {
                        var filename = getAttachmentFileName(xhr.getResponseHeader('Content-Disposition'));
                        var URL = window.URL || window.webkitURL;
                        var downloadUrl = URL.createObjectURL(blob);
                        if (filename) {
                            if (typeof window.navigator.msSaveBlob !== 'undefined') {
                                window.navigator.msSaveBlob(blob, filename);
                            } else {
                                // use HTML5 a[download] attribute to specify filename
                                var a = document.createElement("a");
                                // safari doesn't support this yet
                                if (typeof a.download === 'undefined') {
                                    window.location = downloadUrl;
                                } else {
                                    a.href = downloadUrl;
                                    a.download = filename;
                                    document.body.appendChild(a);
                                    a.click();
                                }
                            }
                        } else {
                            if (typeof window.navigator.msSaveOrOpenBlob !== 'undefined') {
                                window.navigator.msSaveOrOpenBlob(blob);
                            } else {
                                window.location = downloadUrl;
                            }
                        }

                        setTimeout(function () {
                            URL.revokeObjectURL(downloadUrl);
                        }, 100); // cleanup
                    }
                } else { // json
                    if (load) {
                        var response;
                        if (typeof this.response === "string") {
                            eval("response=" + this.response);
                        } else {
                            response = this.response;
                        }
                        load(response, this.status, this.statusText);
                    }
                }
            };
            xhr.onerror = function (e) {
                load({
                    "jsonrpc": "2.0",
                    "error": {
                        "code": -32003,
                        "message": "Connection error",
                        "meaning": "Cannot connect to server"
                    }
                });
            };
            xhr.responseType = responseType;
            xhr.send(data);
        }
    };

    rpc.initWebsocketEndpoint = function (endpoint, ping) {
        var proxy = new Object();
        rpc.getWebsocketEndpoint = function () {
            return proxy;
        };
        var queue = new Array();
        var services;
        var url;
        if (endpoint.startsWith("wss:") || endpoint.startsWith("ws:")) {
            url = endpoint;
        } else {
            if (window.location.protocol === "https:") {
                url = "wss:";
            } else {
                url = "ws:";
            }
            if (endpoint.startsWith("/")) {
                url += "//" + window.location.host + endpoint;
            } else {
                url += "//" + window.location.host + window.location.pathname + endpoint;
            }
        }
        var ws;
        reconnect();
        var lastReqId = 0;
        var rpcCallbacks = new Object();
        var topicCallbacks = new Object();

        function reconnect() {
            ws = new WebSocket(url);
            ws.onmessage = function (event) {
                var response;
                eval("response=" + event.data);
                if (response.jsonrpc) {
                    var callback = rpcCallbacks[response.id];
                    delete rpcCallbacks[response.id];
                    callback(response);
                } else {
                    var callback = topicCallbacks[response.topic];
                    callback(response.message);
                }
            };
            for (var topic in topicCallbacks) {
                if (topicCallbacks.hasOwnProperty(topic)) {
                    proxy.exec({
                        service: "rpc.topics.subscribe",
                        input: {id: topic}
                    });
                }
            }
        }

        function exec(load, service, input) {
            var reqId;
            if (load) {
                reqId = ++lastReqId;
                rpcCallbacks[reqId] = load;
            }
            var req = createRpcRequest(service, input, reqId);

            var reconnecting = false;

            function sendMessage(msg) {
                if (ws.readyState === 1) {
                    ws.send(msg);
                    reconnecting = false;
                } else if (ws.readyState === 0) {
                    setTimeout(
                            function () {
                                sendMessage(msg);
                            },
                            100);
                } else {
                    if (!reconnecting) {
                        reconnect();
                        reconnecting = true;
                        sendMessage(msg);
                    } else {
                        if (load) {
                            load({
                                "jsonrpc": "2.0",
                                "id": reqId,
                                "error": {
                                    "code": -32003,
                                    "message": "Connection error",
                                    "meaning": "Cannot connect to server",
                                    "data": "Server connection lost. Try reloading the page"
                                }
                            });
                        }
                    }
                }
            }
            sendMessage(JSON.stringify(req));
        }

        exec(function (response) {
            services = new Object();
            for (var i = 0; i < response.result.length; i++) {
                services[response.result[i].id] = response.result[i];
            }
            for (var i = 0; i < queue.length; i++) {
                var execParam = queue[i];
                proxy.exec(execParam);
            }
            queue = [];
        }, "rpc.wskt.services");

        setInterval(function () {
            exec(function (response) {
                if (response.error) {
                    throw response.error.meaning + (response.error.data ? (". " + response.error.data) : "");
                }
            }, "rpc.wskt.ping");
        }, ping ? ping : 30000);

        proxy.subscribe = function (topic, callback) {
            topicCallbacks[topic] = callback;
            proxy.exec({
                service: "rpc.topics.subscribe",
                input: {id: topic}
            });
        };
        proxy.unsubscribe = function (topic) {
            delete topicCallbacks[topic];
            proxy.exec({
                service: "rpc.topics.unsubscribe",
                input: {id: topic}
            });
        };
        proxy.exec = function (execParam) {
            if (execParam === null || typeof execParam !== "object") {
                throw "exec() parameter has to be an object";
            }
            if (!execParam.service) {
                throw "execParam.service is required";
            }
            if (services) {
                var service = services[execParam.service];
                if (!service) {
                    throw "Service not found: '" + execParam.service + "'";
                }
                exec(execParam.load, execParam.service, execParam.input);
            } else {
                queue[queue.length] = execParam;
            }
        };
        return proxy;
    };

}());




© 2015 - 2025 Weber Informatics LLC | Privacy Policy