UNPKG

17.2 kBJavaScriptView Raw
1/*!
2 * Simple Node Mobile Portal
3 * Copyright(c) 2012 Faisal Kottarathil
4 * MIT Licensed
5 */
6/**
7 * Database middleware for `simpleportal.Server`
8 *
9 * @property db
10 * @for simpleportal
11 * @type {db}
12 * @static
13 */
14
15/**
16 * Database middleware for `simpleportal.Server`
17 *
18 * @class db
19 * @module middleware
20 * @static
21 */
22var db = module.exports = {};
23
24var mongodb = require('mongodb');
25var fs = require('fs');
26var zlib = require('zlib');
27
28var logger = require("./logger");
29var util = require('./util');
30var exec = require('child_process').exec;
31
32//var BSON = mongodb.BSONPure;
33
34var ObjectID;
35if(mongodb.BSONPure)
36 ObjectID = mongodb.BSONPure.ObjectID;
37else
38 ObjectID = mongodb.ObjectID;
39
40var dbInstance;
41
42var DBPool = require('./wrapper/dbpool');
43var dbpool;
44
45var dbConfiguration;
46
47/**
48 * To generate the id from the text
49 *
50 * @method generateId
51 * @param {string} name text to be formatted
52 * @return name formatted id
53 */
54db.generateId = function(name) {
55 return util.generateId(name);
56}
57
58/**
59 * To get the default database instance
60 *
61 * @method getInstance
62 * @return dbInstance Database instance
63 */
64db.getInstance = function(){
65 return dbInstance;
66}
67
68db.registerDB = function(dbid, configuration){
69 dbpool.registerDB(dbid, configuration);
70}
71
72/**
73 * Method to check the connectivity options for the db is given properly during server setup!
74 * @method checkDBConfig
75 * @param {object} options for the db connection
76 * @callback callback function after the connection check
77 */
78db.checkDBConfig = function(options, callback){
79 var mongoserver = new mongodb.Server(options.host, Number(options.port), options.params||{});
80 var mongoinstance = new mongodb.Db(options.dbName, mongoserver, {});
81
82 mongoinstance.open(function(error, client){
83 callback(error, client);
84 });
85}
86
87/**
88 * To start the database instance
89 *
90 * @method start
91 *
92 * @param {object} options Options for the database instance
93 * @param {callback} callback The callback to excecute when complete
94 */
95db.start = function(options, callback){
96 callback = callback || function(){};
97 var server = new mongodb.Server(options.host, Number(options.port), options.params||{});
98
99 var dbInstance_ = new mongodb.Db(options.dbName, server, {});
100
101 dbInstance_.open(function(error, client){
102 if(error){
103 logger.getInstance().error('Smple Portal -db', 'Error While initialiing' + error);
104 dbInstance_ = null;
105 callback(error);
106 } else{
107 callback(null, dbInstance_);
108 }
109 });
110}
111
112/**
113 * To initialize the database instance
114 * @method init
115 * @param {} configuration Configurations for the database instance
116 * @param {callback} callback The callback to excecute when complete
117 */
118db.init = function(configuration, callback){
119 logger.getInstance().info('Simple Portal -db', 'Initializing DB');
120
121 db.dbpool=dbpool = new DBPool();
122
123 if(configuration && configuration.db){
124 dbConfiguration = configuration.db.mongodb;
125
126 dbpool.registerDB('default', dbConfiguration);
127
128 db.dbpool.getInstance('default', function(error, dbInstance_){
129 dbInstance = dbInstance_;
130 callback(error, dbInstance_);
131 });
132 } else {
133 logger.getInstance().info('Simple Portal -db', 'DB configuration is not done properly!!!');
134 callback('DB configuration is not done properly!!!')
135 }
136}
137
138/**
139 * To get the information of a file uploaded in database file storage
140 *
141 * @todo should support couchdb and othe nosql databases
142 * @method fileInfo
143 *
144 * @param {} fileName Name of the file
145 * @param {callback} callback The callback to excecute when complete
146 * @param {} dbInstance Optional db instance object if not mentioned will use default db instance
147 */
148db.fileInfo = function(fileName, callback, dbInstance){
149 dbInstance = dbInstance||db.getInstance();
150 var gridStore = new mongodb.GridStore(dbInstance, fileName, "r");
151
152 gridStore.open(callback);
153};
154
155/**
156 * To check whether a file exists in database file storage or not
157 *
158 * @todo should support couchdb and other nosql databases
159 * @method existFile
160 *
161 * @param {} fileName Name of the file
162 * @param callback The callback to excecute when complete
163 * @param {} dbInstance Optional db instance object if not mentioned will use default db instance
164 */
165db.existFile = function(fileName, callback, dbInstance){
166 dbInstance = dbInstance||db.getInstance();
167 mongodb.GridStore.exist(dbInstance, fileName, callback);
168};
169
170/**
171 * To upload file in to the databases file storage
172 *
173 * @todo should support couchdb and othe nosql databases
174 * @method uploadFile
175 *
176 * @param {string} filePath Absolute path of the file to upload in to the database
177 * @param {string} fileName Name of the file
178 * @param {string} contentType File content type
179 * @param {callback} callback The callback to excecute when complete
180 * @param {} dbInstance Optional db instance object if not mentioned will use default db instance
181 */
182db.uploadFile = function(filePath, fileName, contentType, callback, dbInstance){
183 dbInstance = dbInstance||db.getInstance();
184 if(dbInstance){
185
186 var gridStore = new mongodb.GridStore(dbInstance, fileName, "w", {
187 "contentType": contentType/*,
188 "chunk_size": 1024*4*/
189 });
190
191 gridStore.open(function(error, gridStore){
192 if(error)
193 callback(error);
194 else
195 gridStore.writeFile(filePath, function(err, object) {
196 if(err)
197 callback(err);
198 else{
199 callback(null, {fileId : object.fileId});
200 }
201 });
202 });
203 } else
204 callback("No db instance found!!");
205}
206
207/**
208 * To get the file content from the databases file storage
209 *
210 * @method getFileContent
211 *
212 * @param {} fileId Id of the file
213 * @param {} dbInstance Optional database instance object if not mentioned will use default database instance
214 * @param {callback} callback The callback to excecute when complete
215 */
216db.getFileContent = function(fileId, dbInstance, callback){
217 dbInstance = dbInstance||db.getInstance();
218 if(dbInstance){
219 mongodb.GridStore.exist(dbInstance, fileId, function(){
220 //mongodb.GridStore.exist(dbInstance, fileId, function(){
221 var gridStore = new mongodb.GridStore(dbInstance, fileId , "r");
222 gridStore.open(function(error, data){
223 if(data)
224 mongodb.GridStore.read(dbInstance, fileId, function(err, fileData) {
225 if(error){
226 callback(error.toString());
227 } else{
228 callback(null, gridStore.currentChunk.data.buffer);
229 }
230 });
231 else if(error)
232 callback(error.toString());
233 else
234 callback('');
235 });
236 });
237 } else{
238 callback("No db instance found!!");
239 }
240}
241
242/**
243 * To send the file content in to the http response
244 *
245 * @method sendFile
246 * @param {} fileId Id of the file
247 * @param {} contentType Content type of the file
248 * @param {} response http response
249 * @param {} dbInstance Optional database instance object if not mentioned will use default database instance
250 */
251db.sendFile = function(fileId, contentType, response, dbInstance){
252 dbInstance = dbInstance||db.getInstance();
253 if(dbInstance){
254 mongodb.GridStore.exist(dbInstance, fileId, function(){
255 var gridStore = new mongodb.GridStore(dbInstance, fileId , "r");
256 gridStore.open(function(error, data){
257 mongodb.GridStore.read(dbInstance, fileId, function(err, fileData) {
258 if(error){
259 response.writeHead(400);
260 response.write(error.toString());
261 response.end();
262 } else{
263 if(contentType == 'binary/octet-stream'){
264 response.write(fileData, 'binary');
265
266 response.end();
267 }else{
268 response.writeHead(200, { 'Content-Type': contentType});
269 if(contentType ='image/png')
270 response.write(fileData, 'base64');
271 else
272 response.write(fileData, 'binary');
273 response.end();
274 }
275 }
276 });/*
277 gridStore.read([1024*4], function(error, data){
278 if(error){
279 response.writeHead(400);
280 response.write(error.toString());
281 response.end();
282 } else{
283 if(contentType == 'binary/octet-stream'){
284 response.write(gridStore.currentChunk.data.buffer, 'binary');
285
286 response.end();
287 }else{
288 response.writeHead(200, { 'Content-Type': contentType});
289 if(contentType ='image/png')
290 response.write(gridStore.currentChunk.data.buffer, 'base64');
291 else
292 response.write(gridStore.currentChunk.data.buffer, 'binary');
293 response.end();
294 }
295 }
296 });*/
297 });
298 });
299 } else{
300 response.writeHead(400);
301 response.write("No db instance found!!");
302 response.end();
303 }
304}
305
306/**
307 * To write the file from the database in to the file storage
308 *
309 * @method writeFile
310 * @param {} fileId Id of the file
311 * @param {} contentType Content type of the file
312 * @param {} file Path for the filesystem where the file will be stored
313 * @param {callback} callback The callback to excecute when complete
314 * @param {} dbInstance Optional database instance object if not mentioned will use default database instance
315 */
316db.writeFile = function(fileId, contentType, file, callback, dbInstance){
317 dbInstance = dbInstance||db.getInstance();
318 if(dbInstance){
319 mongodb.GridStore.exist(dbInstance, fileId, function(){
320 var gridStore = new mongodb.GridStore(db.getInstance(), fileId , "r");
321 gridStore.open(function(error, data){
322 gridStore.read(/*[1024*4], */function(error, data){
323 if(error){
324 callback(error.toString());
325 } else{
326 var fs = require('fs');
327 var stream = fs.createWriteStream(file);
328 stream.once('open', function(fd) {
329 stream.write(gridStore.currentChunk.data.buffer, 'binary');
330 });
331 callback(null, {});
332 }
333 });
334 });
335 });
336 } else{
337 callback("No db instance found!!");
338 }
339}
340
341/**
342 * To download the database backup across the http response
343 *
344 * @method downloadBackup
345 *
346 * @param {} options database options
347 * @param {} response Http response
348 */
349db.downloadBackup = function(options, response){
350 var file = options.file;
351 var dumpdir = options.dumpdir||dbConfiguration.dumpdir||'./dump';
352
353 fs.lstat(dumpdir + '/' + file + '.gz', function(error, stats) {
354 if (!error) {
355 var raw = fs.createReadStream(dumpdir + '/' + file + '.gz');
356 raw.pipe(zlib.createGzip()).pipe(response);
357 } else{
358 response.writeHead(400);
359 response.write("No file found with the detail you provided!!");
360 response.end();
361 }
362 });
363}
364
365/**
366 * To take a database backup
367 *
368 * @method backup
369 * @param {} options database instance configurations
370 * @param {callback} callback The callback to excecute when complete
371 */
372db.backup = function(options, callback){
373 options = options||{};
374 var dumptool = options.dumptool||dbConfiguration.dumptool||'mongodump';
375 var dbName = options.dbName||dbConfiguration.dbName;
376 var dumpdir = options.dumpdir||dbConfiguration.dumpdir||'./dump';
377
378 util.checkDir(dumpdir, function(error){
379 if(error){
380 callback(error);
381 } else{
382 var cmd = dumptool + " --db " + dbName;
383 if(dumpdir)
384 cmd += ' -o' + dumpdir;
385
386
387 var date = new Date();
388 var dumpfile = dbName + '-' + date.getDate() + '-' + date.getMonth() + '-' + date.getYear() + '-'+ date.getHours() + '-'+ date.getMinutes() + '-' + date.getSeconds();
389
390 exec(cmd, function (error, stdout, stderr) {
391 if(error){
392 callback(error);
393 } else{
394 var stream = fs.createWriteStream(dumpdir + '/'+ dbName + '/README.txt');
395 stream.once('open', function(fd) {
396 stream.write('Copyrighted by EviMed online GmbH, Misusing of this file may invite legal actions!!');
397 });
398
399 var cmd_bckup = 'cd ' + dumpdir + '/' + dbName + ' && tar -zcvf ../' + dumpfile + '.gz *';
400
401 var result = {mongodump:{stdout : stdout, stderr:stderr}};
402
403 exec(cmd_bckup, function (error, stdout, stderr) {
404 result.zip_archive = {stdout : stdout, stderr:stderr, file:dumpfile}
405 callback(error, result);
406 });
407 }
408 });
409 }
410 });
411}
412
413/**
414 * To restore a database collection from a backup
415 *
416 * @method restoreCollection
417 * @param {} options database collection options
418 * @param {callback} callback The callback to excecute when complete
419 * @private
420 */
421function restoreCollection(options, callback){
422 options = options||{};
423 var restoretool = options.restoretool||dbConfiguration.restoretool||'mongorestore';
424 var dbName = options.dbName||dbConfiguration.dbName;
425 var restoredir = options.restoredir||dbConfiguration.restoredir||'./dump_import';
426
427 var collectionName = options.collectionName;
428 var filePath = options.filePath;
429
430 if(collectionName && filePath){
431 db.backup(options, function(error){
432 if(!error){
433 var date = new Date();
434 var restorefile = 'import-' + collectionName + '-' + date.getDate() + '-' + date.getMonth() + '-' + date.getYear() + '-'+ date.getHours() + '-'+ date.getMinutes() + '-' + date.getSeconds() + '.bson';
435
436 util.moveFile(restoredir, restorefile, filePath, function(error){
437 var cmd = restoretool + " -v -d " + dbName + ' -c ' + collectionName + ' ' + restoredir + '/' + restorefile;
438
439 exec(cmd, function (error, stdout, stderr) {
440 if(error){
441 callback(error);
442 } else{
443 var result = {mongorestore:{stdout : stdout, stderr:stderr}};
444 callback(error, result);
445 }
446 });
447 });
448 }else
449 callback('Some problem while taking the back up the collection');
450 });
451 } else
452 callback('Collection and file is missing!!!');
453}
454
455/**
456 * To restore a complete database from a backup
457 *
458 * @method restoreDatabase
459 * @param {} options database configuration
460 * @param {callback} callback The callback to excecute when complete
461 * @private
462 */
463function restoreDatabase(options, callback){
464 options = options||{};
465 var restoretool = options.restoretool||dbConfiguration.restoretool||'mongorestore';
466 var dbName = options.dbName||dbConfiguration.dbName;
467 var restoredir = options.restoredir||dbConfiguration.restoredir||'./dump_import';
468
469 var filePath = options.filePath;
470 var filemapping = options.filemapping||{};
471 if(filePath){
472 db.backup(options, function(error){
473 if(!error){
474 var date = new Date();
475 var inputFile = dbName + '-' + date.getDate() + '-' + date.getMonth() + '-' + date.getYear() + '-'+ date.getHours() + '-'+ date.getMinutes() + '-' + date.getSeconds();
476
477 var response = fs.createWriteStream(restoredir +'/'+ inputFile + '.gz');
478 var raw = fs.createReadStream(filePath);
479 raw.pipe(zlib.createGunzip()).pipe(response);
480
481 filePath = restoredir +'/'+ inputFile + '.gz';
482
483 util.checkDir(restoredir +'/'+ inputFile, function(error){
484 if(error)
485 callback(error);
486 else{
487 var cmd_bckup = 'tar -xvzf ' + restoredir +'/' + inputFile + '.gz' + ' -C ' + restoredir +'/'+ inputFile;
488
489 var result = {};
490 logger.getInstance().info('Simpleportal -db', 'Exeuting the extracting tool command' + cmd_bckup);
491
492 exec(cmd_bckup, function (error, stdout, stderr) {
493 if(error)
494 callback(error);
495 else{
496 fs.readdirSync(restoredir +'/'+ inputFile).forEach(function(filename){
497 if (/\.bson$/.test(filename) && filemapping[filename]) {
498 var newfilename = filemapping[filename];
499 logger.getInstance().info('Simpleportal -db', 'Renaming file filename - '+ filename + ' -- to -- '+ newfilename);
500 fs.renameSync(restoredir +'/'+ inputFile + '/' + filename, restoredir +'/'+ inputFile + '/' + newfilename);
501 }
502 });
503
504 var cmd = restoretool + " -v -d " + dbName + ' ' + restoredir +'/'+ inputFile;
505 logger.getInstance().info('Simpleportal -db', 'Executing the restore tool command' + cmd);
506
507 exec(cmd, function (error, stdout, stderr) {
508 if(error){
509 callback(error);
510 } else{
511 var result = {mongorestore:{stdout : stdout, stderr:stderr}};
512 callback(error, result);
513 }
514 });
515 }
516 });
517 }
518 });
519 } else{
520 callback('Some problem while taking the back up the collection -' + error);
521 }
522 });
523 } else
524 callback('DB and file is missing!!!');
525}
526
527/**
528 * To restore a database collection from a backup
529 *
530 * @method importCollection
531 * @param {} options Options for the restore
532 * @param {callback} callback The callback to excecute when complete
533 */
534db.importCollection = function(options, callback){
535 restoreCollection(options, callback);
536}
537
538/**
539 * To import / restore a database from an exisiting backup
540 * @method importDB
541 * @param {} options
542 * @param {callback} callback The callback to excecute when complete
543 * @return
544 */
545db.importDB = function(options, callback){
546 restoreDatabase(options, callback);
547}
548
549/**
550 * To get the BSON formatted id from the text string
551 *
552 * @method getBSONObjectId
553 * @param {string} id ID to e formatted
554 * @return {object} BSON ID object
555 */
556db.getBSONObjectId = function(id) {
557 try{
558 return new ObjectID(id);
559 } catch(error){
560 console.log(error);
561 return null;
562 }
563}
564
565/**
566 * To get the BSON Object id from hexa decimal string
567 *
568 * @method getObjectId
569 * @param {string} id text which will be used to generate the id
570 * @return formatted db object id
571 */
572db.getObjectId = function(id) {
573 return ObjectID.createFromHexString(id); /* Alternate is new BSON.ObjectID(id) */
574}
575
576db.LocalCache = require('./wrapper/localcache').LocalCache;
\No newline at end of file