Esempio n. 1
0
module.exports = Eventer.extend({

    init: function(task, worker) {
        this.worker = worker;
        this.task = task;
        this.ID = task.ID;
        this.updating = {};
        this.started = false;

        var self = this;
        this.done = _.after(3,function() {
            self.emit('loaded.all', {updating: self.updating});
            if(_(self.updating).size() > 0){
                self.updated = _.after(_(self.updating).size(), function() {
                    self.calculateRatings();
                });
            }
        });
    },

    startLoading: function() {
        this.started = true;
        this.getPlayerInfo();
        this.getPlayerStats();
        this.getPlayerTanks();
    },

    setPlayerInfo: function(player) {
        if(!player){
            player = this.worker.Players.new({id: this.ID});
        }
        this.player = player;
        this.emit('loaded.info', player.getData());
        this.done();
    },

    getPlayerInfo: function() {
        var self = this;
        this.worker.Players.find(this.ID, function(err, player){
            self.setPlayerInfo(player);
        });
    },

    setPlayerStats: function(stats) {
        var self = this;
        if(!stats){
            stats = this.worker.PlayerStats.new({player_id: this.ID});
        }
        this.stats = stats;
        if(stats.needsUpdate()){
            this.updating.stats = true;
            this.updating.info = true;
            this.emit('update.info', function(event, data) {
                self.updateStats(data);
            });
        }
        this.emit('loaded.stats', stats.getData());
        this.done();
    },

    getPlayerStats: function() {
        var self = this;
        this.worker.PlayerStats.findByPlayerID(this.ID, function(err, stats){
             self.setPlayerStats(stats);
        });
    },

    setPlayerTanks: function(tanks) {
        var self = this;
        if(!tanks){
            tanks = this.worker.PlayerTankCollections.new({p: this.ID});
        }
        this.tanks = tanks;
        if(tanks.needsUpdate()){
            this.updating.tanks = true;
            this.emit('update.tanks', function(event, data) {
                self.updateTanks(data);
            });
        }
        this.emit('loaded.tanks', tanks.getData());
        this.done();
    },

    getPlayerTanks: function() {
        var self = this;
        this.worker.PlayerTankCollections.findByPlayerID(this.ID, function(err, tanks){
            self.setPlayerTanks(tanks);
        });
    },

    updateTanks: function(data) {
        var self = this;
        this.tanks.update(data, function() {
            self.emit('updated.tanks', self.tanks.getData());
            self.updated();
        });
    },

    updateStats: function(data) {
        var self = this;
        this.player.update(data, function() {
            self.emit('updated.info', self.player.getData());
            self.updated();
        });
        this.stats.update(data.statistics, function() {
            self.emit('updated.stats', self.stats.getData());
            self.updated();
        });
    },

    calculateRatings: function() {
        var self = this;
        this.stats.average_tier = this.tanks.getAverageTier();
        this.stats.expected_values = this.tanks.getExpectedValues();
        this.stats.calcWN7();
        this.stats.calcEFR();
        this.stats.calcWN8();
        this.stats.sc3 = this.stats.wn7/1500*this.tanks.base_score;
        this.stats.saveAll(function() {
            self.emit('updated.ratings', self.stats.getData());
            self.emit('updated.all');
        });
    }

});
module.exports = Eventer.extend({
    init: function(options){
        this.tasks = {};
        this.options = options;
    },

    setModels: function(models) {
        this.models = models;
        _.each(this.models,  function(model, name) {
            this[name] = model;
        },this);
    },

    setTask: function(task, callback) {
        var self = this;

        var taskID = _.keys(task)[0];
        task = task[taskID];
        if(!task){
            console.log('Set task, but it is undefined:',taskID);
            return;
        }
        this.Clans.inRegion(task.region,{order: 'id',limit: [task.skip, task.limit]}, function(err, clans) {
            var goodClans = [];

            _.each(clans, function(clan){
                if(clan.status > -1){
                    goodClans.push(clan);
                }
            });
            var count = goodClans.length;
            var done = 0;
            _.each(goodClans, function(clan){
                self.once('clans.'+clan.id+'.updated', function(){
                    done++;
                    if(done == count){
                        self.emit('finish-task', taskID, {count: done});
                    }
                });
            });
            if(done == count){
                self.emit('finish-task', taskID, {count: done});
                self.emit('ready', self.options);
                return;
            }

            var newTask = {
                ID: taskID,
                region: Regions.TranslatedRegion[task.region],
                skip: task.skip/task.limit,
                clans: _(goodClans).map(function(clan){return clan.id;})
            };
            callback(newTask);
            newTask.clans = goodClans;
            self.tasks[taskID] = newTask;
        });
    },

    getUnfinishedTasks: function() {
        return _(this.tasks).keys();
    },

    processTask: function (ID, data){
        if(!this.tasks[ID]){
            console.log('No such task:',ID);
            return;
        }
        var clans = this.tasks[ID].clans;
        delete this.tasks[ID];
        var IDs = _.pluck(clans,'id');
        var self = this;
        this.Players.where(['clan_id IN ?', IDs], function(err, players) {
            var clanPlayers = {};
            _.each(players, function(player){
                if(!clanPlayers[player.clan_id]){
                    clanPlayers[player.clan_id] = [];
                }
                clanPlayers[player.clan_id].push(player);
            });
            _.each(clans, function(clan){
                clan.members = clanPlayers[clan.id] || [];
                clan.on('*',function(){
                    var args = _.toArray(arguments);
                    var event = args.shift();
                    args.unshift('clans.'+clan.id+'.'+event);
                    self.emit.apply(self, args);
                });
                clan.update(data[clan.id]);
            });
        });
    }
});
Esempio n. 3
0
module.exports = Eventer.extend({

    init: function(app) {
        this.app = app;

        this.toDoQueue = [];
        this.pendingQueue = {};
        this.pendingID = 0;
        this.clansPerItem = 30;
        this.queueTreshold = 50;

        this.totalCount = 0;
        this.doneCount = 0;
        this.finishedClans = 0;
        this.finishedTasks = 0;
        this.errorTasks = 0;
        this.speed = 0;

        this.fillingQueue = false;
        this.start = new Date();
        this.regionStats = {};
        _.each(Regions.supportedRegions, function(region) {
            this.regionStats[region] = {
                pending: 0,
                errors: []
            };
        }, this);
        this.recentTasks = [];
    },

    setModels: function(models){
        this.models = models;
        _.each(this.models,  function(model, name) {
            this[name] = model;
        },this);
    },

    fillQueue: function() {
        if(!this.models || this.fillingQueue){
            return;
        }
        var self = this;
        this.fillingQueue = true;
        var tempQueues = [];

        var buildQueue = _.after(Regions.supportedRegions.length, function(){
            var queue = [];
            tempQueues.sort(function(a, b) {
                return a.length - b.length;
            });
            _.each(tempQueues, function(q) {
                if(q){
                    queue = queue.length > 0 ? self.mixArrays(q, queue) : q;
                }
            });

            self.toDoQueue.push.apply(self.toDoQueue, queue);
            self.fillingQueue = false;
            self.totalCount = self.toDoQueue.length;
            self.doneCount = 0;
            self.cycleStart = new Date();
            self.emit('filled');
            self.emit('update', self.getCurrentStatus(), true);
        });

        _.each(Regions.supportedRegions, function(region) {
            this.Clans.countInRegion(region, function(err, count) {
                tempQueues[region] = [];
                for(var i = 0; i < count/self.clansPerItem; i++){
                    tempQueues[region].push({
                        skip: i*self.clansPerItem,
                        limit: self.clansPerItem,
                        region: region,
                        retryCount: 0
                    });
                }
                buildQueue();
            });
        }, this);
    },

    mixArrays: function (a1, a2){
        var result = [];
        var length = a2.length;
        for(var i = 0; i < length; i++){
            var ratio = a1.length/a2.length;
            result.push(a2.shift());
            for(var j = 0; j < Math.round(ratio); j++){
                result.push(a1.shift());
            }
        }
        return result;
    },

    getCurrentStatus: function() {
        return {
            totalCount: this.totalCount,
            doneCount: this.doneCount,
            pending: _.size(this.pendingQueue),
            finishedClans: this.finishedClans,
            finishedTasks: this.finishedTasks,
            errorTasks: this.errorTasks,
            speed: this.speed,
            start: this.start,
            cycleStart: this.start
        }
    },

    tooManyErrors: function(i) {
        var task = this.toDoQueue[i];
        var errors = this.regionStats[task.region].errors;
        if(errors.length == 0){
            return false;
        }
        var duration = (new Date()).getTime() - _(errors).first().getTime();
        return errors.length/duration*1000 > 0.25;
    },

    notInRegion: function(i, region) {
        if(region === undefined){
            return false;
        }
        var task = this.toDoQueue[i];
        return region != task.region;
    },

    getFromQueue: function(callback, workerID, options) {
        var self = this;

        if(this.toDoQueue.length == 0){
            this.once('filled', function() {
                self.getFromQueue(callback, workerID, options);
            });
        }else{
            var ret = {};
            var ID = this.pendingID++;

            setTimeout(function(){
                if(self.pendingQueue[ID]){
                    console.log('Task timeout:', ID);
                    self.reportFail(ID);
                }
            },60000);

            var i = 0;
            while(i<this.toDoQueue.length-1 && (this.tooManyErrors(i) || this.notInRegion(i, options.region))){i++;}
            var elem = this.toDoQueue.splice(i,1)[0];
            this.pendingQueue[ID] = elem;

            if(i == this.toDoQueue.length-1 && !this.fillingQueue){
                this.fillQueue();
            }

            ret[ID] = elem;

            this.emit('update', this.getCurrentStatus(), true);

            callback(ret);
        }

        if(this.toDoQueue.length < this.queueTreshold && !this.fillingQueue){
            this.fillQueue();
        }

        _.each(Regions.supportedRegions, function(region) {
            while(this.regionStats[region].errors.length > 0 && (new Date()).getTime() - this.regionStats[region].errors[0].getTime() > 20*1000 ){
                this.regionStats[region].errors.shift();
            }
        }, this);
    },

    confirmSuccess: function(ID, data) {
        delete this.pendingQueue[ID];
        this.doneCount++;
        this.finishedTasks++;
        if(data){
            this.finishedClans += data.count;
        }
        this.calcSpeed(data.count);
        this.emit('update', this.getCurrentStatus(), true);
    },

    calcSpeed: function(count) {
        if(count){
            this.recentTasks.push({
                count: count,
                time: new Date()
            });
        }
        while(this.recentTasks.length > 0 && (new Date()).getTime() - this.recentTasks[0].time.getTime() > 5*1000 ){
            this.recentTasks.shift();
        }
        if(this.recentTasks.length > 1){
            var sum = _.chain(this.recentTasks).pluck('count').reduce(function(memo, num){ return memo + num; }, 0).value();
            var duration = _(this.recentTasks).last().time.getTime() - _(this.recentTasks).first().time.getTime();
            this.speed = Math.round(sum/duration*1000*100)/100;
        }
    },

    reportFail: function(ID) {
        if(!this.pendingQueue[ID]){
            return;
        }
        this.errorTasks++;
        if(this.pendingQueue[ID].limit == 1){
            this.pendingQueue[ID].retryCount++;
            if(this.pendingQueue[ID].retryCount < 3){
                this.toDoQueue.unshift(this.pendingQueue[ID]);
            }else{
                console.log('Too many retries:',this.pendingQueue[ID]);
            }
        } else {
            this.splitTask(this.pendingQueue[ID]);
        }
        var region = this.pendingQueue[ID].region;
        delete this.pendingQueue[ID];
        this.regionStats[region].errors.push(new Date());
        this.calcSpeed();
        this.emit('update', this.getCurrentStatus(), true);
    },

    splitTask: function(task) {
        var task1 = {skip: task.skip, limit: Math.round(task.limit/2), region: task.region, retryCount: 0};
        var task2 = {skip: task.skip+task1.limit, limit: task.limit-task1.limit, region: task.region, retryCount: 0};
        //console.log('Split',task,'into',task1,task2);
        this.toDoQueue.unshift(task1);
        this.toDoQueue.unshift(task2);
        this.totalCount++;
    }

});
Esempio n. 4
0
module.exports = Eventer.extend({

    init: function(ID, manager, controller) {
        this.ID = ID;
        this.controller = controller;
        this.manager = manager;
        this.done = false;
        this.loaded = false;
        this.lastAccessed = new Date();
        this.maxAge = Config.caches.Clan.maxAge;

        this.IDs = [];
        this.caches = {};
        var self = this;
        this.controller.Players.inClan(ID, function(err, players) {
            _(players).each(function(player) {
                self.IDs.push(player.id);
                var playerCache = self.controller.getCache('player.'+player.id);
                if(!playerCache){
                    playerCache = new PlayerCache(player.id, self.manager);
                    self.controller.setCache('player.'+player.id, playerCache);
                }
                self.caches[player.id] = playerCache;
            });
            self.setCacheCallbacks();
        });

        this.interval = setInterval(function(){
            _(self.caches).each(function(cache) {
                cache.lastAccessed = new Date();
            });
        },1000);
    },

    onClose: function() {
        if(this.done){ clearInterval(this.interval); }
        return this.done;
    },

    setCacheCallbacks: function() {
        var self = this;
        _(this.caches).each(function(cache) {
            if(!cache.done){
                cache.once('done', function() {
                    if(self.getProgress() >= 100){ self.emit('done'); self.done = true; }
                });
            }
        });
        var counter = 0;
        _(this.caches).each(function(cache) {
            if(!cache.loaded){
                counter++;
                cache.once('loaded', function() {
                    if(--counter <= 0){ self.emit('loaded'); self.loaded = true; }
                });
            }
        });
    },

    getProgress: function() {
        var count = 0;
        var progress = 0;
        _(this.caches).each(function(cache) {
            count += 1;
            progress += cache.progress;
        });
        return progress/count;
    },

    getData: function(options) {
        this.lastAccessed = new Date();
        options = options || {};
        return {
            progress: this.getProgress(),
            players: _.object(_(this.caches).keys(), _(this.caches).map(function(cache) {
                return cache.getData(options.players);
            }))
        };
    }

});