UNPKG

aframe-physics-extras

Version:

Cannon API interface components the A-Frame Physics System.

204 lines (179 loc) 5.29 kB
var http = require('http') var path = require('path') var defaultIndex = require('simple-html-index') var ecstatic = require('ecstatic') var Router = require('routes-router') var inject = require('inject-lr-script') var urlParse = require('url').parse var fs = require('fs') var log = require('bole')('budo') var asyncDetectSeries = require('async').detectSeries module.exports = createServer function createServer (entryHandler, opts) { var router = Router() var staticPaths = [].concat(opts.dir).filter(Boolean) if (staticPaths.length === 0) { staticPaths = [ process.cwd() ] } var staticHandlers = staticPaths.map(function (filepath, i, list) { var last = i === list.length - 1 return ecstatic({ root: filepath, handleError: last }) }) var entrySrc = opts.serve var live = opts.live var middleware = opts.middleware || defaultMiddleware if (typeof middleware !== 'function') { throw new TypeError('expected opts.middleware to be a function') } var server = http.createServer(function (req, res) { if (middleware.length === 3) { var removeLogger = logger('middleware', req, res) // user wants to specify which routes to fall through to budo middleware(req, res, function (err) { removeLogger() if (err) { var msg = err.message ? err.message : err console.error(msg) res.statusCode = 400 res.end(msg) } else { router(req, res) } }) } else { // all routes will fall through to budo routes // we won't add a logger here to avoid doubling up middleware(req, res) router(req, res) } }) if (entryHandler) { var entryRoute = urlParse(entrySrc).pathname router.addRoute('/' + entryRoute, function (req, res) { logger('generated', req, res) entryHandler(req, res) }) } router.addRoute('/index.html', home) router.addRoute('/', home) router.addRoute('/favicon.ico', favicon) router.addRoute('*.html?', wildcard(true)) if (!opts.pushstate) { router.addRoute('/**/', wildcard(true)) } router.addRoute('*', wildcard()) // allow user to toggle live reload integration server.setLiveOptions = setLiveOptions return server function logger (type, req, res) { var byteLength = 0 var now = Date.now() var fn = function () { var elapsed = Date.now() - now log.info({ elapsed: elapsed, contentLength: byteLength, method: (req.method || 'GET').toUpperCase(), url: req.url, statusCode: res.statusCode, type: type === 'static' ? undefined : type, colors: { elapsed: elapsed > 1000 ? 'yellow' : 'dim' } }) } res.once('finish', fn) var write = res.write // catch content-length of payload res.write = function (payload) { if (payload) byteLength += payload.length res.write = write res.write.apply(res, arguments) } // allow removal return function () { res.removeListener('finish', fn) } } function favicon (req, res) { var maxAge = 345600 // 4 days res.setHeader('Cache-Control', 'public, max-age=' + Math.floor(maxAge / 1000)) res.setHeader('Content-Type', 'image/x-icon') res.statusCode = 200 // should we clutter logs with favicon.ico requests? // logger('generated', req, res) res.end() } function defaultMiddleware (req, res, next) { next() } function setLiveOptions (liveOpts) { live = liveOpts } function wildcard (html) { return function (req, res) { // inject LiveReload into HTML content if needed if (html && live && !live.plugin) { res = inject(res, live) } logger('static', req, res) staticRequest(req, res) } } function staticRequest (req, res, stack) { if (!stack) { stack = staticHandlers.slice() } var nextFn = stack.shift() nextFn(req, res, function () { if (stack.length === 0) { if (opts.pushstate) { // reset for home req.url = '/' res.statusCode = 200 home(req, res) } else { res.statusCode = 404 res.end('404 not found: ' + req.url) } } else { staticRequest(req, res, stack) } }) } function findDefaultIndex (cb) { if (opts.forceDefaultIndex) { return process.nextTick(function () { cb(false) }) } var homeFiles = staticPaths.map(function (base) { return path.join(base, 'index.html') }) asyncDetectSeries(homeFiles, fs.exists, cb) } function home (req, res) { findDefaultIndex(function (result) { // inject LiveReload into HTML content if needed if (live && !live.plugin) { res = inject(res, live) } var type = result ? 'static' : 'generated' logger(type, req, res) if (result) { staticRequest(req, res) } else { generateIndex(req, res) } }) } function generateIndex (req, res) { res.setHeader('content-type', 'text/html') var stream = opts.defaultIndex || defaultIndex stream({ entry: entrySrc, title: opts.title, css: opts.css }).pipe(res) } }