UNPKG

nextorigin-express-skeleton

Version:
111 lines (84 loc) 3.23 kB
http = require "http" path = require "path" express = require "express" favicon = require "serve-favicon" Flannel = require "flannel" compression = require "compression" bodyParser = require "body-parser" render = require "express-rendertype" GracefulExit = require "express-graceful-exit" class Skeleton logPrefix: "(Skeleton)" port: 3000 shutdownTimeout: 2*60 + 10 constructor: (@options) -> unless @Flannel?.winston @Flannel = Flannel.init Console: level: "debug" @Flannel.shirt this @debug "initializing" @address = @options.address @port = process.env.PORT or @options.port or @port @app or= express() @server = http.createServer @app @app.use @Flannel.morgan " info" @loadMiddleware() @bindRoutes() @handleRouteErrors() process.on "SIGTERM", @gracefulShutdown process.on "uncaughtException", @errThenGracefulShutdown loadMiddleware: -> # view engine setup @app.set "views", @options.views if @options.views @app.set "view engine", "pug" @app.use GracefulExit.middleware @app @app.use compression() @app.use express.static (@options.static.root or @options.static), (@options.static.options or {}) if @options.static @app.use favicon @options.favicon if @options.favicon @app.use bodyParser.json() @app.use bodyParser.urlencoded extended: !!@options.urlencoded_extended @app.use @options.render or render.auto "text" redirectToHttps: (req, res, next) -> unless proto = req.headers["x-forwarded-proto"] forwarded = req.headers["forwarded"] forwarded = /proto=(http[s]?)/.exec forwarded proto = forwarded and forwarded[1] if proto and proto isnt "https" dest = "https://#{req.hostname}#{req.url}" return res.redirect dest next() health: (req, res, next) -> res.send "OK" listen: (port = @port) => @server.on "error", @handleListeningError @server.on "listening", @listening @server.listen port, @address handleListeningError: (error) => throw error if error.syscall isnt "listen" bind = if typeof @port is "string" then "Pipe #{@port}" else "Port #{@port}" switch error.code when "EACCES" console.error "#{bind} requires elevated privileges" process.exit 1 when "EADDRINUSE" console.error "#{bind} is already in use" process.exit 1 else throw error listening: => @info "listening on #{@server.address().address}:#{@server.address().port}" bindRoutes: => @debug "stub for loading routes" handleRouteErrors: => @app.use render.Errors.Error404 @app.use render.FancyErrors.auto "text", null, @log if (@app.get "env") is "development" @app.use render.Errors.auto "text", null, @log close: (callback) => @server.close callback errThenGracefulShutdown: (err) => @err err.stack @gracefulShutdown() gracefulShutdown: => GracefulExit.gracefulExitHandler @app, this, log: true, logger: (@Flannel.shirt().info.bind this), suicideTimeout: @shutdownTimeout * 1000 delay: (timeout, fn) -> setTimeout (fn.bind this), timeout module.exports = Skeleton