Skip to content
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"curly": ["error", "all"]
},
"globals": {
"PERSISTENT": false,
"angular": false,
"$fh": false,
"FileTransfer": false,
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
npm-debug.log
.idea
.vscode

57 changes: 55 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,59 @@ camera.capture()
});
```

Example of re-init/restarting fileTransfer queues :

```javascript
fileClient.processQueue()
.then(function(hasJobs) {
console.info('Found job to process in queues, starting file-Transfer');
}, function() {
console.info('No jobs to process currently, file-Transfer idle.');
})
```

Example of saving/persisting fileTransfer queues :

```javascript
fileClient.persistQueue()
.then(function(success) {
console.info('file-Transfer queues have been saved!');
}, function(error) {
console.error('Problem saving fileTransfer queues!: ', error);
});
```

Example of saving/persisting fileTransfer queues :

```javascript
fileClient.persistQueue()
.then(function(success) {
console.info('file-Transfer queues have been saved!');
}, function(error) {
console.error('Problem saving fileTransfer queues!: ', error);
});
```


Example of adding item to `uploads` queue :

```javascript
camera.capture()
.then(function(dataUrl) {
return fileClient.uploads.addItem({
id: profileData.id,
fileName: 'my-super-img-file.png'
fileURi: dataUrl,
createdTs: Date.now(),
status: 'waiting',
retries: 3,
userId: 'trever',
step: 'rsik-assessment',
result: this.model
})
});
```

For a more complete example around files operations, please check the [demo mobile app](https://github.com/feedhenry-raincatcher/raincatcher-demo-mobile/blob/master/src/app/file/file.js).

#### Directives
Expand Down Expand Up @@ -95,8 +148,8 @@ Base url : `/file/wfm`

## Mediator events
the module publishes following topics:
- `wfm:file:detail:close` - on file detail view close.
- `wfm:file:detail:close` - on file detail view close.

Client app example:
```
mediator.subscribeForScope('wfm:file:detail:close', $scope, function() {
Expand Down
13 changes: 10 additions & 3 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
'use strict';
// 'use strict';

module.exports = {
apiHost: 'http://localhost:8080',
apiPath: '/file/wfm',
cloudDataTopicPrefix: 'wfm:cloud:data:',
datasetId: 'file'
};
datasetId: 'file',
queue: {
prefix: 'fh.wfm.file.queue.',
storageType: 'localStorage',
uploadsLabel: 'uploads',
downloadsLabel: 'downloads',
fileContentType: 'application/json'
}
};
110 changes: 80 additions & 30 deletions lib/file.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

var config = require('./config'),
QUEUE = require('./queue'),
fsModule = require('./fileSystem.js'),
q = require('q');

var client = {};
Expand All @@ -25,7 +27,31 @@ client.init = function() {
deferredReady.resolve();
}

client.initPromise = q.all([deferredFhinit.promise, deferredReady.promise]);
var deferredInitUploadsQueue = q.defer();
if (!client.uploads) {
client.uploads = new QUEUE(config.queue.uploadsLabel, config.queue.storageType) || {};
deferredInitUploadsQueue.resolve();
} else if (client.uploads.ready) {
deferredInitUploadsQueue.resolve();
}

var deferredInitDownloadsQueue = q.defer();
if (!client.downloads) {
client.downloads = new QUEUE(config.queue.downloadsLabel, config.queue.storageType) || {};
deferredInitDownloadsQueue.resolve();
} else if (client.downloads.ready) {
deferredInitUploadsQueue.resolve();
}

client.fs = fsModule.fs;

client.initPromise = q.all([
deferredFhinit.promise,
deferredReady.promise,
deferredInitUploadsQueue.promise,
deferredInitDownloadsQueue.promise
]);

return client.initPromise;
};

Expand All @@ -35,14 +61,12 @@ client.uploadDataUrl = function(userId, dataUrl) {
deferred.reject('Both userId and a dataUrl parameters are required.');
} else {
$fh.cloud({
path: config.apiPath + '/owner/'+userId+'/upload/base64/photo.png',
path: config.apiPath + '/owner/' + userId + '/upload/base64/photo.png',
method: 'post',
data: dataUrl
},
function(res) {
}, function(res) {
deferred.resolve(res);
},
function(message, props) {
}, function(message, props) {
var e = new Error(message);
e.props = props;
deferred.reject(e);
Expand All @@ -52,22 +76,19 @@ client.uploadDataUrl = function(userId, dataUrl) {
};

client.list = function(userId) {
var url = arguments.length === 0 ? config.apiPath + '/all'
: config.apiPath + '/owner/' + userId;
var url = arguments.length === 0 ? config.apiPath + '/all' :
config.apiPath + '/owner/' + userId;
var deferred = q.defer();
$fh.cloud({
path: url,
method: 'get'
},
function(res) {
deferred.resolve(res);
},
function(message, props) {
var e = new Error(message);
e.props = props;
deferred.reject(e);
}
);
}, function(res) {
deferred.resolve(res);
}, function(message, props) {
var e = new Error(message);
e.props = props;
deferred.reject(e);
});
return deferred.promise;
};

Expand All @@ -84,17 +105,16 @@ function fileUpload(fileURI, serverURI, fileUploadOptions) {

function fileUploadRetry(fileURI, serverURI, fileUploadOptions, timeout, retries) {
return fileUpload(fileURI, serverURI, fileUploadOptions)
.then(function(response) {
return response;
}, function() {
if (retries === 0) {
throw new Error("Can't upload to " + JSON.stringify(serverURI));
}
return q.delay(timeout)
.then(function() {
return fileUploadRetry(fileURI, serverURI, fileUploadOptions, timeout, retries - 1);
});
});
.then(function(response) {
return response;
}, function() {
if (retries === 0) {
throw new Error("Can't upload to " + JSON.stringify(serverURI));
}
return q.delay(timeout).then(function() {
return fileUploadRetry(fileURI, serverURI, fileUploadOptions, timeout, retries - 1);
});
});
}

client.uploadFile = function(userId, fileURI, options) {
Expand All @@ -119,6 +139,36 @@ client.uploadFile = function(userId, fileURI, options) {
}
};

client.processQueue = function() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Where is this function called from? It it called from the application consuming the module?

@col1985 col1985 Mar 15, 2017

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, the intention is to call this function from the app.js or where ever the developer would prefer. There is also an expectation the developer will handle offline and online events, saving and processing the queue as needed.

I will update README detailing this. What do you think?

return client.initPromise.then(function() {
return client.uploads.recoverQueue();
}).then(function(processingQueue) {
if (processingQueue) {
client.uploads.queue.forEach(function(item) {
if (window && window.cordova) {
return client.uploadFile(item.userId, item.filePath, {
fileName: item.fileName
});
} else {
return client.uploadDataUrl(item.userId, item.filePath);
}
});
} else {
return;
}
});
};

client.persistQueue = function() {
var d = q.defer();
client.uploads.save().then(function(success) {
d.resolve(success);
}, function(error) {
d.reject(error);
});
return d.promise;
};

client.init();

module.exports = client;
module.exports = client;
Loading