FrenchYeti/dexcalibur

View on GitHub
inspectors/Saver/SaveManager.js

Summary

Maintainability
F
6 days
Test Coverage
const _fs_ = require("fs");
const _path_ = require("path");

const Logger = require('../../src/Logger.js')(); 
const DB = require('../../connectors/inmemory/InMemoryDb.js');


/**
 * Useful with 'inmemory' DB
 *
 * @class
 */
class SaveManager
{
    static EXT = '.bkp';
    static FNAME = 'db.json';

    static T_CLASS = 1;
    static T_METHOD = 2;
    static T_FIELD = 3;
    static T_HOOK = 4;
    static T_HOOK_STATUS = 5;

    static __self = null;


    static getInstance(pContext){
        if(SaveManager.__self === null){
            SaveManager.__self = new SaveManager(pContext);
        }

        return SaveManager.__self;
    }

    constructor(pContext){
        this.context = pContext;
        this._ready = false;
        this._enabled = true;
        this._filepath = null;
        this._db = new DB.InMemoryDb(pContext);

        this.queue = {
            method:{},
            field:{},
            class:{},
            hooks: {},
            "hooks-status": {}
        };
        this.queueSize = {
            method:0,
            field:0,
            class:0,
            hooks:0,
            "hooks-status": 0
        };


        // init db
        this.initInternalDB();

        // init path
        this._filepath = _path_.join(
            this.context.workspace.getSaveDir(),
            SaveManager.FNAME
        );
    }

    isReady(){
        return this._ready;
    }

    disable(){
        this._enabled = false;
    }

    enable(){
        this._enabled = true;
    }

    isEnabled(){
        return (this._enabled === true);
    }

    addToQueue(pType, pKey, pVal){
        if(this.queue[pType] !== undefined){
            this.queue[pType][pKey] = pVal;
            this.queueSize[pType]++;
        }
    }

    removeFromQueue(pType, pKey){
        let o={};

        if(this.queue[pType] !== undefined){
            this.queueSize[pType] = 0;
            for(let i in this.queue[pType]){
                if(i !== pKey){
                    o[i] = this.queue[pType][i];
                    this.queueSize[pType]++;
                }
            }
        }
        this.queue[pType] = o;
    }

    getFromQueue(pType, pKey){
        if(this.queue[pType] !== undefined){
            if(this.queue[pType][pKey] !== undefined){
                return this.queue[pType][pKey];
            }else{
                return null;
            }
        }else{
            return null;
        }
    }

    initInternalDB(){
        this._db.newCollection("classes");
        this._db.newCollection("fields");
        this._db.newCollection("methods");
        this._db.newCollection("hooks");
        this._db.newCollection("hooks-status");
    }
/*
    newAlias( pType, pObject){
        switch(pType){
            case SaveManager.T_CLASS:
                this._db.getIndex("classes").setEntry();
                break;
            case SaveManager.T_FIELD:
                this._db.getIndex("fields").setEntry();
                break;
            case SaveManager.T_METHOD:
                this._db.getIndex("methods").setEntry();
                break;
        }
    }*/

    updateAlias( pType, pObject){

        switch(pType){
            case SaveManager.T_CLASS:
                this._db.getIndex("classes").addEntry(pObject.signature(),pObject);
                break;
            case SaveManager.T_METHOD:
                this._db.getIndex("methods").addEntry(pObject.signature(),pObject);
                break;
            case SaveManager.T_FIELD:
                this._db.getIndex("fields").addEntry(pObject.signature(),pObject);
                break;
        }
    }

    updateHook( pObject){
        this._db.getIndex("hooks").addEntry(pObject.hook.id, pObject.hook);
    }

    
    updateHookStatus( pHook, pEnable){
        this._db.getIndex("hooks-status").addEntry(pHook.id, pEnable);
    }

    import(pData){
        let index = null, o=null, hook=null, qflag=0;

        if(pData.classes.size > 0){
            index = this._db.getIndex("classes");
            for(let k in pData.classes.data){
                o = this.context.find.get.class(k);
                if(o != null){
                    o.setAlias(pData.classes.data[k].alias);
                    this.updateAlias(k, o);
                }else{
//                    this.queue.class[k] = pData.classes.data[k];
                    this.addToQueue("class",k,pData.classes.data[k]);
                    qflag++;
                }
            }
        }

        if(pData.methods.size > 0){
            index = this._db.getIndex("methods");
            for(let k in pData.methods.data){
                o = this.context.find.get.method(k);
                if(o != null){
                    o.setAlias(pData.methods.data[k].alias);
                    this.updateAlias(k, o);
                }else{
//                    this.queue.method[k] = (pData.methods.data[k]);
                    this.addToQueue("method",k,pData.methods.data[k]);
                    qflag++;
                }
            }
        }

        if(pData.fields.size > 0){
            index = this._db.getIndex("fields");
            for(let k in pData.fields.data){
                o = this.context.find.get.field(k);
                if(o != null){
                    o.setAlias(pData.fields.data[k].alias);
                    this.updateAlias(k, o);
                }else{
            //        this.queue.field[k] = (pData.fields.data[k]);
                    this.addToQueue("field",k,pData.fields.data[k]);
                    qflag++;
                }
            }
        }

        if(pData.hooks.size > 0){
            index = this._db.getIndex("hooks");
            for(let k in pData.hooks.data){
                
                o = this.context.find.get.method(pData.hooks.data[k].method);
                if(o != null){
                    // search if the hook already exists
                    hook = this.context.hook.getProbe(o);
                    
                    // if thereis not hook, call the hook manager and generate one
                    if(hook == null){
                        hook = this.context.hook.probe(o);
                    }

                    // update the current hook with the imported data
                    hook.updateWith(pData.hooks.data[k].hook, o);
                    this.updateHook({ hook:hook });
                }else{
                   // this.queue.hooks[k] = (pData.hooks.data[k]);
                    //console.log("test : ",pData.hooks.data[k].method);
                    this.addToQueue("hooks",k,pData.hooks.data[k]);
                    qflag++;
                }
            }
        }

        if(pData["hooks-status"].size > 0){
            index = this._db.getIndex("hooks-status");
            for(let k in pData["hooks-status"].data){

                hook = this.context.hook.getHookByID(k);
                if(hook != null){
                    if(pData["hooks-status"].data[k].enable == false){
                        this.context.bus.prevent("probe.disable");
                        hook.disable();
                        this.updateHookStatus(hook, false);
                    }else{
                        this.context.bus.prevent("probe.enable");
                        hook.enable();
                        this.updateHookStatus(hook, true);
                    }
                }else{
         //           this.queue["hooks-status"][k] = (pData["hooks-status"].data[k]);
                    this.addToQueue("hooks-status",k,pData.hooks.data[k]);
                    qflag++;
                }
            }
        }

        if(qflag>0){
            Logger.error("[SAVE] "+qflag+" elements have not been imported. Queued ..");
        }else
            Logger.info("[SAVE] All elements have been imported ...");
        //console.log(this.queue);

        this.context.bus.unprevent("probe.disable")
        this.context.bus.unprevent("probe.enable")
    }

    save(){
        let data = this.export();
        this.write(
            this._filepath,
            data
        );
    }

    export(pExclude=null){
        let data={}, coll=null, pData=null;
        let self=this;

        data.methods = {data:{}, size:self._db.getIndex("methods").size()};
        data.fields = {data:{}, size:self._db.getIndex("fields").size()};
        data.classes = {data:{}, size:self._db.getIndex("classes").size()};
        data.hooks = {data:{}, size:self._db.getIndex("hooks").size()};
        data["hooks-status"] = {data:{}, size:self._db.getIndex("hooks-status").size()};

        //if(this.queue.fields)

        if(this.queueSize.fields > 0){
            for(let i in this.queue.fields){
                data.fields.data[i] = {
                    type: SaveManager.T_FIELD,
                    alias: this.queue.fields[i].alias
                };
            }
        }
        if(this.queueSize.methods > 0){
            for(let i in this.queue.methods){
                data.methods.data[i] = {
                    type: SaveManager.T_METHOD,
                    alias: this.queue.methods[i].alias
                };
            }
        }
        if(this.queueSize.classes > 0){
            for(let i in this.queue.classes){
                data.classes.data[i] = {
                    type: SaveManager.T_CLASS,
                    alias: this.queue.classes[i].alias
                };
            }
        }
        if(this.queueSize.hooks > 0){
            for(let i in this.queue.hooks){
                data.hooks.data[i] = {
                    type: SaveManager.T_HOOK,
                    alias: this.queue.hooks[i].alias
                };
            }
        }
        if(this.queueSize["hooks-status"] > 0){
            for(let i in this.queue["hooks-status"]){
                data["hooks-status"].data[i] = {
                    type: SaveManager.T_HOOK_STATUS,
                    enable: this.queue["hooks-status"][i]
                };
            }
        }

        if(data.fields.size > 0){
            coll = self._db.getIndex("fields");
            coll.map(function(ref,obj){
                data.fields.data[ref] = {
                    type: SaveManager.T_FIELD,
                    alias: obj.getAlias()
                };
            });
        }

        if(data.methods.size > 0){
            coll = self._db.getIndex("methods");
            coll.map(function(ref,obj){
                data.methods.data[ref] = {
                    type: SaveManager.T_METHOD,
                    alias: obj.getAlias()
                };
            });
        }

        if(data.classes.size > 0){
            coll = self._db.getIndex("classes");
            coll.map(function(ref,obj){
                data.classes.data[ref] = {
                    type: SaveManager.T_CLASS,
                    alias: obj.getAlias()
                };
            });
        }

        if(data.hooks.size > 0){
            coll = self._db.getIndex("hooks");
            coll.map(function(ref,obj){
                data.hooks.data[ref] = {
                    type: SaveManager.T_HOOK,
                    id: ref,
                    hook: obj.toJsonObject(),
                    method: obj.method.signature()
                };
            });
        }

        if(data["hooks-status"].size > 0){
            coll = self._db.getIndex("hooks-status");
            coll.map(function(ref,obj){
                data["hooks-status"].data[ref] = {
                    type: SaveManager.T_HOOK_STATUS,
                    enable: obj
                };
            });
        }
        
        pData = JSON.stringify(data);
        
       return pData;
    }

    /**
     * 
     * @param {Path} pFilepath File path where data should be write 
     * @param {Object} pData Data to write
     */
    write(pFilepath, pData){
        let self = this;
        if(_fs_.existsSync(pFilepath)){
            if(_fs_.existsSync(pFilepath+SaveManager.EXT))
                 _fs_.unlinkSync(pFilepath+SaveManager.EXT);

            _fs_.renameSync(pFilepath, pFilepath+SaveManager.EXT);
        }
            
        _fs_.writeFile(pFilepath, pData, (err)=>{
            if(err) 
                throw new Error(err);

            self.context.trigger({
                type: "save.write",
                data: self
            });
        });           
    }

    restore(){
        let self=this;
        _fs_.exists(this._filepath, function(pExists){

            //console.log(self._filepath+" exists : "+pExists);
            if(pExists){
                _fs_.readFile(
                    self._filepath, {encoding:'utf-8'}, 
                    function(err,pData){
                        if(!err && pData.length>0){
                            self.import(JSON.parse(pData));
                        }

                });
            }
        });
    }
}

module.exports = SaveManager;