1 |
|
2 | (function() {
|
3 | var EventEmitter, async, crypto, extend, mime, pathutil, zlib,
|
4 | __hasProp = {}.hasOwnProperty,
|
5 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
6 |
|
7 | async = require('async');
|
8 |
|
9 | crypto = require('crypto');
|
10 |
|
11 | pathutil = require('path');
|
12 |
|
13 | zlib = require('zlib');
|
14 |
|
15 | mime = require('mime');
|
16 |
|
17 | mime.types.js = 'text/javascript';
|
18 |
|
19 | mime.extensions['text/javascript'] = 'js';
|
20 |
|
21 | extend = require('./util').extend;
|
22 |
|
23 | EventEmitter = require('events').EventEmitter;
|
24 |
|
25 | exports.Asset = (function(_super) {
|
26 |
|
27 | __extends(Asset, _super);
|
28 |
|
29 | Asset.prototype.defaultMaxAge = 60 * 60 * 24 * 365;
|
30 |
|
31 | function Asset(options) {
|
32 | var headers, key, value, _ref, _ref1, _ref2,
|
33 | _this = this;
|
34 | Asset.__super__.constructor.call(this);
|
35 | if (options == null) {
|
36 | options = {};
|
37 | }
|
38 | if (options.url != null) {
|
39 | this.url = options.url;
|
40 | }
|
41 | if (options.contents != null) {
|
42 | this.contents = options.contents;
|
43 | }
|
44 | this.headers = options.headers ? options.headers : {};
|
45 | headers = {};
|
46 | _ref = this.headers;
|
47 | for (key in _ref) {
|
48 | value = _ref[key];
|
49 | headers[key.toLowerCase()] = value;
|
50 | }
|
51 | this.headers = headers;
|
52 | this.ext = pathutil.extname(this.url);
|
53 | if (options.mimetype != null) {
|
54 | this.mimetype = options.mimetype;
|
55 | }
|
56 | if ((_ref1 = this.mimetype) == null) {
|
57 | this.mimetype = mime.types[this.ext.slice(1, this.ext.length)];
|
58 | }
|
59 | if ((_ref2 = this.mimetype) == null) {
|
60 | this.mimetype = 'text/plain';
|
61 | }
|
62 | this.gzip = options.gzip;
|
63 | if (options.hash != null) {
|
64 | this.hash = options.hash;
|
65 | }
|
66 | if (options.maxAge != null) {
|
67 | this.maxAge = options.maxAge;
|
68 | }
|
69 | if (options.allowNoHashCache != null) {
|
70 | this.allowNoHashCache = options.allowNoHashCache;
|
71 | }
|
72 | this.on('newListener', function(event, listener) {
|
73 | if (event === 'complete' && _this.completed === true) {
|
74 | return listener();
|
75 | }
|
76 | });
|
77 | this.on('created', function(data) {
|
78 | if ((data != null ? data.contents : void 0) != null) {
|
79 | _this.contents = data.contents;
|
80 | }
|
81 | if ((data != null ? data.assets : void 0) != null) {
|
82 | _this.assets = data.assets;
|
83 | }
|
84 | if (_this.contents != null) {
|
85 | _this.createSpecificUrl();
|
86 | _this.createHeaders();
|
87 | }
|
88 | _this.completed = true;
|
89 | return _this.emit('complete');
|
90 | });
|
91 | this.on('error', function(error) {
|
92 | if (_this.listeners('error' === 1)) {
|
93 | throw error;
|
94 | }
|
95 | });
|
96 | this.on('start', function() {
|
97 | var _ref3, _ref4, _ref5, _ref6, _ref7;
|
98 | if ((_ref3 = _this.maxAge) == null) {
|
99 | _this.maxAge = (_ref4 = _this.rack) != null ? _ref4.maxAge : void 0;
|
100 | }
|
101 | if (_this.hash !== false) {
|
102 | if ((_ref5 = _this.maxAge) == null) {
|
103 | _this.maxAge = _this.defaultMaxAge;
|
104 | }
|
105 | }
|
106 | if ((_ref6 = _this.allowNoHashCache) == null) {
|
107 | _this.allowNoHashCache = (_ref7 = _this.rack) != null ? _ref7.allowNoHashCache : void 0;
|
108 | }
|
109 | return _this.create(options);
|
110 | });
|
111 | process.nextTick(function() {
|
112 | var _ref3;
|
113 | if ((_ref3 = _this.maxAge) == null) {
|
114 | _this.maxAge = _this.defaultMaxAge;
|
115 | }
|
116 | if (_this.rack == null) {
|
117 | return _this.create(options);
|
118 | }
|
119 | });
|
120 | }
|
121 |
|
122 | Asset.prototype.respond = function(request, response) {
|
123 | var headers, key, value, _ref;
|
124 | headers = {};
|
125 | if (request.url === this.url && this.allowNoHashCache !== true) {
|
126 | _ref = this.headers;
|
127 | for (key in _ref) {
|
128 | value = _ref[key];
|
129 | headers[key] = value;
|
130 | }
|
131 | delete headers['cache-control'];
|
132 | } else {
|
133 | headers = this.headers;
|
134 | }
|
135 | for (key in headers) {
|
136 | value = headers[key];
|
137 | response.header(key, value);
|
138 | }
|
139 | if (this.gzip) {
|
140 | return response.send(this.gzipContents);
|
141 | } else {
|
142 | return response.send(this.contents);
|
143 | }
|
144 | };
|
145 |
|
146 | Asset.prototype.checkUrl = function(url) {
|
147 | return url === this.specificUrl || (!(this.hash != null) && url === this.url);
|
148 | };
|
149 |
|
150 | Asset.prototype.handle = function(request, response, next) {
|
151 | var handle,
|
152 | _this = this;
|
153 | handle = function() {
|
154 | var asset, _i, _len, _ref;
|
155 | if (_this.assets != null) {
|
156 | _ref = _this.assets;
|
157 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
158 | asset = _ref[_i];
|
159 | if (asset.checkUrl(request.url)) {
|
160 | return asset.respond(request, response);
|
161 | }
|
162 | }
|
163 | }
|
164 | if (_this.checkUrl(request.url)) {
|
165 | return _this.respond(request, response);
|
166 | } else {
|
167 | return next();
|
168 | }
|
169 | };
|
170 | if (this.completed === true) {
|
171 | return handle();
|
172 | } else {
|
173 | return this.on('complete', function() {
|
174 | return handle();
|
175 | });
|
176 | }
|
177 | };
|
178 |
|
179 | Asset.prototype.create = function(options) {
|
180 | return this.emit('created');
|
181 | };
|
182 |
|
183 | Asset.prototype.createHeaders = function() {
|
184 | var _base, _base1, _base2, _ref, _ref1, _ref2;
|
185 | if ((_ref = (_base = this.headers)['content-type']) == null) {
|
186 | _base['content-type'] = "" + this.mimetype;
|
187 | }
|
188 | if (this.gzip) {
|
189 | if ((_ref1 = (_base1 = this.headers)['content-encoding']) == null) {
|
190 | _base1['content-encoding'] = 'gzip';
|
191 | }
|
192 | }
|
193 | if (this.maxAge != null) {
|
194 | return (_ref2 = (_base2 = this.headers)['cache-control']) != null ? _ref2 : _base2['cache-control'] = "public, max-age=" + this.maxAge;
|
195 | }
|
196 | };
|
197 |
|
198 | Asset.prototype.tag = function() {
|
199 | var tag;
|
200 | switch (this.mimetype) {
|
201 | case 'text/javascript':
|
202 | tag = "\n<script type=\"" + this.mimetype + "\" ";
|
203 | return tag += "src=\"" + this.specificUrl + "\"></script>";
|
204 | case 'text/css':
|
205 | return "\n<link rel=\"stylesheet\" href=\"" + this.specificUrl + "\">";
|
206 | }
|
207 | };
|
208 |
|
209 | Asset.prototype.createSpecificUrl = function() {
|
210 | var _this = this;
|
211 | this.md5 = crypto.createHash('md5').update(this.contents).digest('hex');
|
212 | if (this.hash === false) {
|
213 | this.useDefaultMaxAge = false;
|
214 | return this.specificUrl = this.url;
|
215 | }
|
216 | this.specificUrl = "" + (this.url.slice(0, this.url.length - this.ext.length)) + "-" + this.md5 + this.ext;
|
217 | if (this.hostname != null) {
|
218 | this.specificUrl = "//" + this.hostname + this.specificUrl;
|
219 | }
|
220 | if (this.gzip) {
|
221 | return zlib.gzip(this.contents, function(error, gzip) {
|
222 | return _this.gzipContents = gzip;
|
223 | });
|
224 | }
|
225 | };
|
226 |
|
227 | Asset.prototype.isRelevantUrl = function(specificUrl) {
|
228 | var baseUrl;
|
229 | baseUrl = this.url.slice(0, this.url.length - this.ext.length);
|
230 | if (specificUrl.indexOf(baseUrl !== -1 && this.ext === pathutil.extname(specificUrl))) {
|
231 | return true;
|
232 | }
|
233 | return false;
|
234 | };
|
235 |
|
236 | Asset.extend = extend;
|
237 |
|
238 | return Asset;
|
239 |
|
240 | })(EventEmitter);
|
241 |
|
242 | }).call(this);
|