I'm trying to write an image file to the localFolder storage. I want to write it specifically to the images/heroes/ folder inside the localFolder. Is there some way to do this with my existing code?
return WinJS.xhr({ url: fileToDownloadURL, responseType: 'blob' }).then(
function (response) {
var input = response.response.msDetachStream();
var filename = 'ms-appx:///local/images/heroes/image_name.png';
Windows.Storage.ApplicationData.current.localFolder.createFileAsync(filename,
Windows.Storage.CreationCollisionOption.replaceExisting).then(
function (file) {
return file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(
function (output) {
return Windows.Storage.Streams.RandomAccessStream.copyAsync(input, output).then(
function () {
output.flushAsync().then(function () {
input.close();
output.close();
});
});
});
}
}
)};
I get this error message:
0x8007007b - JavaScript runtime error: The filename, directory name, or volume label syntax is incorrect.
WinRT information: The specified name (ms-appx:///local/images/heroes/image_name.png) contains one or more invalid characters.
I figured it out. For anyone wondering, you can call
getFolderAsync('SomeFolderName')
from the
Windows.Storage.ApplicationData.current.localFolder
instance. getFolderAsync() is like any promise function and will return with an error if the folder does not exist. From there you can run
createFolderAsync('SomeFolderName')
to create the folder, and then continue what you were doing. In my case it was better to create a function like writeFileAsync() and then call it depending on whether or not the folder exists first.
Keep in mind getFolderAsync() can only get one folder at a time, so something like
getFolderAsync('along/list/of/folders')
won't work. You'll have to chain together the getFolderAsync() calls together, I believe (correct me if I'm wrong!).
Related
I have a flutter app which contains a large list of quotes, each with an associated audio file.
I've written a simple test that verifies all the specified audio files are where they're supposed to be, in case of typos etc:
test('specified audio file should exist for all quotes', () {
ALL_QUOTES.forEach((quote) {
final expectedPath = 'assets/${quote.filename}.wav';
final exists = new File(expectedPath).existsSync();
expect(exists, isTrue, reason: '$expectedPath does not exist');
});
});
This passes fine in IntelliJ, however running from the command line using flutter test it fails on the first thing it looks for.
Is there a way of doing this which will work regardless of how it's run? Why does it pass one way but not the other?
Ok so I got to the bottom of this, and it is something you can do in a unit test.
To diagnose, I added the line print(Directory.current); to the test. Running in IntelliJ, I get /home/project_name. From the command line, it's /home/project_name/test. So just a simple file path thing to resolve.
Edited to include Ovidiu's simpler logic for getting the right asset path
void main() {
test('specified audio file should exist for all quotes', () {
ALL_QUOTES.forEach((quote) {
final expectedPath = 'assets/${quote.filename}.wav';
final exists = _getProjectFile(expectedPath).existsSync();
expect(exists, isTrue, reason: '$expectedPath does not exist');
});
});
}
File _getProjectFile(String path) {
final String assetFolderPath = Platform.environment['UNIT_TEST_ASSETS'];
return File('$assetFolderPath/$path');
}
I'm not familiar enough with node.js or lambda to see an obvious solution to a dilemma I have. I'm writing some utilities on lambda to manipulate images in an S3 bucket and make them accessible via the GatewayAPI to rest calls.
BACKGROUND DETAILS:
One of the utilities I have retrieves the headObject information such as the mtime, size and metadata. The images themselves will likely be coming in from various means and I won't always have control over adding metadata to them when they arrive/are-created. But I don't really need it until it's necessary to view details about the image from a web interface. And when I do that, I use a thumbnail instead so I created a lambda create-event triggered script (and also have a fall back variation of it via the gatewayAPI) that will create a thumbnail (either when the image is first uploaded to S3 or whenever I make the gateway CreateThumbbnail call) at which time it adds metadata to the thumbnail for the image with things like the original image mimetype, pixel width and height.
What I would like to be able to do, is to create a 'GetObjectInfo' that firsts pulls the headObject data, then checks to see if the bucket specified is or is not the bucket with the associated thumbnail files. (e.g. if it is or is not a thumbnail object) If it is 'not' a thumbnail, I want to then go retrieve -- or at least attempt to retrieve -- the headObject for the associated thumbnail file and attach the thumbnail file's metadata (if the thumbnail exists) onto the data from the original head request before returning the information.
The problem is, that when I set up an async callback scheme, the first headObject request completes, the second never seems to get out of the starting gate.
The method in my class is:
getHeadObject(bucket,object,callback) {
console.log(bucket, "CLASS-head#1")
this.s3.headObject({"Bucket":bucket,"Key":object}, function(err,data){
console.log(bucket, "CLASS-head#2")
callback(err,data)
})
}
getObjectInfo(bucket,object,callback) {
let scope = this
console.log(bucket,"CLASS-object#1")
this.getHeadObject(bucket,object,function(err,data) {
console.log(bucket,"CLASS-object#2")
if(err)
callback(err,data)
else
callback(null,data)
})
}
The lambda code that calls it recursively is:
var cInst = new myClass()
cInst.getObjectInfo(srcBucket,filePath,function(err,data) {
if(data.status == 1) { // if parent request success
// if parent is not thumbnail
if(srcBucket != THUMB_BUCKET) { // see if a thumbnail exists
let thumbPath = myClass.getThumbPath(srcBucket,userId,directory,targetObject)
console.log('---- thumbPath', thumbPath)
cInst.getObjectInfo(THUMB_BUCKET,thumbPath, function(err,thumbData) {
console.log("thumbData #1",thumbData)
if(thumbData.status == 1) { // thumbnail exists
console.log("thumbData")
}
})
}
context.succeed(myClass.createResponse(1, data, api))
} else {
context.fail(myClass.createResponse(data.status, data, api))
}
})
First call on the parent is see
{bucket} "CLASS-object#1"
{bucket} "CLASS-head#1"
{bucket} "CLASS-head#2"
{bucket} "CLASS-object#2"
on the second I only see:
image-thumbnails "CLASS-object#1"
image-thumbnails "CLASS-head#1"
(getThumbPath is just a static utility function that builds the thumbnail path based on the parameters related to the original file. It is already tested as working and produces something like {original-bucket-name}/{userid}/{subdirectory}/{file-basename_150x150.jpg} for any given image - I confirmed that in this instance, the thumbnail exists and matches the path returned by getThumbPath and the acl appears to have permission to read the bucket and the object)
UPDATE: More weirdness
I tried setting the permissions to publicly readable on the thumbnail and it worked. So I started messing with the acl. For the time being since I am still testing, I just gave the role for the scripts full S3 permissions.
But I noticed now that it's working and not working intermittently. One time it completes, the next time it doesn't. WTF is going on here?
I would bet that this is the most common problem that people see when using Node.js with Lambda.
When a Node.js Lambda reaches the end of the main thread, it ends all other threads. When it reaches the end of the handler, it stops all concurrent promises or async calls that are running.
To make sure that the lambda does not prematurely terminate those threads, wait until those promises are complete by using await.
In your case, the following will work: wrap any async calls in a promise and then await them.
await new Promise(async (resolve, reject) => {
cInst.getObjectInfo(srcBucket,filePath,function(err,data) {
if(data.status == 1) {
if(srcBucket != THUMB_BUCKET) {
...
...
await new Promise((resolve2, reject2) => {
cInst.getObjectInfo(THUMB_BUCKET,thumbPath, function(err,thumbData) {
...
...
resolve2();
})
})
}
context.succeed(myClass.createResponse(1, data, api))
resolve();
} else {
context.fail(myClass.createResponse(data.status, data, api))
reject();
}
})
})
I am filtering projects with a computed property like this:
filtered_projects() {
return this.projects.filter( (project) => {
return project.title.toLowerCase().indexOf(this.project_filter.toLowerCase()) !== -1
})
}
When I add a new project using this
submitNewProject() {
let path = '/api/projects';
Vue.http.post(path, this.project)
.then( (rsp) => {
this.projects.push(rsp.data);
this.project = this.getSingleProject();
this.create_project = false;
return true;
});
}
This is giving me an error that I can't find
TypeError: Cannot read property 'toLowerCase' of undefined
It may just be that you are not correctly passing the projects data to the projects array.
Firstly vue-resource now uses body not data to get the response, therefore you may need to use:
this.projects.push(rsp.body)
then this will give you a single array item containing all projects which doesn't look like what you want. I believe instead you're after:
this.projects = rsp.body
Assuming the response body is an array of objects this will then allow:
this.projects.filter(project => {})
to work as expected. Meaning project.title should now be valid
EDIT
For a project title to be set to lowerCase you must be returning an object with a title param, i.e.
rsp.body = {
title: 'FOO',
}
which you'd then set on the projects array via:
this.projects.push(rsp.body)
so the first thing to fix is your response, sort your endpoint so it returns what you are expecting, then the rest of the above code should work
You need preserve "this" before Vue.http.post (self=this) and then in callback change this.projects to self.projects.
Explanation:
How to access the correct `this` context inside a callback?
I am using dropzonejs and using following code to initialize dropzone:
var myDropzone = new Dropzone("div#myId", { url: "/file/post"});
On the server side, I am using expressjs\nodejs & using following code:
fs.readFile(req.files.displayImage.path, function (err, data) {
// ...
var newPath = __dirname + "/uploads/uploadedFileName";
fs.writeFile(newPath, data, function (err) {
res.redirect("back");
});
});
problem is req.files is always coming as undefined.
I want to know when we upload a file, is there a way through developertoolbar to check the payload & confirm whether file is been sent or not?
I created an upload script in node.js using express/formidable. It basically works, but I am wondering where and when to check the uploaded file e. g. for the maximum file size or if the file´s mimetype is actually allowed.
My program looks like this:
app.post('/', function(req, res, next) {
req.form.on('progress', function(bytesReceived, bytesExpected) {
// ... do stuff
});
req.form.complete(function(err, fields, files) {
console.log('\nuploaded %s to %s', files.image.filename, files.image.path);
// ... do stuff
});
});
It seems to me that the only viable place for checking the mimetype/file size is the complete event where I can reliably use the filesystem functions to get the size of the uploaded file in /tmp/ – but that seems like a not so good idea because:
the possibly malicious/too large file is already uploaded on my server
the user experience is poor – you watch the upload progress just to be told that it didnt work afterwards
Whats the best practice for implementing this? I found quite a few examples for file uploads in node.js but none seemed to do the security checks I would need.
With help from some guys at the node IRC and the node mailing list, here is what I do:
I am using formidable to handle the file upload. Using the progress event I can check the maximum filesize like this:
form.on('progress', function(bytesReceived, bytesExpected) {
if (bytesReceived > MAX_UPLOAD_SIZE) {
console.log('### ERROR: FILE TOO LARGE');
}
});
Reliably checking the mimetype is much more difficult. The basic Idea is to use the progress event, then if enough of the file is uploaded use a file --mime-type call and check the output of that external command. Simplified it looks like this:
// contains the path of the uploaded file,
// is grabbed in the fileBegin event below
var tmpPath;
form.on('progress', function validateMimetype(bytesReceived, bytesExpected) {
var percent = (bytesReceived / bytesExpected * 100) | 0;
// pretty basic check if enough bytes of the file are written to disk,
// might be too naive if the file is small!
if (tmpPath && percent > 25) {
var child = exec('file --mime-type ' + tmpPath, function (err, stdout, stderr) {
var mimetype = stdout.substring(stdout.lastIndexOf(':') + 2, stdout.lastIndexOf('\n'));
console.log('### file CALL OUTPUT', err, stdout, stderr);
if (err || stderr) {
console.log('### ERROR: MIMETYPE COULD NOT BE DETECTED');
} else if (!ALLOWED_MIME_TYPES[mimetype]) {
console.log('### ERROR: INVALID MIMETYPE', mimetype);
} else {
console.log('### MIMETYPE VALIDATION COMPLETE');
}
});
form.removeListener('progress', validateMimetype);
}
});
form.on('fileBegin', function grabTmpPath(_, fileInfo) {
if (fileInfo.path) {
tmpPath = fileInfo.path;
form.removeListener('fileBegin', grabTmpPath);
}
});
The new version of Connect (2.x.) has this already baked into the bodyParser using the limit middleware: https://github.com/senchalabs/connect/blob/master/lib/middleware/multipart.js#L44-61
I think it's much better this way as you just kill the request when it exceeds the maximum limit instead of just stopping the formidable parser (and letting the request "go on").
More about the limit middleware: http://www.senchalabs.org/connect/limit.html