<commit_before>"use strict";

/*
    Title: Test Harness Server
    
    Implementation of the Math Fluency <test harness at http://fluencychallenge.com/wiki/DesignAndImplementation/TestHarness>.
*/

var urllib = require('url'),
    fs = require('fs'),
    express = require('express'),
    restapi = require('../server/restapi'),
    modelInit = require('./model'),
    gameController = require('./gamecontroller').gameController,
    addInstructorEndpoints = require('./instructorserver').addInstructorEndpoints,
    MySQLSessionStore = require('connect-mysql-session')(express),
    form = require('connect-form'),
    resolveRelativePath = require('../server/serverutils').resolveRelativePath;


function runServer(config, model)
{
    config.outputPath = resolveRelativePath(config.outputPath, __dirname);
    config.cliFlashPath = resolveRelativePath(config.cliFlashPath, __dirname);
    config.dataPath = resolveRelativePath(config.dataPath || '../../data', __dirname);
    config.gameConfig = resolveRelativePath(config.gameConfig, __dirname);
    
    var port = config.port || 80,
        rootPath = config.rootPath || '/';
    
    var gc = gameController(config, model);
    
    var app = express.createServer();
    if (rootPath && rootPath != '/')
    {
        app.set('home', rootPath);
    }
    else
    {
        rootPath = '';
    }
    express.logger.token('user', function (req, res)
    {
        return (req.instructor ? req.instructor.loginID + '(i)' :
                req.student ? req.student.loginID + '(s)' :
                '-');
    });
    if (config.debug)
    {
        app.use(express.logger({ format: 'dev' }));
    }
    else
    {
        app.use(express.logger({
            format: ':req[x-forwarded-for] :user [:date] :method :url :status :res[content-length] - :response-time ms'
        }));
    }
    app.set('view engine', 'ejs');
    app.set('views', resolveRelativePath('views', __dirname));
    
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
    app.use(express.bodyParser());
    app.use(form());
    app.use(express.cookieParser());
    app.use(express.session({
        store: new MySQLSessionStore(config.mysql.database, config.mysql.user, config.mysql.password, config.sequelizeOptions),
        secret: "keyboard cat",
        cookie: {
            maxAge: null
        }
    }));
    
    // Static handlers for client-side JS and game assets, etc.
    
    app.use(rootPath + '/js/node_modules', express.static(resolveRelativePath('../../node_modules', __dirname)));
    app.use(rootPath + '/js/common', express.static(resolveRelativePath('../common', __dirname)));
    app.use(rootPath + '/js/client', express.static(resolveRelativePath('../client', __dirname)));
    app.use(rootPath + '/js', express.static(resolveRelativePath('clientjs', __dirname)));
    app.use(rootPath + '/static', express.static(resolveRelativePath('../static', __dirname)));
    app.use(rootPath + '/static', express.directory(resolveRelativePath('../static', __dirname), {icons:true}));
    app.use(rootPath + '/output', express.static(config.outputPath));
    app.use(rootPath + '/output', express.directory(config.outputPath, {icons:true}));
    app.use(rootPath + '/css', express.static(resolveRelativePath('css', __dirname)));
    
    // These are the MATHia fluency tasks. On the production server, these are served directly by nginx instead of going through the node webapp. We have these static handlers so dev environment can run without the nginx reverse proxy.
    app.use(rootPath + '/fluency/data', express.static(config.dataPath));
    app.use(rootPath + '/fluency/data', express.directory(config.dataPath, {icons:true}));
    app.use(rootPath + '/fluency/games', express.static(config.cliFlashPath));
    app.use(rootPath + '/fluency/games', express.directory(config.cliFlashPath, {icons:true}));

    // Middleware to load student or instructor data before processing requests.
    
    app.use(function (req, res, next)
    {
        if (req.session && req.session.instructorID)
        {
            model.Instructor.find(req.session.instructorID).on('success', function (instructor)
            {
                req.instructor = instructor;
                next();
            });
        }
        else if (req.session && req.session.studentID)
        {
            gc.getPlayerState(req.session.studentID, function (student)
            {
                req.student = student;
                
                // The REST API uses req.playerState, so set that too.
                req.playerState = student;
                <commit_msg>Cache static Flash swf files for 10 seconds even when running in dev environment.<commit_after>"use strict";

/*
    Title: Test Harness Server
    
    Implementation of the Math Fluency <test harness at http://fluencychallenge.com/wiki/DesignAndImplementation/TestHarness>.
*/

var urllib = require('url'),
    fs = require('fs'),
    express = require('express'),
    restapi = require('../server/restapi'),
    modelInit = require('./model'),
    gameController = require('./gamecontroller').gameController,
    addInstructorEndpoints = require('./instructorserver').addInstructorEndpoints,
    MySQLSessionStore = require('connect-mysql-session')(express),
    form = require('connect-form'),
    resolveRelativePath = require('../server/serverutils').resolveRelativePath;


function runServer(config, model)
{
    config.outputPath = resolveRelativePath(config.outputPath, __dirname);
    config.cliFlashPath = resolveRelativePath(config.cliFlashPath, __dirname);
    config.dataPath = resolveRelativePath(config.dataPath || '../../data', __dirname);
    config.gameConfig = resolveRelativePath(config.gameConfig, __dirname);
    
    var port = config.port || 80,
        rootPath = config.rootPath || '/';
    
    var gc = gameController(config, model);
    
    var app = express.createServer();
    if (rootPath && rootPath != '/')
    {
        app.set('home', rootPath);
    }
    else
    {
        rootPath = '';
    }
    express.logger.token('user', function (req, res)
    {
        return (req.instructor ? req.instructor.loginID + '(i)' :
                req.student ? req.student.loginID + '(s)' :
                '-');
    });
    if (config.debug)
    {
        app.use(express.logger({ format: 'dev' }));
    }
    else
    {
        app.use(express.logger({
            format: ':req[x-forwarded-for] :user [:date] :method :url :status :res[content-length] - :response-time ms'
        }));
    }
    app.set('view engine', 'ejs');
    app.set('views', resolveRelativePath('views', __dirname));
    
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
    app.use(express.bodyParser());
    app.use(form());
    app.use(express.cookieParser());
    app.use(express.session({
        store: new MySQLSessionStore(config.mysql.database, config.mysql.user, config.mysql.password, config.sequelizeOptions),
        secret: "keyboard cat",
        cookie: {
            maxAge: null
        }
    }));
    
    // Static handlers for client-side JS and game assets, etc.
    
    app.use(rootPath + '/js/node_modules', express.static(resolveRelativePath('../../node_modules', __dirname)));
    app.use(rootPath + '/js/common', express.static(resolveRelativePath('../common', __dirname)));
    app.use(rootPath + '/js/client', express.static(resolveRelativePath('../client', __dirname)));
    app.use(rootPath + '/js', express.static(resolveRelativePath('clientjs', __dirname)));
    app.use(rootPath + '/static', express.static(resolveRelativePath('../static', __dirname)));
    app.use(rootPath + '/static', express.directory(resolveRelativePath('../static', __dirname), {icons:true}));
    app.use(rootPath + '/output', express.static(config.outputPath));
    app.use(rootPath + '/output', express.directory(config.outputPath, {icons:true}));
    app.use(rootPath + '/css', express.static(resolveRelativePath('css', __dirname)));
    
    // These are the MATHia fluency tasks. On the production server, these are served directly by nginx instead of going through the node webapp. We have these static handlers so dev environment can run without the nginx reverse proxy.
    app.use(rootPath + '/fluency/data', express.static(config.dataPath));
    app.use(rootPath + '/fluency/data', express.directory(config.dataPath, {icons:true}));
    // Cache Flash resources for 10 seconds.
    app.use(rootPath + '/fluency/games', express.static(config.cliFlashPath, {maxAge: 10000}));
    app.use(rootPath + '/fluency/games', express.directory(config.cliFlashPath, {icons:true}));

    // Middleware to load student or instructor data before processing requests.
    
    app.use(function (req, res, next)
    {
        if (req.session && req.session.instructorID)
        {
            model.Instructor.find(req.session.instructorID).on('success', function (instructor)
            {
                req.instructor = instructor;
                next();
            });
        }
        else if (req.session && req.session.studentID)
        {
            gc.getPlayerState(req.session.studentID, function (student)
            {
                req.student = student;
                
                // The REST API uses req.playerState, so set that too.
                req.playerState = student;
                
{'fraction_non_alphanumeric': 0.14641943734015345, 'fraction_numerical': 0.0013853367433930093, 'mean_word_length': 2.915310805173133, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '6789345', 'n_tokens_mistral': 2695, 'n_tokens_neox': 2633, 'n_words': 555}