Node JS promisified services

Date: 2016-07-04

A promisified file system:

var fs = require('fs');
var Promise = require('bluebird');

fs = Promise.promisifyAll(fs);

module.exports = fs;

A promisified FTP service:

var config = require('../config');
var Promise = require('bluebird');
var log = require('../services/logService');
var fs = require('../services/fsService');
var FtpClient = require('ftp');

var ftp = {};

var _connectionPromise = null;

ftp.getConnectionAsync = function () {
    if (!_connectionPromise) {
        _connectionPromise = new Promise(function (resolve, reject) {
            var c = new FtpClient();
            c.connect({
                host: config.ftp.host, // string - The hostname or IP address of the FTP server. Default: 'localhost'
                port: config.ftp.port, // integer - The port of the FTP server. Default: 21
                secure: config.ftp.secure, // mixed - Set to true for both control and data connection encryption,
                // 'control' for control connection encryption only, or
                // 'implicit' for implicitly encrypted control connection (this mode is deprecated in modern times, but usually uses port 990) Default: false
                secureOptions: {
                    rejectUnauthorized: false,
                    checkServerIdentity: function(servername, cert) {}
                }, // object - Additional options to be passed to tls.connect(). Default: (none)
                user: config.ftp.user, // string - Username for authentication. Default: 'anonymous'
                password: config.ftp.password, // - string - Password for authentication. Default: 'anonymous@'
                connTimeout: 10000, // - integer - How long (in milliseconds) to wait for the control connection to be established. Default: 10000
                pasvTimeout: 10000, // - integer - How long (in milliseconds) to wait for a PASV data connection to be established. Default: 10000
                keepalive: 10000 // - integer - How often (in milliseconds) to send a 'dummy' (NOOP) command to keep the connection alive. Default: 10000
            });
            c.on('ready', function () {
                c = Promise.promisifyAll(c);
                resolve(c);
            });
            c.on('error', function(error) {
                reject(error);
            });
        });
    }
    return _connectionPromise;
};

ftp.closeConnectionAsync = function() {
    return ftp.getConnectionAsync()
        .then(function(c) {
            c.end();
        })
        .timeout(2000)
        .finally(function() {
            _connectionPromise = null;
            return Promise.resolve('Connection closed');
        });
};

ftp.onError = function(error) {
    var stack = new Error().stack;
    log.error(error);
    log.error(stack);
    return ftp.closeConnectionAsync()
        .finally(function() {
            return Promise.reject(error);
        });
};

var writeStreamToFile = function(stream, fileName) {
    return new Promise(function(resolve, reject) {
        stream.once('close', resolve);
        stream.on('error', reject);
        stream.pipe(fs.createWriteStream(fileName));
    });
};

ftp.lsAsync = function(folder) {
    return ftp.getConnectionAsync()
        .then(function(c) {
            return c.listAsync(folder);
        })
        .catch(ftp.onError);
};

ftp.getAsync = function(remotePath, localPath) {
    return ftp.getConnectionAsync()
        .then(function(c) {
            return c.getAsync(remotePath)
                .then(function(stream) {
                    return writeStreamToFile(stream, localPath);
                });
        })
        .catch(ftp.onError);
};

ftp.putAsync = function(localPath, remotePath) {
    return ftp.getConnectionAsync()
        .then(function(c) {
            return c.putAsync(localPath, remotePath);
        })
        .catch(ftp.onError);
};

ftp.deleteAsync = function(remotePath) {
    return ftp.getConnectionAsync()
        .then(function(c) {
            return c.deleteAsync(remotePath);
        })
        .catch(ftp.onError);
};

ftp.renameAsync = function(remotePath, newRemotePath) {
    return ftp.getConnectionAsync()
        .then(function(c) {
            return c.renameAsync(remotePath, newRemotePath);
        })
        .catch(ftp.onError);
};

module.exports = ftp;

A promisified ODBC service:

var config = require('../config');
var Promise = require('bluebird');
var log =  require('../services/logService');

var db = require('odbc')();
db = Promise.promisifyAll(db);

var _db = null;
db.getDB = function() {
	if (_db) {
		return Promise.resolve(_db);
	}
    log.info('opening database connection ..');
	return db.openAsync(config.odbc.connectionString)
		.then(function(){
            log.info('database connection opened.');
			_db = db;
			return Promise.resolve(_db);
		});
};

db.closeDB = function() {
    if (_db) {
        log.info('closing database connection ..');
		db.closeSync();
		log.info('database connection closed.');

        // return db.closeAsync(function () {
        //     log.info('database connection closed.');
		// 	return Promise.resolve('OK');
        // });
    }
    return Promise.resolve('OK');
};

module.exports = db;

A promisified Samba client:

var config = require('../config');
var Promise = require('bluebird');
var SambaClient = require('samba-client');

var client = new SambaClient({
    address: config.smb.share // required
        // username: 'test', // not required, defaults to guest
        // password: 'test', // not required
});

client = Promise.promisifyAll(client);

module.exports = client;

A promisified (recursive) mkdir:

var mkdirp = require('mkdirp');

var Promise = require('bluebird');

mkdirp = Promise.promisify(mkdirp);	// single function

module.exports = mkdirp;

A (unpromisified) bunyan logger service:

var config = require('../config');

var bunyan = require('bunyan');

function MyRawStream() {};
MyRawStream.prototype.write = function (rec) {
    console.log('[%s] %s: %s',
        rec.time.toISOString(),
        bunyan.nameFromLevel[rec.level],
        rec.msg);
};

var log = bunyan.createLogger({
    name: config.log.loggerName,
    streams: [{
        level: config.log.level,
        stream: new MyRawStream(),
        type: 'raw'
    }, {
        level: config.log.level,
        path: config.log.file, // log ERROR and above to a file
	type: 'rotating-file',
	period: '1d',
	count: 3 
    }]
});

log.on('error', function (err, stream) {    
	console.log('[%s] %s: %s',
        new Date().toISOString(),
        "ERROR",
        err,
	stream);
});


// examle usage
//log.info({message: 'test', status: 'ok'});

module.exports = log;

1820cookie-checkNode JS promisified services