<commit_before>var utilities = require(__basedir + "/utilities/");
var Class = utilities.Class;
var fs = require("fs");
var zlib = require("zlib");
var path = require("path");
var moment = require("moment");
var extend = require("extend");
var sanitize = require("sanitize-filename");
var log = require("./log");

/**
 * @class GameLogger: a simple manager that attaches to a directory and logs games (creates gamelogs) into that folder, as well as retrieves them from.
 */
var GameLogger = Class({
    /**
     * Initializes the GameLogger (needed on every thread)
     *
     * @param {Object} args - initialization args, from args.js, plus `directory` override
     */
    init: function(args) {
        this.gamelogDirectory = (args && args.directory) || "output/gamelogs/";

        if(args.arena) {
            this._filenameFormat = "{gameName}-{gameSession}"; // TODO: upgrade arena so it can get the "real" filename with the moment string in it via RESTful API
        }

        this._host = args.host;
        this._port = args.httpPort;
        this._visualizerURL = args.visualizerURL;
        this._filenamesWritting = {}; // easy lookup filenames we are writting to the filesystem, so they are not reported as gamelogs and read in incomplete
    },


    gamelogExtension: ".json.gz",
    _filenameFormat: "{moment}-{gameName}-{gameSession}", // default format

    /**
     * Creates a gamelog for the game in the directory set during init
     *
     * @param {Object} gamelog - the gamelog which should be serializable to json representation of the gamelog
     * @param {Function} callback - callback to invoke once the file has been written to the filesystem.
     */
    log: function(gamelog, callback) {
        var self = this;
        var serialized = JSON.stringify(gamelog);
        var filename = this.filenameFor(gamelog);

        var path = (this.gamelogDirectory + filename + this.gamelogExtension);
        var writeSteam = fs.createWriteStream(path, "utf8");
        var gzip = zlib.createGzip();

        gzip.on("error", function(err) {
            log.error("Could not save gamelog '" + gamelog.gameName + "' - '" + gamelog.gameSession + "'.", err);
        });

        this._filenamesWritting[filename] = true;
        gzip.on("finish", function() {
            delete self._filenamesWritting[filename];
            if(callback) {
                callback(filename);
            }
        });

        gzip.pipe(writeSteam);
        gzip.write(serialized);
        gzip.end();
    },

    /**
     * Gets all the gamelogs in output/gamelogs. The gamelogs are not complete, but rather a "shallow" gamelog.
     *
     * @param {function} callback - callback to invoke once gamelogs have been loaded asynchronously
     */
    getLogs: function(callback) {
        var self = this;
        fs.readdir(this.gamelogDirectory, function(err, files) {
            if(err) {
                return callback();
            }

            var gamelogs = [];
            for(var i = 0; i < files.length; i++) {
                var filename = files[i];
                if(!this._filenamesWritting[filename] && filename.endsWith(self.gamelogExtension)) { // then it is a gamelog
                    var split = filename.split("-");
                    if(split.length === 3) { // then we can figure out what the game is based on file name
                        var session = split[2];
                        gamelogs.push({
                            filename: filename,
                            epoch: utilities.unMomentString(split[0]),
                            gameName: split[1],
                            gameSession: session.substring(0, session.length - self.gamelogExtension.length),
                        });
                    }
                }
            }

            callback(gamelogs);
        });
    },

    /**
     * Returns the expected filename for a gamelog
     *
     * @param {string|Object} gameName - name of the game, or an object with these parms as key/values
     * @param {string} gameSession - name of the session
     * @param {number} epoch - when thge gamelog was logged
     * @returns {string} the filename for the given game settings
     */<commit_msg>Fix getLogs crashing entire server<commit_after>var utilities = require(__basedir + "/utilities/");
var Class = utilities.Class;
var fs = require("fs");
var zlib = require("zlib");
var path = require("path");
var moment = require("moment");
var extend = require("extend");
var sanitize = require("sanitize-filename");
var log = require("./log");

/**
 * @class GameLogger: a simple manager that attaches to a directory and logs games (creates gamelogs) into that folder, as well as retrieves them from.
 */
var GameLogger = Class({
    /**
     * Initializes the GameLogger (needed on every thread)
     *
     * @param {Object} args - initialization args, from args.js, plus `directory` override
     */
    init: function(args) {
        this.gamelogDirectory = (args && args.directory) || "output/gamelogs/";

        if(args.arena) {
            this._filenameFormat = "{gameName}-{gameSession}"; // TODO: upgrade arena so it can get the "real" filename with the moment string in it via RESTful API
        }

        this._host = args.host;
        this._port = args.httpPort;
        this._visualizerURL = args.visualizerURL;
        this._filenamesWritting = {}; // easy lookup filenames we are writting to the filesystem, so they are not reported as gamelogs and read in incomplete
    },


    gamelogExtension: ".json.gz",
    _filenameFormat: "{moment}-{gameName}-{gameSession}", // default format

    /**
     * Creates a gamelog for the game in the directory set during init
     *
     * @param {Object} gamelog - the gamelog which should be serializable to json representation of the gamelog
     * @param {Function} callback - callback to invoke once the file has been written to the filesystem.
     */
    log: function(gamelog, callback) {
        var self = this;
        var serialized = JSON.stringify(gamelog);
        var filename = this.filenameFor(gamelog);

        var path = (this.gamelogDirectory + filename + this.gamelogExtension);
        var writeSteam = fs.createWriteStream(path, "utf8");
        var gzip = zlib.createGzip();

        gzip.on("error", function(err) {
            log.error("Could not save gamelog '" + gamelog.gameName + "' - '" + gamelog.gameSession + "'.", err);
        });

        this._filenamesWritting[filename] = true;
        gzip.on("finish", function() {
            delete self._filenamesWritting[filename];
            if(callback) {
                callback(filename);
            }
        });

        gzip.pipe(writeSteam);
        gzip.write(serialized);
        gzip.end();
    },

    /**
     * Gets all the gamelogs in output/gamelogs. The gamelogs are not complete, but rather a "shallow" gamelog.
     *
     * @param {function} callback - callback to invoke once gamelogs have been loaded asynchronously
     */
    getLogs: function(callback) {
        var self = this;
        fs.readdir(this.gamelogDirectory, function(err, files) {
            if(err) {
                return callback();
            }

            var gamelogs = [];
            for(var i = 0; i < files.length; i++) {
                var filename = files[i];
                if(!self._filenamesWritting[filename] && filename.endsWith(self.gamelogExtension)) { // then it is a gamelog
                    var split = filename.split("-");
                    if(split.length === 3) { // then we can figure out what the game is based on file name
                        var session = split[2];
                        gamelogs.push({
                            filename: filename,
                            epoch: utilities.unMomentString(split[0]),
                            gameName: split[1],
                            gameSession: session.substring(0, session.length - self.gamelogExtension.length),
                        });
                    }
                }
            }

            callback(gamelogs);
        });
    },

    /**
     * Returns the expected filename for a gamelog
     *
     * @param {string|Object} gameName - name of the game, or an object with these parms as key/values
     * @param {string} gameSession - name of the session
     * @param {number} epoch - when thge gamelog was logged
     * @returns {string} the filename for the given game settings
     */
{'fraction_non_alphanumeric': 0.10997291887436712, 'fraction_numerical': 0.0016484163428705993, 'mean_word_length': 2.0921004732435384, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4367157', 'n_tokens_mistral': 2368, 'n_tokens_neox': 2280, 'n_words': 714}