You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			197 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			197 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
#!/usr/bin/env node
 | 
						|
//# vi: ft=javascript
 | 
						|
 | 
						|
var fs = require('fs');
 | 
						|
var path = require('path');
 | 
						|
var exec = require('child_process').exec;
 | 
						|
 | 
						|
var _ = require('lodash');
 | 
						|
var async = require('async');
 | 
						|
var express = require('express');
 | 
						|
var handlebars = require('handlebars');
 | 
						|
 | 
						|
var app = express();
 | 
						|
var staticHandler = express['static'].bind(express);
 | 
						|
 | 
						|
app.use((function log() {
 | 
						|
  var text = '{{date}} {{req.method}} {{req.url}}';
 | 
						|
  var logTemplate = handlebars.compile(text);
 | 
						|
 | 
						|
  return function (req, res, next) {
 | 
						|
    console.log(logTemplate({date: new Date().toISOString(), req: req}));
 | 
						|
    next();
 | 
						|
  };
 | 
						|
}()));
 | 
						|
 | 
						|
function renderError(res, err) {
 | 
						|
  console.error(err.toString());
 | 
						|
  res.writeHead(500, {'Content-Type': 'text/plain'});
 | 
						|
  res.send(err.toString());
 | 
						|
}
 | 
						|
 | 
						|
function pathToFile() {
 | 
						|
  return path.normalize(
 | 
						|
    path.join.apply(null, [__dirname, '..'].concat(_.toArray(arguments)))
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
function index(req, res) {
 | 
						|
  var indexFile = pathToFile('assets', 'index.html');
 | 
						|
 | 
						|
  function compileServe(err, text) {
 | 
						|
    if (err) {
 | 
						|
      renderError(res, err);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    var tmpl = handlebars.compile(text);
 | 
						|
    res.send(tmpl());
 | 
						|
  }
 | 
						|
 | 
						|
  fs.readFile(indexFile, {encoding: 'utf8'}, compileServe);
 | 
						|
}
 | 
						|
 | 
						|
app.get('/', index);
 | 
						|
 | 
						|
function serveIfExists(path) {
 | 
						|
  return function _serveIfExists(cb) {
 | 
						|
    fs.exists(path, function (exists) {
 | 
						|
      if (!exists) {
 | 
						|
        cb(null, null);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      fs.readFile(path, {encoding: 'utf8'}, cb);
 | 
						|
    });
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
app.get('/slides', function showHandler(req, res) {
 | 
						|
  fs.readdir(pathToFile('data', 'slide'), function (err, files) {
 | 
						|
    files.sort();
 | 
						|
    var jsonFiles = _.filter(files, function (file) {
 | 
						|
      return /^\d+\.json$/.test(file);
 | 
						|
    });
 | 
						|
 | 
						|
    res.send(_.map(jsonFiles, function (file) {
 | 
						|
      return {
 | 
						|
        id: parseInt(file.replace(/\.json$/, ''), 10)
 | 
						|
      };
 | 
						|
    }));
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
app.get(/slide\/(\d+)/, function showHandler(req, res, next) {
 | 
						|
  if (!req.xhr) {
 | 
						|
    index(req, res);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  var slideId = req.params[0];
 | 
						|
  var slidePath = pathToFile('data', 'slide', slideId + '.json');
 | 
						|
 | 
						|
  fs.exists(slidePath, function (exists) {
 | 
						|
    if (!exists) {
 | 
						|
      next();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    fs.readFile(slidePath, {encoding: 'utf8'}, function (err, content) {
 | 
						|
      if (err) {
 | 
						|
        renderError(res, err);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      try {
 | 
						|
        var slide = JSON.parse(content);
 | 
						|
      } catch (err) {
 | 
						|
        renderError(res, err);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      async.parallel({
 | 
						|
        copy: serveIfExists(pathToFile('data', 'copy', slide.copy + '.md')),
 | 
						|
        code: serveIfExists(pathToFile('data', 'code', slide.code + '.js'))
 | 
						|
      }, function (err, slideContent) {
 | 
						|
        if (err) {
 | 
						|
          renderError(res, err);
 | 
						|
          return;
 | 
						|
        }
 | 
						|
        slideContent.id = parseInt(slideId, 10);
 | 
						|
        slideContent.title = slide.title || '';
 | 
						|
        res.send(slideContent);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
app.get(/results\/([^\/]+)\/(\d\d)$/, function resultsHandler(req, res, next) {
 | 
						|
  var app = req.params[0];
 | 
						|
  var slideId = req.params[1];
 | 
						|
  var validApps = [
 | 
						|
    'node', 'phantomjs-1.9.8', 'phantomjs-2.0.0'
 | 
						|
  ];
 | 
						|
 | 
						|
  if (!_.contains(validApps, app)) {
 | 
						|
    next();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  var slidePath = pathToFile('data', 'slide', slideId + '.json');
 | 
						|
  fs.exists(slidePath, function (exists) {
 | 
						|
    if (!exists) {
 | 
						|
      return next();
 | 
						|
    }
 | 
						|
 | 
						|
    var noSlideError = new Error('No code for slide');
 | 
						|
    async.waterfall([
 | 
						|
 | 
						|
      function (cb) {
 | 
						|
        fs.readFile(slidePath, {encoding: 'utf8'}, cb);
 | 
						|
      },
 | 
						|
 | 
						|
      function (content, cb) {
 | 
						|
        try {
 | 
						|
          var slide = JSON.parse(content);
 | 
						|
        } catch (err) {
 | 
						|
          cb(err, null);
 | 
						|
          return;
 | 
						|
        }
 | 
						|
        cb(null, slide);
 | 
						|
      },
 | 
						|
 | 
						|
      function (slide, cb) {
 | 
						|
        var codePath = pathToFile('data', 'code', slide.code + '.js');
 | 
						|
        fs.exists(codePath, function (exists) {
 | 
						|
          if (exists) {
 | 
						|
            cb(null, codePath);
 | 
						|
          } else {
 | 
						|
            cb(noSlideError);
 | 
						|
          }
 | 
						|
        });
 | 
						|
      },
 | 
						|
 | 
						|
      function (path, cb) {
 | 
						|
        exec(app + ' ' + path, cb);
 | 
						|
      }
 | 
						|
 | 
						|
    ], function (err, stdout, stderr) {
 | 
						|
      if (err === noSlideError) {
 | 
						|
        next();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      if (err) {
 | 
						|
        res.send({stdout: '', stderr: err.toString()});
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      res.send({stdout: stdout, stderr: stderr});
 | 
						|
    });
 | 
						|
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
app.use('/data', staticHandler('data'));
 | 
						|
app.use('/vendor', staticHandler('vendor'));
 | 
						|
app.use('/static', staticHandler('static'));
 | 
						|
 | 
						|
app.listen(8000);
 |