UNPKG

8.66 kBJavaScriptView Raw
1var path = require('path');
2var fs = require('fs');
3var util = require("../util/util");
4var async = require("async");
5var request = require("request");
6
7var http = require("http");
8var https = require("https");
9
10var logFactory = require("../util/logger");
11
12/**
13 * WCM Resource Dependency Manager
14 *
15 * Tracks page renditions and their dependencies.
16 * Calls over to Cloud CMS to store page renditions.
17 *
18 * @type {Function}
19 */
20exports = module.exports = function()
21{
22 var POLLING_TIMEOUT_MS = 500;
23
24 var logger = this.logger = logFactory("RENDITIONS");
25
26 // allow for global redis default
27 // allow for redis broadcast specific
28 // otherwise default to error
29 if (typeof(process.env.CLOUDCMS_RENDITIONS_LOG_LEVEL) !== "undefined") {
30 logger.setLevel(("" + process.env.CLOUDCMS_RENDITIONS_LOG_LEVEL).toLowerCase(), true);
31 }
32 else {
33 logger.setLevel("error");
34 }
35
36 var isRenditionsEnabled = function()
37 {
38 if (!process.configuration.renditions) {
39 process.configuration.renditions = {};
40 }
41 if (typeof(process.configuration.renditions.enabled) === "undefined") {
42 if (process.env.CLOUDCMS_APPSERVER_MODE === "production")
43 {
44 console.log("App Server running in production mode, renditions not defined, defaulting to: true");
45 process.configuration.renditions.enabled = true;
46 }
47 }
48
49 if (process.env.FORCE_CLOUDCMS_RENDITIONS_ENABLED === "true")
50 {
51 process.configuration.renditions.enabled = true;
52 }
53
54 return process.configuration.renditions.enabled;
55 };
56
57 // dispatcher factory
58 var DispatcherFactory = function(gitana) {
59
60 var QUEUE = [];
61
62 var syncRows = function(rows, callback)
63 {
64 var URL = util.asURL(process.env.GITANA_PROXY_SCHEME, process.env.GITANA_PROXY_HOST, process.env.GITANA_PROXY_PORT) + "/bulk/pagerenditions";
65
66 var agent = http.globalAgent;
67 if (process.env.GITANA_PROXY_SCHEME === "https")
68 {
69 agent = https.globalAgent;
70 }
71
72 // add "authorization" for OAuth2 bearer token
73 var headers = {};
74 var headers2 = gitana.platform().getDriver().getHttpHeaders();
75 headers["Authorization"] = headers2["Authorization"];
76
77 request({
78 "method": "POST",
79 "url": URL,
80 "qs": {},
81 "json": {
82 "rows": rows
83 },
84 "headers": headers,
85 "timeout": process.defaultHttpTimeoutMs,
86 "agent": agent
87 }, function (err, response, body) {
88 callback();
89 });
90 };
91
92 var fn = function() {
93 setTimeout(function() {
94
95 // chew off a bit of the queue that we'll send
96 var queueLength = QUEUE.length;
97 if (queueLength === 0) {
98 return fn();
99 }
100
101 // if queue length > 50, we trim back
102 if (queueLength > 50) {
103 queueLength = 50;
104 }
105
106 var rows = [];
107 for (var i = 0; i < queueLength; i++) {
108 rows.push(QUEUE[i]);
109 }
110
111 // strip down the queue
112 QUEUE = QUEUE.slice(queueLength);
113
114 // send rows via HTTP
115 logger.info("Dispatching " + rows.length + " rows");
116 syncRows(rows, function() {
117 logger.info("Completed Dispatch of " + rows.length + " rows");
118 fn();
119 });
120 }, POLLING_TIMEOUT_MS);
121 };
122 fn();
123
124 var r = {};
125
126 r.push = function(pageRendition)
127 {
128 QUEUE.push(pageRendition);
129
130 logger.info("Pushed 1 page rendition to queue, queue size: " + QUEUE.length);
131 };
132
133 return r;
134 };
135 var Dispatcher = null;
136
137
138 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
139 //
140 // RESULTING OBJECT
141 //
142 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
143
144 var r = {};
145
146 /**
147 * Marks a page cache element as dependent on a set of dependencies.
148 *
149 * This calls over to Cloud CMS to register a page rendition described by "descriptor" as being dependent on the "dependencies".
150 *
151 * The descriptor structure is:
152 *
153 * {
154 * "url": req.url,
155 * "host": req.host,
156 * "path": offsetPath,
157 * "params": req.params,
158 * "headers": req.headers,
159 * "tokens": tokens,
160 * "matchingPath": matchingPath,
161 * "pageId": page._doc,
162 * "scope": scope (either "PAGE" or "FRAGMENT")
163 * }
164 *
165 * And dependencies are:
166 *
167 * {
168 * "requires": {
169 * "locale": ["en-US"]
170 * },
171 * "produces": {
172 * "node": ["abc123", "def456"]
173 * }
174 * }
175 *
176 * @type {Function}
177 */
178 var markRendition = r.markRendition = function(req, descriptor, dependencies, callback)
179 {
180 // if renditions aren't enabled, don't bother sending back
181 if (!isRenditionsEnabled())
182 {
183 return;
184 }
185
186 if (!Dispatcher) {
187 Dispatcher = new DispatcherFactory(req.gitana);
188 }
189
190 // empty dependencies if not defined
191 if (!dependencies) {
192 dependencies = {};
193 }
194
195 // noop callback if not defined
196 if (!callback) {
197 callback = function() { };
198 }
199
200 req.branch(function(err, branch) {
201
202 req.application(function (err, application) {
203
204 if (err)
205 {
206 return callback(err);
207 }
208
209 var applicationId = application._doc;
210
211 var deploymentKey = "default";
212 if (req.descriptor && req.descriptor.deploymentKey)
213 {
214 deploymentKey = req.descriptor.deploymentKey;
215 }
216
217 // the descriptor contains "path", "params" and "headers". We use this to generate a unique key.
218 // essentially this is a hash and acts as the page cache key
219 var pageCacheKey = util.generatePageCacheKey(descriptor);
220
221 // headers
222 var headers = {};
223
224 var renditionObject = {
225 "deploymentKey": deploymentKey,
226 "key": pageCacheKey,
227 "page": {
228 "id": descriptor.matchingPageId,
229 "title": descriptor.matchingPageTitle,
230 "url": descriptor.matchingUrl,
231 "path": descriptor.matchingPath,
232 "tokens": descriptor.tokens,
233 "attributes": descriptor.pageAttributes ? descriptor.pageAttributes : {}
234 },
235 "pageCacheKey": pageCacheKey,
236 "request": {
237 "url": descriptor.url,
238 "path": descriptor.path,
239 "host": descriptor.host,
240 "protocol": descriptor.protocol,
241 "headers": descriptor.headers,
242 "params": descriptor.params
243 },
244 "dependencies": dependencies,
245 "active": true,
246 "scope": "PAGE"
247 };
248
249 renditionObject.repositoryId = branch.getRepositoryId();
250 renditionObject.branchId = branch.getId();
251
252 if (descriptor.scope)
253 {
254 renditionObject.scope = descriptor.scope;
255 }
256 if (descriptor.fragmentId)
257 {
258 renditionObject.fragmentId = descriptor.fragmentId;
259 renditionObject.fragmentCacheKey = descriptor.fragmentCacheKey;
260 renditionObject.key = descriptor.fragmentCacheKey;
261 }
262
263 // build up a row that we can queue
264 var row = {};
265 row.object = renditionObject;
266 row.applicationId = applicationId;
267 row.deploymentKey = deploymentKey;
268
269 // push row to dispatcher
270 Dispatcher.push(row);
271
272 });
273 });
274 };
275
276 return r;
277}();
278