Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"env": {
"node": true,
"browser": true,
"mocha": true
},
"extends": "eslint:recommended",
"rules": {
"array-callback-return": "warn",
"brace-style": ["error", "1tbs"],
"complexity": ["warn", 20],
"eqeqeq": "error",
"guard-for-in": "error",
"indent": ["error", 2],
"linebreak-style": ["error", "unix"],
"no-array-constructor": "error",
"no-console": "warn",
"no-lonely-if": "warn",
"no-loop-func": "warn",
"no-mixed-spaces-and-tabs": ["error"],
"no-nested-ternary": "error",
"no-spaced-func": "error",
"no-trailing-spaces": "error",
"semi": ["error", "always"],
"space-before-blocks": "error",
"space-before-function-paren": ["error", "never"],
"keyword-spacing": ["error"],
"curly": ["error", "all"]
},
"globals": {
"angular": false,
"$fh": false,
"FileTransfer": false,
"FileUploadOptions": false
}
}

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
npm-debug.log
.idea
25 changes: 25 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
language: node_js
node_js:
- '0.10'
- '4.4'
sudo: false
before_install:
- npm install -g [email protected]
- npm install -g [email protected]
- npm install -g grunt-cli
install: npm install
services:
- docker
script:
- npm test
- bash <(curl https://gist.githubusercontent.com/raincatcher-bot/01ac4cdb3b0770bdb58489dbc17ed6b6/raw/6205a628c3616f6736fd866d5f0fba0a781ec1e4/sonarqube.sh)
notifications:
email: false
slack:
on_success: change
on_failure: always
rooms:
secure: >-
qrcxApjaQtD/vHsvkApXF8KBPncxPfDZmQSSWktGKuReC5MjJjPSHn658/jRNVxzJfL7Bp0TvQmVsBFNnmlXrw97p7r9rM4zOJRFMRXHXO9q7pjS/bDiJAck5nrKMBmCQfkgy+TxIO6aKErso/T8VJSJJgAP8FCbtYGrkqcvHBZka0Migy1+hyJ56+KdogTlGMSyQqAQPLzFLcwr9v7Sf/xAY2Hok0WSkpdcH4AUld9p2N5U+IZ12E2Szb9GtZmsNqL/3OzqOOWomAguXsgzxz1Morg947d9g95EStO7TlwqYu0IKo8JljmKj6k6Mu7Q2KPViPEJfTxMe0F3OJj2pAoBrM4ZZrGmr8NdNbU5YiqiWly2Z5Jwx8P8gC7HEcX89YrBzvAen1MVFLAxjnaRsca2UdwdcPdNHi67Xl6tPm4u8JE3UYzh6Wj0JO5BPDLzzvaTpzqbZTX6EvydOrwByKfRj0cfHUYInhezYoVMQa5s3sRYOTReTOvxoyoLJFY8Tv3gmRC75JIFszDz6XaWjmP8IFEyPnjo6QSTF61c6jRHJwtXgyXKwih9zbVvNgm559bmIYZBnxC36zoWde/o3WynY0EKLxjqkKyu8Lccmo9172s0rQFlC2SCmI8bUaDjClHWNUXIsscUa6NfvTJ6oget978jtdTqdxQQDSq66Do=
on_pull_requests: false

27 changes: 27 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module.exports = function(grunt){
'use strict';
require('load-grunt-tasks')(grunt);
grunt.initConfig({
eslint: {
options: {
configFile: '.eslintrc'
},
target: ["lib/**/*.js"]
},
mochify: {
options: {
reporter: 'spec'
},
unit: {
src: ['lib/**/*-spec.js']
}
},
wfmTemplate: {
module: "wfm.file.directives",
templateDir: "lib/angular/templates",
outputDir: "lib/angular/dist-templates"
}
});
grunt.registerTask('eslint', ['eslint']);
grunt.registerTask('test', ['mochify:unit']);
};
20 changes: 20 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2016 Red Hat

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
1 change: 1 addition & 0 deletions lib/client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO Add code to support offline storage capabilities for client applications.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create JIRA for this task and put here JIRA#

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is jira and I'm going to work on this after merging this PR

91 changes: 91 additions & 0 deletions lib/cloud/file-storage/awsStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
var q = require('q');
var s3 = require('s3');
var path = require('path');

var config;
var awsClient;

function init(storageConfiguration) {
config = storageConfiguration;
validateConfig();
awsClient = s3.createClient(config);
}

function writeFile(namespace, fileName, fileLocation) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could probably use a comment here describing the function and parameters.

var file;
if (namespace) {
file = path.join(namespace, fileName);
} else {
file = fileName;
}

var params = {
localFile: fileLocation,
ACL: 'authenticated-read',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a constant?

s3Params: {
Bucket: config.bucket,
Key: file
}
};

var deferred = q.defer();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are migrating to using bluebird vs q.deffered as it is an antipattern https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns#the-deferred-anti-pattern

Copy link
Contributor Author

@wtrocki wtrocki Apr 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bluebird developer telling that q api is anti pattern is not surprising.
We need to migrate to bluebird, but possibly using similar patterns across the all modules. Let's address this in our backlog as there are multiple migration steps and we should be consistent.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@witmicko KISS. We should not focus on choosing whats worse anti-pattern. If we need then we should create follow up task with refactoring after having POC that bluebird is our choice

var uploader = awsClient.uploadFile(params);
uploader.on('error', function(err) {
console.log(err);
deferred.reject(err.stack);
});
uploader.on('progress', function() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we doing anything with this progress event? If not we can probably remove the listener.

});
uploader.on('end', function() {
deferred.resolve(fileName);
});
return deferred.promise;
}

function streamFile(namespace, fileName) {
var file;
if (namespace) {
file = path.join(namespace, fileName);
} else {
file = fileName;
}
var deferred = q.defer();
var paramsStream = {
Bucket: config.bucket,
Key: file
};
try {
var buffer = awsClient.downloadStream(paramsStream);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a buffer or a stream ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ReadableStream :)

deferred.resolve(buffer);
} catch (error) {
console.log(error);
deferred.reject(error);
}
return deferred.promise;
}

function validateConfig() {
if (!config.s3Options) {
throw Error("Invalid configuration for s3 storage");
}
if (!config.s3Options.accessKeyId) {
throw Error("Invalid configuration for s3 storage: Access Key missing");
}
if (!config.s3Options.secretAccessKey) {
throw Error("Invalid configuration for s3 storage: secretAccessKeymissing");
}
if (!config.s3Options.region) {
throw Error("Invalid configuration for s3 storage: region missing");
}
}

/**
* Implements storage interface for AWS S3 storage
*
* @type {{init: function, writeFile: function, streamFile: function}}
*/
module.exports = {
init: init,
writeFile: writeFile,
streamFile: streamFile
}
73 changes: 73 additions & 0 deletions lib/cloud/file-storage/gridfsStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
var q = require('q');
var fs = require('fs');
var mongo = require('mongodb');
var Grid = require('gridfs-stream');
var MongoClient = require('mongodb').MongoClient

var gfs;

function init(storageConfiguration) {
var config = storageConfiguration;
if (!config || !config.mongoUrl) {
throw Error("Missing mongoUrl parameter for GridFs storage");
}
MongoClient.connect(config.mongoUrl, function(err, connection) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be passing back a Promise as MongoClient.connect is asynchronous?

if (err) {
return console.log("Cannot connect to mongodb server. Gridfs storage will be disabled");
}
console.log("Connected successfully to storage server");
gfs = Grid(connection, mongo);
});
}

function writeFile(namespace, fileName, fileLocation) {
if (!gfs) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think gfs should be a promise to take account of the async mongo connection.

Then you could have gfs.then(...)

console.log("Gridfs not initialized");
return;
}
var deferred = q.defer();
var options = {
filename: fileName
};
if (namespace) {
options.root = namespace;
}
var writeStream = gfs.createWriteStream(options);
writeStream.on('error', function(err) {
console.log('An error occurred!', err);
deferred.reject(err);
});

writeStream.on('close', function(file) {
deferred.resolve(file);
});
fs.createReadStream(fileLocation).pipe(writeStream);
return deferred.promise;
}

function streamFile(namespace, fileName) {
if (!gfs) {
console.log("Gridfs not initialized");
return;
}
var deferred = q.defer();
var options = {
filename: fileName
};
if (namespace) {
options.root = namespace;
}

var readstream = gfs.createReadStream(options);
readstream.on('error', function(err) {
console.log('An error occurred when reading file from gridfs!', err);
});
deferred.resolve(readstream);
return deferred.promise;
}

module.exports = {
init: init,
writeFile: writeFile,
streamFile: streamFile
};
26 changes: 26 additions & 0 deletions lib/cloud/file-storage/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
var gridfsStorage = require('./gridfsStorage');
var s3Storage = require('./awsStorage');

var client;

/**
*
* Initialising the storage engine
*
* @param config
* @returns {StorageEngine}
*/
module.exports = function(config) {
if (!client) {
if (config.s3) {
client = s3Storage;
client.init(config.s3);
} else if (config.gridFs) {
client = gridfsStorage;
client.init(config.gridFs);
} else {
throw Error("Invalid configuration passed to the module", config);
}
}
return client;
};
14 changes: 14 additions & 0 deletions lib/cloud/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
var mediatorSubscribers = require('./mediator-subscribers');
var StorageEngine = require('./file-storage');

/**
* Initialisation of the file storage module.
*
* @param {Mediator} mediator
* @param {object} config - module configuration
*/
module.exports = function(mediator, config) {
//Initialising the subscribers to topics that the module is interested in.
var storageEngine = StorageEngine(config);
return mediatorSubscribers.init(mediator, storageEngine);
};
34 changes: 34 additions & 0 deletions lib/cloud/mediator-subscribers/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
var _ = require('lodash');
var CONSTANTS = require('../../constants');


/**
* Initialising a subscriber for creating a file.
*
* @param {object} fileEntityTopics
* @param fileClient
*/
module.exports = function createFileSubscriber(fileEntityTopics, storageClient) {

/**
* Handling the file upload
*
* @param {object} parameters
* @returns {*}
*/
return function handleCreateFileTopic(parameters) {
var self = this;
parameters = parameters || {};
var fileCreateErrorTopic = fileEntityTopics.getTopic(CONSTANTS.TOPICS.CREATE, CONSTANTS.ERROR_PREFIX, parameters.topicUid);
if (!parameters.fileName || !parameters.location) {
return self.mediator.publish(fileCreateErrorTopic, new Error("Invalid Data To Create A File."));
}
storageClient.writeFile(parameters.namespace, parameters.fileName, parameters.location)
.then(function(response) {
self.mediator.publish(fileEntityTopics.getTopic(CONSTANTS.TOPICS.CREATE, CONSTANTS.DONE_PREFIX, parameters.topicUid), response);
})
.catch(function(error) {
self.mediator.publish(fileCreateErrorTopic, error);
});
};
};
Loading