AutolabJS/AutolabJS

View on GitHub
main_server/main_server.js

Summary

Maintainability
D
2 days
Test Coverage
/* eslint import/no-dynamic-require: 0 */
var fs = require('fs');
var express = require('express');
var path = require('path');
var app = express();
var https = require('https');
var https_config={
  key : fs.readFileSync('./ssl/key.pem'),
  cert: fs.readFileSync('./ssl/cert.pem'),
  rejectUnauthorized:false,
};
var httpolyglot = require('httpolyglot');

//redirect to https


var server = httpolyglot.createServer(https_config,app);

var bodyParser = require('body-parser');

var io = require('socket.io')(server);
var session = require('express-session')({
  secret:"Autolab",
  httpOnly:true,
  secure:true,
  resave:true,
  saveUninitialized:true
});

app.use(session);
var socketSession = require('express-socket.io-session')
var mysql = require('mysql');

const { check } = require('../util/environmentCheck.js');
/* The environment variables MSCONFIG, MSLABCONFIG, MSSCORES and MSAPIKEYS
  will contain the path to the respective config files.
  The paths for the config files are
  1.Variable: MSCONFIG
    Actual Path: "../deploy/configs/main_server/conf.json"
    Path in docker containers: "/etc/main_server/conf.json"

  2.Variable: MSLABCONFIG
    Actual Path: "../deploy/configs/main_server/labs.json"
    Path in docker containers: "/etc/main_server/labs.json"

  3.Variable: MSCOURSECONFIG
    Actual Path: "../deploy/configs/main_server/course.json"
    Path in docker containers: "/etc/main_server/course.json"

  4.Variable: MSAPIKEYS
    Actual Path: "../deploy/configs/main_server/APIKeys.json"
    Path in docker containers: "/etc/main_server/APIKeys.json"
*/

check('MSCONFIG');
check('MSLABCONFIG');
check('MSCOURSECONFIG');
check('MSAPIKEYS');
var config_details = require(process.env.MSCONFIG);

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());




var load_balancer_hostname=config_details.load_balancer.hostname;
var load_balancer_port=config_details.load_balancer.port;

var connection = require('./database.js');

function initLabs()
{
  lab_config = require(process.env.MSLABCONFIG);
  for(var j=0;j<lab_config.Labs.length;j++)
  {
    initScoreboard(lab_config.Labs[j].Lab_No);
  }
}

function initScoreboard(lab_no) {
  table_name='l'+lab_no;
  console.log(table_name)
  connection.query('SELECT * FROM information_schema.tables WHERE table_schema = ? AND table_name = ? LIMIT 1', [config_details.database.database,table_name] ,function(err, rows, fields) {

      // if(err && process.env.environment !== "development")
      // {
      //   process.exit();
      //   return;
      // }
       if(err && process.env.mode === "TESTING")
      {
        console.log("Disabled connection with  MYSQL until testing completion.")
        return;
      }

      if(rows!=undefined && rows.length===0)
      {
        var q='CREATE TABLE l'+lab_no+'(id_no varchar(30), score int, time datetime, PRIMARY KEY (id_no))';
        connection.query(q, function(err, rows, fields) {
          console.log(err,rows,fields)
        });
      }
  });
}

initLabs();




//Start the server if not running tests on the main server
if(process.env.mode !== "TESTING")
{

    server.listen(config_details.main_server.port);
    console.log("Listening at "+config_details.main_server.port);
}

// Redirection from HTTP to HTTPS for all the routes.
app.use(function(req,res,next)
{

  if(req.protocol=='http')
  {

    res.redirect('https://' + req.get('host') + req.originalUrl);

  }

  else
    {

      next()
    }
})


app.use('/',express.static(__dirname + '/public'));


var submission_pending = [];  // Holds the pending submissions of the users



// app.get('/', function (req,res) {


//   res.sendFile(path.join(__dirname + '/public/index.html'));

// });


app.get('/admin', function (req,res) {
  var stream = fs.createReadStream(__dirname + '/public/admin.html');
  stream.pipe(res);
  //res.sendFile(path.join(__dirname+ '/public/admin.html'));

});


app.get('/config',function(req,res)
{
  console.log("Request Session")
  console.log(req.session)
    if(!req.session.key) res.redirect('/admin')
    //else res.sendFile(path.join(__dirname+ '/public/config.html'));
    else {
      var stream = fs.createReadStream(__dirname + '/public/config.html');
      stream.pipe(res);
    }
});


app.get('/revaluation/download/:lab',function(req,res)
{
  if(!req.session.key) res.redirect('/admin')
  var lab = req.params.lab;
  // var file = fs.createReadStream('./reval/'+lab+'_reval_score.csv');
  // file.pipe(res);

  res.download('./reval/'+lab+'_reval_score.csv');


});

app.post('/results', function(req, res){
  console.log('Results post request received');
  console.log(req.body);
  res.send("true");
  submission_pending.splice(submission_pending.indexOf(req.body.id_no,1));
  console.log('remove Users');
  io.to(req.body.socket).emit('scores', req.body);
});

app.get('/scoreboard/:Lab_no', function(req, res) {
  console.log('Scoreboard requested');
  lab = req.params.Lab_no;
  flag=0;
  lab_conf = require(process.env.MSLABCONFIG);
  for(var i=0;i<lab_conf.Labs.length;i++) {
    if(lab_conf.Labs[i].Lab_No == lab)
    {
      flag=1;
      break;
    }
  }
  if(flag == 1)
  {
    connection.query('SELECT id_no,score,DATE_FORMAT(CONVERT_TZ(time,"GMT","Asia/Kolkata"),"%d-%b-%Y %T") AS time FROM l'+lab+' ORDER BY score DESC, time' ,function(err, rows, fields) {
      res.send(rows);
    });
  }
  else {
    res.send(false);
  }
});

//status requested
app.get('/status', function (statusReq,statusRes) {

  console.log('Status requested');
  //options for load_balancer get request
  var options = {
    host: load_balancer_hostname,
    port: load_balancer_port,
    path: '/connectionCheck',
    key : fs.readFileSync('./ssl/key.pem'),
    cert: fs.readFileSync('./ssl/cert.pem'),
    rejectUnauthorized:false,
  };

  //send a get request and capture the response
  var req = https.request(options, function(res){

    // Buffer the body entirely for processing as a whole.
    var bodyChunks = [];
    res.on('data', function(chunk){
      bodyChunks.push(chunk);
    }).on('end', function(){

      var body = Buffer.concat(bodyChunks);
      var result = '';
      result = result.concat(body);
      statusRes.send(result);
    });
  });

  req.on('error', function(e) {
    statusRes.send('Load Balancer Error: ' + e.message);
    console.log('Load Balancer Error: ' + e.message);
  });

  req.end();

});

io.use(socketSession(session,{
  autoSave:true
}))



io.on('connection', function(socket) {
  require('./admin.js')(socket)
  lab_conf = require(process.env.MSLABCONFIG);
  var current_time= new Date();
  labs_status=[];
  for(var i=0;i<lab_conf.Labs.length;i++) {
    start=new Date(lab_conf.Labs[i].start_year, lab_conf.Labs[i].start_month -1 ,lab_conf.Labs[i].start_date, lab_conf.Labs[i].start_hour,lab_conf.Labs[i].start_minute, 0,0);
    end=new Date(lab_conf.Labs[i].end_year, lab_conf.Labs[i].end_month -1 ,lab_conf.Labs[i].end_date, lab_conf.Labs[i].end_hour,lab_conf.Labs[i].end_minute, 0,0);
    hard=new Date(lab_conf.Labs[i].hard_year, lab_conf.Labs[i].hard_month -1 ,lab_conf.Labs[i].hard_date, lab_conf.Labs[i].hard_hour,lab_conf.Labs[i].hard_minute, 0,0);
    var status = 0;
    if(current_time-start > 0)
    {
      if(current_time - end < 0)
      {
        delta = Math.abs((end - current_time) / 1000);
        status=1;
      }
      else {
        if(current_time - hard < 0)
        {
          status =2;
        }
      }
    }

    lab_x = {"Lab_No" :lab_conf.Labs[i], "status": status};
    labs_status.push(lab_x);
  }
  //emit course name,number and instructors
  socket.emit('course details',require(process.env.MSCOURSECONFIG));

  //emit lab status
  socket.emit('labs_status', labs_status);

  socket.on('submission', function(data) {

    var APIKeys = require(process.env.MSAPIKEYS).keys
    console.log('Socket submission event triggered');
    id_number=data[0];
    lab_no=data[1];
    commit_hash=data[2];
    language=data[3];
    if(data.length == 5) admin_key = data[4];
    else admin_key=null;
    // next if part of condition disabled to allow blocked students to
    // submit evaluation requests again
    // TODO: old evaluation request jsons remain in submission_pending - MEMORY LEAK PROBLEM.
    if(false && (admin_key==null || APIKeys.indexOf(admin_key)==-1 ) && submission_pending.indexOf(id_number)!=-1)       // Check if there is a pending submission
    {
      console.log("Pending Submission request" + ' ' + admin_key)                                                // with the same Non-Admin ID number
      io.to(socket.id).emit('submission_pending',{});
       return false;
    }
    else
      {
        submission_pending.push(id_number);
         console.log("New request");
        current_time = new Date();
        lab_config = require(process.env.MSLABCONFIG);
        flag=0;
        penalty=0;
        for(var i=0;i<lab_config.Labs.length;i++) {
          if(lab_config.Labs[i].Lab_No == lab_no)
          {
            start=new Date(lab_config.Labs[i].start_year, lab_config.Labs[i].start_month -1 ,lab_config.Labs[i].start_date, lab_config.Labs[i].start_hour,lab_config.Labs[i].start_minute, 0,0);
            end=new Date(lab_config.Labs[i].end_year, lab_config.Labs[i].end_month -1 ,lab_config.Labs[i].end_date, lab_config.Labs[i].end_hour,lab_config.Labs[i].end_minute, 0,0);
            hard=new Date(lab_config.Labs[i].hard_year, lab_config.Labs[i].hard_month -1 ,lab_config.Labs[i].hard_date, lab_config.Labs[i].hard_hour,lab_config.Labs[i].hard_minute, 0,0);
            flag=1;
            break;
          }
        }
        id_number = id_number.replace(/\s+/, "");
        commit_hash = commit_hash.replace(/\s+/, "");
        if(/^\w+$/.test(id_number)===false)
        {
          flag=0;
        }
        if(/^\w*$/.test(commit_hash)===false)
        {
          flag=0;
        }
        // uncomment the next if condition to place restriction on the length of username
        /*
        if(id_number.length!=12)
        {
          flag=0;
        }
        */
        if(flag==1) {
          var status = 0;
          if(current_time-start > 0)
          {
            if(current_time - end < 0)
            {
              status=1;
            }
            else {
              if(current_time - hard < 0)
              {
                status =2;
                penalty=lab_config.Labs[i].penalty;
              }
            }
          }
          body_json= {"id_no" :id_number.toUpperCase(), "Lab_No": lab_no, "time":current_time.toISOString().slice(0, 19).replace('T', ' '), "commit": commit_hash, "status": status, "penalty": penalty, "socket": socket.id, "language": language};

          var options = {
            host: load_balancer_hostname,
            port: load_balancer_port,
            path: '/userCheck',
            key : fs.readFileSync('./ssl/key.pem'),
            cert: fs.readFileSync('./ssl/cert.pem'),
            rejectUnauthorized:false,
          };
          var body=JSON.stringify(body_json);
          var request = https.request({
            hostname: load_balancer_hostname,
            port: load_balancer_port,
            path: "/submit",
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              "Content-Length": Buffer.byteLength(body)
            },
            key : fs.readFileSync('./ssl/key.pem'),
            cert: fs.readFileSync('./ssl/cert.pem'),
            rejectUnauthorized:false,
          });
          request.end(body);
          request.on('error', function(e) {
            console.log(e);
            socket.emit("invalid", "Invalid Lab No");
          });
        }
        else {
          socket.emit("invalid", "Invalid Lab No");
        }
      }

  });



  socket.emit('lab_data',
  {
    course:fs.readFileSync(process.env.MSCOURSECONFIG).toString('utf-8'),
    lab:fs.readFileSync(process.env.MSLABCONFIG).toString('utf-8')
  });


  socket.on('save',function(data)
  {
    if(!socket.handshake.session.key) return;

    var lab = {
      Labs: data.labs
    };

    for(var i in data.labs)
    {
      if(!(data.labs[i]["Lab_No"]=== "" || data.labs[i]["Lab_No"] === undefined ))
        {
          initScoreboard(data.labs[i]["Lab_No"]);
        }
    }
    fs.writeFile(process.env.MSLABCONFIG,JSON.stringify(lab,null,4));
    fs.writeFile(process.env.MSCOURSECONFIG,JSON.stringify(data.course,null,4));

    socket.emit("saved");
  });


  socket.on('delete lab',function(tableName)
  {
    if(!socket.handshake.session.key) return;
    connection.query(' DROP TABLE l'+tableName, function(err, rows, fields) {

      console.log(err,rows,fields)
      if(process.env.mode === "TESTING" || (rows!=undefined && rows.length!==0))
      {
        var lab_data = JSON.parse(fs.readFileSync(process.env.MSLABCONFIG).toString());

        for(var i=0;i<lab_data.Labs.length;i++)
        {
          if(lab_data["Labs"][i]["Lab_No"] == tableName) lab_data["Labs"].splice(i,1);
        }

        fs.writeFileSync(process.env.MSLABCONFIG,JSON.stringify(lab_data,null,4));
        socket.emit('deleted');
      }
  });

  })

  socket.on('disconnect',function()
  {
    console.log("DISCONNECTED")
  })
});


module.exports.app = app;
module.exports.server = server;
module.exports.connection = connection;