How to save multiple files in a chrome app - javascript

I am trying to save multiple files to a directory - in one operation. If I correctly understand the chrome fileSystem api documentation this should be possible when I use the openDirectory option for chrome.fileSystem.chooseEntry. Is that even allowed?
However, the documentation is very minimalistic and I also did not find any examples via google.
More background:
I have the proper permissions to access a directory and also have write permissions:
/*you need chrome >= Version 31.x [currently chrome beta]*/
"permissions": [
{"fileSystem": ["write", "directory"]}, "storage",
]
Then you are left with chrome.fileSystem.chooseEntry(object options, function callback) and chrome.fileSystem.getWritableEntry(entry entry, function callback), but I did not figure out if these functions are even what I want.
Here is how a single file can be saved to the file system:
chrome.fileSystem.chooseEntry({type:"saveFile", suggestedName:"image.jpg"},
function(entry, array){
save(entry, blob); /*the blob was provided earlier*/
}
);
function save(fileEntry, content) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
fileWriter.onwriteend = null;
fileWriter.truncate(content.size);
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
var blob = new Blob([content], {'type': 'image/jpeg'});
fileWriter.write(blob);
}, errorHandler);
}
But how can I save multiple files when I use chrome.fileSystem.chooseEntry({type:"openDirectory",..} or does openDirectory only grant me read-rights?

I believe this should work.
chrome.fileSystem.chooseEntry({type:'openDirectory'}, function(entry) {
chrome.fileSystem.getWritableEntry(entry, function(entry) {
entry.getFile('file1.txt', {create:true}, function(entry) {
entry.createWriter(function(writer) {
writer.write(new Blob(['Lorem'], {type: 'text/plain'}));
});
});
entry.getFile('file2.txt', {create:true}, function(entry) {
entry.createWriter(function(writer) {
writer.write(new Blob(['Ipsum'], {type: 'text/plain'}));
});
});
});
});

Related

how to create or write a file in android on phonegap?

I am using below code to write a file on android using PhoneGap, I think that this line window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) { is giving the error, can't find the exact error, just because I can't debug on android.
I find PhoneGap documentation confusing.
function download_file(cur_filename)
{
alert(5);
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
alert(2);
console.log('file system open: ' + fs.name);
alert(3);
fs.root.getFile(cur_filename, { create: true, exclusive: false }, function (fileEntry) {
alert("fileEntry is file?" + fileEntry.isFile.toString());
// fileEntry.name == 'someFile.txt'
fileEntry.name==cur_filename;
// fileEntry.fullPath == '/someFile.txt'
writeFile(fileEntry, null);
}, onErrorCreateFile);
}, onErrorLoadFs);
}
function writeFile(fileEntry, dataObj) {
aler(4);
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function() {
console.log("Successful file write...");
readFile(fileEntry);
};
fileWriter.onerror = function (e) {
console.log("Failed file write: " + e.toString());
};
// If data object is not passed in,
// create a new Blob instead.
if (!dataObj) {
dataObj = new Blob(['some file data'], { type: 'text/plain' });
}
fileWriter.write(dataObj);
});
}
Firstly, you can directly download the file rather than having to create and write a new one. You need to first install the following plugins
cordova plugin add cordova-plugin-file
cordova plugin add cordova-plugin-file-transfer
Now, you need to enclose the below logic inside deviceready event in case you are accessing plugins on app launch. The file-transfer ships with a download() that you need to use for downloading your file. Please find a sample code below
document.addEventListener("deviceready", startDownload, false);
function startDownload() {
var fileTransfer = new FileTransfer();
// replace uri with -> http://192.168.43.54/text.csv
var uri = encodeURI("https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_1920_18MG.mp4");
fileTransfer.download(
uri,
cordova.file.dataDirectory + 'videos/big_buck_bunny_720p_1mb.mp4',
function(entry) {
console.log("download complete: ", entry);
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("download error code" + error.code);
}
);
}
Once the download is completed, the entry object will have a nativeURL property that holds the local URL to the file.
More info
File Plugin
File-Transfer Download

Firefox WebExtensions, get local files content by path

I'm trying to write a small add-on for firefox using the WebExtensions structure.
This add-on should read a local file content by it's absolute path:
"/home/saba/desktop/test.txt"
manifest.json
{
"manifest_version": 2,
"name": "Test - load files",
"version": "0.0.1",
"description": "Test - load files",
"permissions": [ "<all_urls>" ],
"background": {
"scripts": [ "main.js" ]
}
}
Here what I tried so far (inside the main.js):
Using XMLHttpRequest
function readFileAjax(_path){
var xhr = new XMLHttpRequest();
xhr.onloadend = function(event) {
console.log("onloadend", this);
};
xhr.overrideMimeType("text/plain");
xhr.open("GET", "file:///"+_path);
xhr.send();
}
readFileAjax("/home/saba/desktop/test.txt");
Failed.
I can't figure out why it always return an empty response
(test.txt contains "test", the path is correct)
onloadend XMLHttpRequest {
onreadystatechange: null,
readyState: 4,
timeout: 0,
withCredentials: false,
upload: XMLHttpRequestUpload,
responseURL: "",
status: 0,
statusText: "",
responseType: "",
response: ""
}
Using FileReader
function readFileFR(_path){
var reader = new FileReader();
reader.addEventListener("loadend", function() {
console.log("loadend", this.result)
});
reader.readAsText(file); // file ????
}
readFileFR("/home/saba/desktop/test.txt");
but here I got stuck because of the file argument.
This method usually get along with an input type="file" tag which gives back a .files array. (but I only have a local path string)
I searched if was possible to create a new Blob or File var using an absolute local file path but seams like it's not possible.
Using WebExtensions API
I didn't find any clue form the documentation pages on how to do this.
Isn't there (maybe) some kind of WebExtensions API which makes this possible like in the SDK?
https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/io_file
https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/io_text-streams
What am I doing wrong or missing?
..is it possible to get the content of a local file by it's absolute path with a WE Add-on?
I finally found the way to do this using the Fetch requests and FileReader APIs.
Here what I came up to:
function readFile(_path, _cb){
fetch(_path, {mode:'same-origin'}) // <-- important
.then(function(_res) {
return _res.blob();
})
.then(function(_blob) {
var reader = new FileReader();
reader.addEventListener("loadend", function() {
_cb(this.result);
});
reader.readAsText(_blob);
});
};
Using the example in my question this is how to use it:
readFile('file:///home/saba/desktop/test.txt', function(_res){
console.log(_res); // <-- result (file content)
});
ES6 with promises
If you prefer to use Promises rather than callbacks:
let readFile = (_path) => {
return new Promise((resolve, reject) => {
fetch(_path, {mode:'same-origin'})
.then(function(_res) {
return _res.blob();
})
.then(function(_blob) {
var reader = new FileReader();
reader.addEventListener("loadend", function() {
resolve(this.result);
});
reader.readAsText(_blob);
})
.catch(error => {
reject(error);
});
});
};
Using it:
readFile('file:///home/saba/desktop/test.txt')
.then(_res => {
console.log(_res); // <-- result (file content)
})
.catch(_error => {
console.log(_error );
});
This doesn't work, or at least not any longer taking the accepted answer into consideration.
Addon's run in a fake root meaning you can only ever access files which have been
Shipped with your extension [1] using e.g. fetch() or
Opened interactive (meaning initiated by the user using either the file
picker or drag&drop) through the File() constructor [2]
Everything else will lead to a Security Error: Content at moz-extension://... may not load data from file:///... causing fetch() to throw the aforementioned TypeError: NetworkError when attempting to fetch resource.
[1] https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/web_accessible_resources
[2] https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Working_with_files#open_files_in_an_extension_using_a_file_picker

Image File Download issue in ionic for iOS platform

I am trying to download some image files and store it for offline accessibility purpose of the app using Ionic framework. I have used two Cordova plugins named "Cordova-plugin-file" and "Cordova-plugin-file transfer". My code works on Android but faces a strange issue in iOS platform.
Error in Success callbackId: FileTransfer552364304 : TypeError: null
is not an object (evaluating 'result.lengthComputable'),
callbackFromNativecordova.js
Sometimes the code works, sometimes it throws me this error. Also I cannot access the error from my javascript code. Can anyone help? The code snippet is given below:
downloadImage: function(url, fileName) {
var deferred = $q.defer();
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
fs.root.getDirectory(
LOCAL_STORAGE_KEYS.app, {
create: true
},
function(dirEntry) {
// console.log(arguments);
dirEntry.getFile(
fileName, {
create: true,
exclusive: false
},
function(fe) {
console.log(arguments);
var p = fe.toURL();
console.log("In service the url path:", p);
fe.remove();
var ft = new FileTransfer();
console.log('File Transfer instance:',ft);
ft.download(
encodeURI(url),
p,
function(entry) {
console.log('In service the entry callback:',entry);
if (entry && entry.toURL) {
deferred.resolve(entry.toURL());
} else {
deferred.resolve();
}
},
function(err) {
console.log('Getting rejected:',err);
deferred.reject(err);
},
false,
null
);
},
function() {
deferred.reject(new Error('get file failed'));
}
);
}
);
},
function() {
deferred.reject(new Error('get directory failed'));
});
return deferred.promise;
}

Chrome Apps : How to save blob content to fileSystem in the background?

In Chrome Apps, I'm downloading a blob content from a server using JavaScript XHR (Angular $http GET in particular, with response type 'blob')
How should I save this to chrome application's file system?
Currently using an Angular wrapper on HTML5 filesystem API
https://github.com/maciel310/angular-filesystem
I do not want to show user a popup (hence I can't use chrome.fileSystem. chooseEntry )
The chrome.fileSystem.requestFileSystem API is only supported by Kiosk-only apps.
Hence I'm using HTML5 FileSystem API instead of chrome's.
I'm using following code to make XHR to fetch blob.
$http({
url: SERVER_URL+"/someVideo.mp4",
method: "GET",
responseType: "blob"
}).then(function(response) {
console.log(response);
fileSystem.writeBlob(response.name, response).then(function() {
console.log("file saved");
}, function(err) {
console.log(err);
});
}, function (response) {
});
This is my writeBlob method
writeBlob: function(fileName, blob, append) {
append = (typeof append == 'undefined' ? false : append);
var def = $q.defer();
fsDefer.promise.then(function(fs) {
fs.root.getFile(fileName, {create: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
if(append) {
fileWriter.seek(fileWriter.length);
}
var truncated = false;
fileWriter.onwriteend = function(e) {
//truncate all data after current position
if (!truncated) {
truncated = true;
this.truncate(this.position);
return;
}
safeResolve(def, "");
};
fileWriter.onerror = function(e) {
safeReject(def, {text: 'Write failed', obj: e});
};
fileWriter.write(blob);
}, function(e) {
safeReject(def, {text: "Error creating file", obj: e});
});
}, function(e) {
safeReject(def, {text: "Error getting file", obj: e});
});
}, function(err) {
def.reject(err);
});
return def.promise;
},
This shows SECURITY_ERR as It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources.
What's the solution for this?
I've tried using --allow-file-access-from-files flag while launching app. It doesn't help.
Chrome Application's sandbox storage doesn't allow files to be stored in root directory (i.e. / )
Modify the code to save it in a specific sub-directory under it.
For example -
fileSystem.writeBlob("/new"+response.name, response).then(function() {
console.log("file saved");
}, function(err) {
console.log(err);
});
This would successfully save the file under /new/ directory.
To expand on this, here is a full example app on how to download a file and save the blob and display it back to the user.
https://github.com/PierBover/chrome-os-app-download-example

Meteor: Not able to upload image to S3 using CollectionFS

I am trying to test the upload functionality using this guide with the only exception of using cfs-s3 package. This is very basic with simple code but I am getting an error on the client console - Error: Access denied. No allow validators set on restricted collection for method 'insert'. [403]
I get this error even though I have set the allow insert in every possible way.
Here is my client code:
// client/images.js
var imageStore = new FS.Store.S3("images");
Images = new FS.Collection("images", {
stores: [imageStore],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
Images.deny({
insert: function(){
return false;
},
update: function(){
return false;
},
remove: function(){
return false;
},
download: function(){
return false;
}
});
Images.allow({
insert: function(){
return true;
},
update: function(){
return true;
},
remove: function(){
return true;
},
download: function(){
return true;
}
});
And there is a simple file input button on the homepage -
// client/home.js
'change .myFileInput': function(e, t) {
FS.Utility.eachFile(e, function(file) {
Images.insert(file, function (err, fileObj) {
if (err){
console.log(err) // --- THIS is the error
} else {
// handle success depending what you need to do
console.log("fileObj id: " + fileObj._id)
//Meteor.users.update(userId, {$set: imagesURL});
}
});
});
}
I have set the proper policies and everything on S3 but I don't think this error is related to S3 at all.
// server/images.js
var imageStore = new FS.Store.S3("images", {
accessKeyId: "xxxx",
secretAccessKey: "xxxx",
bucket: "www.mybucket.com"
});
Images = new FS.Collection("images", {
stores: [imageStore],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
I have also published and subscribed to the collections appropriately. I have been digging around for hours but can't seem to figure out what is happening.
EDIT: I just readded insecure package and everything now works. So basically, the problem is with allow/deny rules but I am actually doing it. I am not sure why it is not acknowledging the rules.
You need to define the FS.Collection's allow/deny rules in sever-only code. These are server-side rules applied to the underlying Mongo.Collection that FS.Collection creates.
The best approach is to export the AWS keys as the following environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, remove the accessKeyId and secretAccessKey options from the FS.Store, and then move the FS.Collection constructor calls to run on both the client and server. The convenience of using env vars is mentioned on the cfs:s3 page
In addition to this you can control the bucket name using Meteor.settings.public, which is handy when you want to use different buckets based on the environment.

Categories

Resources