UNPKG

15.3 kBJavaScriptView Raw
1//- JavaScript source code
2
3//- defs-couch.js ~~
4//
5// NOTE: I need to experiment with `require('https').globalAgent.maxSockets`!
6//
7// ~~ (c) SRW, 25 Sep 2012
8// ~~ last updated 21 Mar 2014
9
10(function () {
11 'use strict';
12
13 // Pragmas
14
15 /*jshint maxparams: 3, quotmark: single, strict: true */
16
17 /*jslint indent: 4, maxlen: 80, node: true, nomen: true */
18
19 /*properties
20 api, avar_ttl, body, box_status, ceil, collect_garbage, 'Content-Type',
21 couch, create, end, error, exp_date, get_avar, get_list, headers, _id,
22 isMaster, join, key, keys, length, log, method, now, on, parse,
23 protocol, push, request, _rev, set_avar, statusCode, stringify,
24 toString, trim
25 */
26
27 // Declarations
28
29 var cluster, create_db, http, https, stringify, upload_ddoc, url;
30
31 // Definitions
32
33 cluster = require('cluster');
34
35 create_db = function (conn, callback) {
36 // This function needs documentation.
37 var options, protocol, req;
38 options = Object.create(conn);
39 options.method = 'PUT';
40 protocol = (conn.protocol === 'http:') ? http : https;
41 req = protocol.request(options, function (response) {
42 // This function needs documentation.
43 var temp = [];
44 response.on('data', function (chunk) {
45 // This function needs documentation.
46 temp.push(chunk.toString());
47 return;
48 });
49 response.on('end', function () {
50 // This function needs documentation.
51 return callback(null, temp.join(''));
52 });
53 return;
54 });
55 req.on('error', callback);
56 req.end();
57 return;
58 };
59
60 http = require('http');
61
62 https = require('https');
63
64 stringify = function (obj, keys) {
65 // This function only exists to serialize the design document cleanly. It
66 // doesn't demand the level of sophistication that the browser client's
67 // `serialize` method does because we know that this function will run in
68 // Node.js and that all functions will be serializable :-)
69 /*jslint unparam: true */
70 var i, n, temp;
71 temp = {};
72 n = keys.length;
73 for (i = 0; i < n; i += 1) {
74 temp[keys[i]] = obj[keys[i]];
75 }
76 return JSON.stringify(temp, function (key, val) {
77 // See the explanation above ;-)
78 if ((typeof val === 'function') && (val instanceof Function)) {
79 return val.toString();
80 }
81 return val;
82 });
83 };
84
85 upload_ddoc = function (file, app_url, callback) {
86 // This function needs documentation.
87 var opts, protocol, req;
88 opts = url.parse(app_url);
89 opts.method = 'GET';
90 protocol = (opts.protocol === 'http:') ? http : https;
91 req = protocol.request(opts, function (response) {
92 // This function needs documentation.
93 var temp = [];
94 response.on('data', function (chunk) {
95 // This function needs documentation.
96 temp.push(chunk.toString());
97 return;
98 });
99 response.on('end', function () {
100 // This function needs documentation.
101 var new_dd, $new_dd, old_dd, $old_dd, opts2, req2;
102 new_dd = require(file);
103 $old_dd = temp.join('');
104 if (response.statusCode === 200) {
105 old_dd = JSON.parse($old_dd);
106 new_dd = require(file);
107 new_dd._id = old_dd._id;
108 new_dd._rev = old_dd._rev;
109 $new_dd = stringify(new_dd, Object.keys(old_dd));
110 $old_dd = stringify(old_dd, Object.keys(old_dd));
111 if ($new_dd === $old_dd) {
112 return callback(null, 'Design document unchanged.');
113 }
114 } else {
115 $new_dd = stringify(new_dd, Object.keys(new_dd));
116 }
117 console.log('Uploading a new design document ...');
118 opts2 = Object.create(opts);
119 opts2.method = 'PUT';
120 req2 = protocol.request(opts2, function (response) {
121 // This function needs documentation.
122 var temp = [];
123 response.on('data', function (chunk) {
124 // This function needs documentation.
125 temp.push(chunk.toString());
126 return;
127 });
128 response.on('end', function () {
129 // This function needs documentation.
130 return callback(null, temp.join(''));
131 });
132 return;
133 });
134 req2.on('error', callback);
135 req2.end($new_dd);
136 return;
137 });
138 return;
139 });
140 req.on('error', callback);
141 req.end();
142 return;
143 };
144
145 url = require('url');
146
147 // Out-of-scope definitions
148
149 exports.api = function (options) {
150 // This function needs documentation.
151
152 var app_url, collect_garbage, conn, exp_date, get_avar, get_list,
153 protocol, set_avar;
154
155 app_url = options.couch + '/_design/app/';
156
157 collect_garbage = function () {
158 // This function removes old documents from the "db" database, but it
159 // does not trigger compaction. The reason is simple -- automatic
160 // compaction is a standard feature of CouchDB 1.2 and later. To read
161 // more about configuring your couch, see http://goo.gl/V634R.
162 var callback, opts, req, target;
163 callback = function (err) {
164 // This function needs documentation.
165 if (err !== null) {
166 console.error('Error:', err);
167 return;
168 }
169 console.log('Finished collecting garbage.');
170 return;
171 };
172 target = app_url + '_list/as-array/outdated?startkey=0&endkey=' +
173 Math.ceil(Date.now() / 1000);
174 opts = url.parse(target);
175 opts.method = 'GET';
176 req = protocol.request(opts, function (res) {
177 // This function needs documentation.
178 var temp = [];
179 res.on('data', function (chunk) {
180 // This function needs documentation.
181 temp.push(chunk.toString());
182 return;
183 });
184 res.on('end', function () {
185 // This function needs documentation.
186 var body, opts2, req2;
187 body = temp.join('');
188 if (body === '[]') {
189 return callback(null);
190 }
191 opts2 = url.parse(options.couch + '/_bulk_docs');
192 opts2.headers = {'Content-Type': 'application/json'};
193 opts2.method = 'POST';
194 req2 = protocol.request(opts2, function () {
195 // This function omits named parameters because it omits
196 // them anyway.
197 return callback(null);
198 });
199 req2.on('error', callback);
200 req2.end('{"docs":' + body + '}');
201 return;
202 });
203 return;
204 });
205 req.on('error', callback);
206 req.end();
207 return;
208 };
209
210 conn = url.parse(options.couch);
211
212 exp_date = function () {
213 // This function needs documentation.
214 return Math.ceil((Date.now() / 1000) + options.avar_ttl);
215 };
216
217 get_avar = function (params, callback) {
218 // This function needs documentation.
219 var opts, req, target;
220 target = app_url + '_show/data/' + params[0] + '&' + params[1];
221 opts = url.parse(target);
222 opts.method = 'GET';
223 req = protocol.request(opts, function (res) {
224 // This function needs documentation.
225 var temp = [];
226 res.on('data', function (chunk) {
227 // This function needs documentation.
228 temp.push(chunk.toString());
229 return;
230 });
231 res.on('end', function () {
232 // This function needs documentation.
233 return callback(null, temp.join(''));
234 });
235 return;
236 });
237 req.on('error', callback);
238 req.end();
239 return;
240 };
241
242 get_list = function (params, callback) {
243 // This function needs documentation.
244 var opts, req, target;
245 target = app_url + '_list/as-array/jobs?key=["' + params[0] +
246 '","' + params[1] + '"]';
247 opts = url.parse(target);
248 opts.method = 'GET';
249 req = protocol.request(opts, function (res) {
250 // This function needs documentation.
251 var temp = [];
252 res.on('data', function (chunk) {
253 // This function needs documentation.
254 temp.push(chunk.toString());
255 return;
256 });
257 res.on('end', function () {
258 // This function needs documentation.
259 return callback(null, JSON.parse(temp.join('')));
260 });
261 return;
262 });
263 req.on('error', callback);
264 req.end();
265 return;
266 };
267
268 protocol = (conn.protocol === 'http:') ? http : https;
269
270 set_avar = function (params, callback) {
271 // This function needs documentation.
272 var obj, opts, req;
273 if (params.length === 4) {
274 obj = {
275 _id: params[0] + '&' + params[1],
276 body: params[3],
277 box_status: params[0] + '&' + params[2],
278 exp_date: exp_date(),
279 key: params[1]
280 };
281 } else {
282 obj = {
283 _id: params[0] + '&' + params[1],
284 body: params[2],
285 exp_date: exp_date(),
286 key: params[1]
287 };
288 }
289 opts = url.parse(app_url + '_update/upsert/' + obj._id);
290 opts.headers = {'Content-Type': 'application/json'};
291 opts.method = 'POST';
292 req = protocol.request(opts, function (res) {
293 // This function needs documentation.
294 res.on('data', function () {
295 // This function is empty, but it is necessary due to changes
296 // in the way that the streaming API works in Node.js, as of
297 // version 0.10 and later.
298 return;
299 });
300 res.on('end', function () {
301 // This function needs documentation.
302 if ((res.statusCode !== 201) && (res.statusCode !== 202)) {
303 // Ordinarily, we want a 201, but batch mode returns an
304 // "HTTP 202: Accepted" response, and Cloudant's BigCouch
305 // seems to use batch mode sometimes. All other status
306 // codes indicate an error.
307 return callback(res.statusCode);
308 }
309 return callback(null);
310 });
311 return;
312 });
313 req.on('error', callback);
314 req.end(JSON.stringify(obj));
315 return;
316 };
317
318 if (cluster.isMaster) {
319 create_db(conn, function (err, response) {
320 // This function needs documentation.
321 if (err !== null) {
322 console.error('Error:', err);
323 }
324 upload_ddoc('./couch-api-ddoc', app_url, function (err) {
325 // This function also accepts a second argument that contains
326 // the "results" of the query, but because I don't use it, I
327 // have omitted it to avoid irritating JSLint et al.
328 if (err !== null) {
329 console.error('Error:', err);
330 }
331 console.log(response.trim());
332 console.log('API: CouchDB storage is ready.');
333 return;
334 });
335 return;
336 });
337 }
338 return {
339 collect_garbage: collect_garbage,
340 get_avar: get_avar,
341 get_list: get_list,
342 set_avar: set_avar
343 };
344 };
345
346 exports.log = function (options) {
347 // This function needs documentation.
348 var app_url, conn, protocol;
349 app_url = options.couch + '/_design/app/';
350 conn = url.parse(options.couch);
351 protocol = (conn.protocol === 'http:') ? http : https;
352 if (cluster.isMaster) {
353 create_db(conn, function (err, response) {
354 // This function needs documentation.
355 if (err !== null) {
356 console.error('Error:', err);
357 }
358 upload_ddoc('./couch-log-ddoc', app_url, function (err) {
359 // This function also accepts a second argument that contains
360 // the "results" of the query, but because I don't use it, I
361 // have omitted it to avoid irritating JSLint et al.
362 if (err !== null) {
363 console.error('Error:', err);
364 }
365 console.log(response.trim());
366 console.log('LOG: CouchDB storage is ready.');
367 return;
368 });
369 return;
370 });
371 }
372 return function (obj) {
373 // This function needs documentation.
374 var req;
375 conn.headers = {'Content-Type': 'application/json'};
376 conn.method = 'POST';
377 req = protocol.request(conn, function (res) {
378 // This function needs documentation.
379 res.on('data', function () {
380 // This function is empty, but it is necessary due to changes
381 // in the way that the streaming API works in Node.js, as of
382 // version 0.10 and later.
383 return;
384 });
385 res.on('end', function () {
386 // See the explanation given above.
387 return;
388 });
389 return;
390 });
391 req.on('error', function (message) {
392 // This function needs documentation.
393 console.error('Error:', message);
394 return;
395 });
396 req.end(JSON.stringify(obj));
397 return;
398 };
399 };
400
401 // That's all, folks!
402
403 return;
404
405}());
406
407//- vim:set syntax=javascript: