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
112
113
114
115
116
117 | 1
1
1
1
9
9
1
1
1
1
| module.exports = handleLiveReload
var responsify = require('response-stream')
, inject = require('script-injector')
, through = require('through')
, watchr = require('watchr')
, path = require('path')
, fs = require('fs')
var liveReloadCode = fs.readFileSync(
path.join(__dirname, '..', 'frontend-js', 'live-reload.js')
, 'utf8'
)
function handleLiveReload(opts, io, nextHandler) {
Eif(!opts.live) {
return nextHandler
}
var lastUpdate = Date.now()
, pending = []
watchr.watch({
path: opts.cwd
, listener: onupdate
, ignoreHiddenFiles: true
, ignorePatterns: true
})
opts = opts.live
opts.rate = +opts.rate || 1000
opts.rate = Math.max(100, Math.min(opts.rate, 1000))
return handle
function handle(server, req, resp, parsed) {
if(parsed.pathname === '/-/live-reload') {
resp.writeHead(200, {'content-type': 'application/json'})
pending.push(function ontimeout() {
resp.end(JSON.stringify({
lastUpdate: lastUpdate
}))
pending.splice(pending.indexOf(ontimeout), 1)
})
return setTimeout(pending[pending.length - 1], 60000)
}
// script-injector expects to be able to wrap & execute
// the incoming code itself. so, we're wrapping it prior
// to handing it over.
var liveReloadInjection = 'function live() { (' + liveReloadCode + ')' +
'(' + lastUpdate + ',' + opts.rate + ') }'
, injector = inject(liveReloadInjection)
, lazyResponse
, piped
lazyResponse = responsify(through())
injector.pipe(resp)
injector.on('error', function(err) {
io.error(err.stack || err.message || 'script injection error')
})
lazyResponse
.on('setHeader', setHeaderListener)
.on('writeHead', writeHeadListener)
return nextHandler(server, req, lazyResponse, parsed)
function setHeaderListener(args, prevent) {
var isCType = args[0].toLowerCase() === 'content-type'
, isHTML = args[1].toLowerCase() === 'text/html'
if(isCType) {
if(isHTML) {
lazyResponse.pipe(injector)
} else {
lazyResponse.pipe(resp)
}
lazyResponse.removeListener('setHeader', setHeaderListener)
lazyResponse.removeListener('writeHead', writeHeadListener)
}
}
function writeHeadListener(args, prevent) {
var hasCType = 'content-type' in args[1]
, isHTML
isHTML = args[1]['content-type'] === 'text/html'
if(hasCType && isHTML) {
lazyResponse.pipe(injector)
} else {
lazyResponse.pipe(resp)
}
lazyResponse.removeListener('setHeader', setHeaderListener)
lazyResponse.removeListener('writeHead', writeHeadListener)
}
}
function onupdate() {
lastUpdate = Date.now()
// remove all functions from pending before
// calling them so we don't have 'em constantly
// indexOf-ing for themselves for no purpose.
var queued = pending.splice(0, pending.length)
for(var i = 0, len = queued.length; i < len; ++i) {
queued[i]()
}
}
}
|