logger.js 8.39 KB
arcs_module(function(ARCS) {
    var Logger;

    var indexedDB = window.indexedDB;
    
    // two modes: websockets or indexeddb
    // the idea is to add a timestamp as well as a timestamp for the start of
    // the component. 
    
    // we need to structure indexeddb, the key is the timestamp.
    // a simple websocket server may write down data in offline json file
    // for a start.
    // it might be great to be able to analyse and draw some graphs using the 
    // tools and libraries used by Mathieu (Mouttapa).
    // see flot charting library (based on canvas) or epoch (based on svg).
    
    
    // configuration: DB, name, table?, websocket, url?, 
    
    // the goal of this function is to transform the object into a structured 
    // data compliant with the logger
    var toStructuredData = function( obj) {
        var i, p, res;
        if (obj instanceof Function) {
            return undefined;
        }
        if (obj instanceof Array) {
            res = [];
            for (i= 0; i<obj.length; i++) {
                res.push(toStructuredData(obj[i]));
            }
            return res;
        }
        if (obj instanceof Object) {
            res = {};
            if (obj instanceof Event) {
                for(p in obj) {
                    if (! Event.prototype.hasOwnProperty(p)) {
                        res[p] = toStructuredData(obj[p]);
                    }
                }
            } else {
                for (p in obj) {
                    res[p] = toStructuredData(obj[p]);
                }
            }
            return res;
        }
        return obj;
    };

    
    Logger = ARCS.Component.create(
        function(obj) {
            var i;
            var self = this;
            var dbconfig;
            var server;
            var db;
            var ws;
            var dbversion;
            var request;
            var openDatabase;
                
            if (typeof obj !== "object") {
                console.error("[Logger] Wrong object structure at initialisation");
                return ;
            }

            /**********************************************************************
            * Creation of data needed for database
            *********************************************************************/
            if (obj.dbconfig != undefined)  {
                dbconfig = obj.dbconfig;
                dbconfig.name = dbconfig.name || "ARCS" ;
                dbconfig.table = dbconfig.table || "logtable";
                dbconfig.clear = dbconfig.clear || false;

                if (indexedDB === undefined) {
                    console.error("[Logger] IndexedDB extension not available");
                    return;
                }
                
                var openDatabase = function ( version ) {
                    var request = indexedDB.open(dbconfig.name, version);
                    request.onerror = function(event) {
                        console.error("[Logger] Could not open database " + dbconfig.name);
                    };
                    request.onsuccess = function(event) {
                        db = request.result;
                        // let's check if the table is available. 
                        if (!db.objectStoreNames.contains(dbconfig.table)) {
                            // otherwise, we should trigger an update
                            dbversion = db.version;
                            db.close();
                            openDatabase(dbversion+1);
                        } else {
                            if (dbconfig.clear) {
                                var request2 = db.transaction([dbconfig.table],"readwrite").objectStore(dbconfig.table).clear();
                                request2.onsuccess = function(event) {
                                    self.emit("onDatabaseReady");
                                };
                                request2.onerror = function(event) {
                                    console.error("[Logger] Could not clear table " + dbconfig.table);
                                };
                            } else {
                                self.emit("onDatabaseReady");
                            }                            
                        }
                    };
                    request.onupgradeneeded = function(event) {
                        db = event.target.result;
                        var objectStore = db.createObjectStore(dbconfig.table, { autoIncrement : true});
                        objectStore.createIndex("timestamp", "timestamp", {unique : false});
                        objectStore.createIndex("event", "event", { unique: false});
                    };
                };
                // the line below should be called later
                //openDatabase();
            }
            
            
            if (obj.slots != undefined) {
                var arr = obj.slots;
                for (i=0; i< arr.length; i++) {
                    if (typeof arr[i] === "string") {
                        this.slots.push(arr[i]);
                        //TokenSender.prototype.slots.push(arr[i]);
                        this[arr[i]] = function( s ) {
                            return function() {
                                // we keep the "event" name i.e. the slot name
                                // and we construct an object with the surrounding data
                                var data = [], i, p, tmpobj ;

                                for (i = 0; i < arguments.length ; i++) {
                                    data.push(toStructuredData(arguments[i]));
                                }
                                
                                var obj = { timestamp : new Date().valueOf() , event: s, data: data };
                                if (db !== undefined) {
                                    try {
                                         var request = db.transaction([dbconfig.table], "readwrite").objectStore(dbconfig.table).add(obj);
                                         request.onerror = function (event) {
                                             console.error("[Logger] could not write data in table " + dbconfig.table);
                                         };
                                    } catch (e) {
                                        console.error("[Logger] problem pushing value in database ("+ e + "): " + JSON.stringify(obj));
                                    }
                                } 
                                if (ws !== undefined) {
                                    if (ws.readyState === WebSocket.OPEN) {
                                        try {
                                            ws.send(JSON.stringify(obj));
                                        } catch (e) {
                                            console.error("[Logger] problem pushing value through socket");
                                        }
                                    } 
                                } 
                            };
                        } (arr[i]);
                    }
                }
            }
            
            // few things should be located inside an init slot
            // this is mainly the preparation of the websocket client 
            // and the preparation of the database.
            // the idea is to start a little bit later events that could be sent
            this.initialise = function() {
                if (openDatabase !== undefined) {
                    openDatabase();
                }

                if (obj.server != undefined) {
                    // here we will create a connection to a websocket server
                    if (obj.server === "") {
                        obj.server = 'ws://' + window.location.hostname + ':8080';
                    }
                    
                    
                    ws = new WebSocket(obj.server);
                    ws.onopen = function() {
                        // may be we should put notifications
                        self.emit("onSocketReady");
                    };
                    ws.onerror = function() {
                        console.error("[Logger] Trouble opening web socket: "+ obj.server);
                    };            
                }
            };
            
        },
        ["initialise"],
        [ "onDatabaseReady","onSocketReady"]
    );
            
    return { Logger: Logger };
});