1 |
|
2 | (function() {
|
3 | var Server, chokidar, defaultExclusions, defaultExts, defaultPort, fs, http, https, path, protocol_version, url, ws;
|
4 |
|
5 | fs = require('fs');
|
6 |
|
7 | path = require('path');
|
8 |
|
9 | ws = require('ws');
|
10 |
|
11 | http = require('http');
|
12 |
|
13 | https = require('https');
|
14 |
|
15 | url = require('url');
|
16 |
|
17 | chokidar = require('chokidar');
|
18 |
|
19 | protocol_version = '7';
|
20 |
|
21 | defaultPort = 35729;
|
22 |
|
23 | defaultExts = ['html', 'css', 'js', 'png', 'gif', 'jpg', 'php', 'php5', 'py', 'rb', 'erb', 'coffee'];
|
24 |
|
25 | defaultExclusions = [/\.git\//, /\.svn\
|
26 |
|
27 | Server = (function() {
|
28 | function Server(config1) {
|
29 | var base, base1, base2, base3, base4, base5, base6, base7;
|
30 | this.config = config1;
|
31 | if (this.config == null) {
|
32 | this.config = {};
|
33 | }
|
34 | if ((base = this.config).version == null) {
|
35 | base.version = protocol_version;
|
36 | }
|
37 | if ((base1 = this.config).port == null) {
|
38 | base1.port = defaultPort;
|
39 | }
|
40 | if ((base2 = this.config).exts == null) {
|
41 | base2.exts = [];
|
42 | }
|
43 | if ((base3 = this.config).exclusions == null) {
|
44 | base3.exclusions = [];
|
45 | }
|
46 | this.config.exts = this.config.exts.concat(defaultExts);
|
47 | this.config.exclusions = this.config.exclusions.concat(defaultExclusions);
|
48 | if ((base4 = this.config).applyCSSLive == null) {
|
49 | base4.applyCSSLive = true;
|
50 | }
|
51 | if ((base5 = this.config).originalPath == null) {
|
52 | base5.originalPath = '';
|
53 | }
|
54 | if ((base6 = this.config).overrideURL == null) {
|
55 | base6.overrideURL = '';
|
56 | }
|
57 | if ((base7 = this.config).usePolling == null) {
|
58 | base7.usePolling = false;
|
59 | }
|
60 | }
|
61 |
|
62 | Server.prototype.listen = function(callback) {
|
63 | this.debug("LiveReload is waiting for browser to connect.");
|
64 | if (this.config.server) {
|
65 | this.config.server.listen(this.config.port);
|
66 | this.server = new ws.Server({
|
67 | server: this.config.server
|
68 | });
|
69 | } else {
|
70 | this.server = new ws.Server({
|
71 | port: this.config.port
|
72 | });
|
73 | }
|
74 | this.server.on('connection', this.onConnection.bind(this));
|
75 | this.server.on('close', this.onClose.bind(this));
|
76 | if (callback) {
|
77 | return this.server.once('listening', callback);
|
78 | }
|
79 | };
|
80 |
|
81 | Server.prototype.onConnection = function(socket) {
|
82 | this.debug("Browser connected.");
|
83 | socket.on('message', (function(_this) {
|
84 | return function(message) {
|
85 | var data, request;
|
86 | _this.debug("Client message: " + message);
|
87 | request = JSON.parse(message);
|
88 | if (request.command === "hello") {
|
89 | _this.debug("Client requested handshake...");
|
90 | _this.debug("Handshaking with client using protocol " + _this.config.version + "...");
|
91 | data = JSON.stringify({
|
92 | command: 'hello',
|
93 | protocols: ['http://livereload.com/protocols/official-7', 'http://livereload.com/protocols/official-8', 'http://livereload.com/protocols/official-9', 'http://livereload.com/protocols/2.x-origin-version-negotiation', 'http://livereload.com/protocols/2.x-remote-control'],
|
94 | serverName: 'node-livereload'
|
95 | });
|
96 | return socket.send(data);
|
97 | }
|
98 | };
|
99 | })(this));
|
100 | socket.on('error', (function(_this) {
|
101 | return function(err) {
|
102 | return _this.debug("Error in client socket: " + err);
|
103 | };
|
104 | })(this));
|
105 | return socket.on('close', (function(_this) {
|
106 | return function(message) {
|
107 | return _this.debug("Client closed connection");
|
108 | };
|
109 | })(this));
|
110 | };
|
111 |
|
112 | Server.prototype.onClose = function(socket) {
|
113 | return this.debug("Socket closed.");
|
114 | };
|
115 |
|
116 | Server.prototype.watch = function(paths) {
|
117 | return this.watcher = chokidar.watch(paths, {
|
118 | ignoreInitial: true,
|
119 | ignored: this.config.exclusions,
|
120 | usePolling: this.config.usePolling
|
121 | }).on('add', this.filterRefresh.bind(this)).on('change', this.filterRefresh.bind(this)).on('unlink', this.filterRefresh.bind(this));
|
122 | };
|
123 |
|
124 | Server.prototype.filterRefresh = function(filepath) {
|
125 | var delayedRefresh, exts, fileext;
|
126 | exts = this.config.exts;
|
127 | fileext = path.extname(filepath).substring(1);
|
128 | if (exts.indexOf(fileext) !== -1) {
|
129 | if (this.config.delay) {
|
130 | return delayedRefresh = setTimeout((function(_this) {
|
131 | return function() {
|
132 | clearTimeout(delayedRefresh);
|
133 | return _this.refresh(filepath);
|
134 | };
|
135 | })(this), this.config.delay);
|
136 | } else {
|
137 | return this.refresh(filepath);
|
138 | }
|
139 | }
|
140 | };
|
141 |
|
142 | Server.prototype.refresh = function(filepath) {
|
143 | var data;
|
144 | this.debug("Refresh: " + filepath);
|
145 | data = JSON.stringify({
|
146 | command: 'reload',
|
147 | path: filepath,
|
148 | liveCSS: this.config.applyCSSLive,
|
149 | liveImg: this.config.applyImgLive,
|
150 | originalPath: this.config.originalPath,
|
151 | overrideURL: this.config.overrideURL
|
152 | });
|
153 | return this.sendAllClients(data);
|
154 | };
|
155 |
|
156 | Server.prototype.alert = function(message) {
|
157 | var data;
|
158 | this.debug("Alert: " + message);
|
159 | data = JSON.stringify({
|
160 | command: 'alert',
|
161 | message: message
|
162 | });
|
163 | return this.sendAllClients(data);
|
164 | };
|
165 |
|
166 | Server.prototype.sendAllClients = function(data) {
|
167 | var i, len, ref, results, socket;
|
168 | ref = this.server.clients;
|
169 | results = [];
|
170 | for (i = 0, len = ref.length; i < len; i++) {
|
171 | socket = ref[i];
|
172 | results.push(socket.send(data, (function(_this) {
|
173 | return function(error) {
|
174 | if (error) {
|
175 | return _this.debug(error);
|
176 | }
|
177 | };
|
178 | })(this)));
|
179 | }
|
180 | return results;
|
181 | };
|
182 |
|
183 | Server.prototype.debug = function(str) {
|
184 | if (this.config.debug) {
|
185 | return console.log(str + "\n");
|
186 | }
|
187 | };
|
188 |
|
189 | Server.prototype.close = function() {
|
190 | this.watcher.close();
|
191 | this.server._server.close();
|
192 | return this.server.close();
|
193 | };
|
194 |
|
195 | return Server;
|
196 |
|
197 | })();
|
198 |
|
199 | exports.createServer = function(config, callback) {
|
200 | var app, requestHandler, server;
|
201 | if (config == null) {
|
202 | config = {};
|
203 | }
|
204 | requestHandler = function(req, res) {
|
205 | if (url.parse(req.url).pathname === '/livereload.js') {
|
206 | res.writeHead(200, {
|
207 | 'Content-Type': 'text/javascript'
|
208 | });
|
209 | return res.end(fs.readFileSync(__dirname + '/../ext/livereload.js'));
|
210 | }
|
211 | };
|
212 | if (config.https == null) {
|
213 | app = http.createServer(requestHandler);
|
214 | } else {
|
215 | app = https.createServer(config.https, requestHandler);
|
216 | }
|
217 | if (config.server == null) {
|
218 | config.server = app;
|
219 | }
|
220 | server = new Server(config);
|
221 | if (!config.noListen) {
|
222 | server.listen(callback);
|
223 | }
|
224 | return server;
|
225 | };
|
226 |
|
227 | }).call(this);
|