-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.coffee
111 lines (93 loc) · 3.31 KB
/
server.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# Usage: coffee server.coffee
# External dependencies
express = require 'express'
toobusy = require 'toobusy-js'
winston = require 'winston'
papertrail = require('winston-papertrail').Papertrail
morgan = require 'morgan'
bodyParser = require 'body-parser'
compression = require 'compression'
timeout = require 'connect-timeout'
# Local dependencies
config = require './app/config.coffee'
devconfig = require './app/devconfig.coffee'
# nodetime
if process.env.NODETIME_ACCOUNT_KEY
require('nodetime').profile
accountKey: process.env.NODETIME_ACCOUNT_KEY
appName: config.site.title
# Set variables
port = process.env.PORT or 3333
encoding = {encoding: 'utf-8'}
cache_days = 5
max_cache_age = cache_days * 24 * 60 * 60 * 1000
sv_timeout = 250 * 1000 # server timeout (in milliseconds)
sv_retry_after = 5 * 1000 # toobusy wait time between requests (in milliseconds)
# Set clients
transports = []
app = express()
if devconfig.dev
transports.push new winston.transports.Console {colorize: true}
options = {filename: 'server.log', maxsize: 2097152}
transports.push new winston.transports.File options
else
host = 'logs.papertrailapp.com'
options = {handleExceptions: true, host: host, port: 55976, colorize: true}
transports.push new papertrail options
logger = new winston.Logger {transports: transports}
# helper functions
logError = (err, src, error=true) ->
logFun = if error then logger.error else logger.warn
message = if src then "#{src}: #{err.message}" else err.message
logFun message
sendError = (err, res, src, code=500) ->
message = if src then "#{src}: #{err.message}" else err.message
res.status(code).send {error: err.message}
haltOnTimedout = (req, res, next) -> if !req.timedout then next()
# middleware
# pipe web server logs through winston
winstonStream = {write: (message, encoding) -> logger.info message}
app.use timeout sv_timeout
app.use morgan 'combined', {stream: winstonStream}
app.use haltOnTimedout
app.use bodyParser.text()
app.use haltOnTimedout
app.use compression()
app.use haltOnTimedout
app.use express.static __dirname + '/public', {maxAge: max_cache_age}
app.use haltOnTimedout
# toobusy err handler
app.use (req, res, next) ->
return next() if not toobusy() or not devconfig.enable.toobusy
res.setHeader 'Retry-After', sv_retry_after
res.location req.url
err = {message: "server too busy. try #{req.url} again later."}
logError err, 'app', false
sendError err, res, 'app', 503
# CORS support
configCORS = (req, res, next) ->
# logger.info "Configuring CORS"
if not req.get 'Origin' then return next()
res.setHeader 'Access-Control-Allow-Origin', '*'
res.setHeader 'Access-Control-Allow-Methods', 'GET, POST'
res.setHeader 'Access-Control-Allow-Headers', 'X-Requested-With, Content-Type'
if 'OPTIONS' is req.method then return res.send 200
next()
# pushState hack
configPush = (req, res, next) ->
if 'api' in req.url.split('/') then return next()
newUrl = req.protocol + '://' + req.get('Host') + '/#' + req.url
res.redirect newUrl
# create server routes
app.all '*', configCORS
app.get '*', configPush
# timeout err handler
app.use (err, req, res, next) ->
logError err, 'app'
sendError err, res, 'app', 504
# start server
server = app.listen port, -> logger.info "Listening on port #{port}"
process.on 'SIGINT', ->
server.close()
toobusy.shutdown()
process.exit()