fetch array buffer random behavior - blob

I want to fetch directly an arrayBuffer using the fetch api (https://fetch.spec.whatwg.org/). Once the data is returned, I want to use the array buffer.
It appears that sometimes arrayBuffer() works and sometimes it doesn't. By doesn't work I mean sometimes it returns an empty array. Most of the time it does not work.
fetch(url).then(function(response) {
response.arrayBuffer().then(function(buffer){
results[i] = buffer;
});
});
If I call blob() and convert it to an array buffer via FileReader it always works.
fetch(url).then(function(response) {
response.blob().then(function(buffer){
results[i] = buffer;
});
});
...
var myReader = new FileReader();
myReader.addEventListener("loadend", function(e){
// ALWAYS GOOD
var byteArray = new Uint8Array(e.srcElement.result);
});
myReader.readAsArrayBuffer(results[0]);
And a live demo:
http://codepen.io/nicolasrannou/pen/OVLyjX
Am I doing something wrong or is it a bug?
Thanks,
Nicolas

Related

Sending response in async function

I need to return an array of labels, but I can only return 1 of the labels so far. The error which I get is "Cannot set headers after they are sent to the client". So I tried res.write and placed res.end after my for loop then I get the obvious error of doing a res.end before a res.write. How do I solve this?
for(let i=0;i<arr.length;i++){
request.get(arr[i], function (error, response, body) {
if (!error && response.statusCode == 200) {
myfunction();
async function myfunction(){
const Labels = await Somefunctioncallwhoseresponseigetlater(body)
res.send(Labels);
}
}
});}
New code-
async function getDataSendResponse(res) {
let allLabels = [];
for (let url of arr) {
let body = await got(url).buffer();
var imgbuff= Buffer.from(body,'base64')
const imageLabels = await rekognition.detectLabels(imgbuff);
allLabels.push(...imageLabels);
}
res.send(allLabels);
}
The error I have with this code is
"Resolver: AsyncResolver
TypeError: Cannot destructure property Resolver of 'undefined' or 'null'."
You are trying to call res.send() inside a for loop. That means you'll be trying to call it more than once. You can't do that. You get to send one response for any given http request and res.send() sends an entire response. So, when you try to call it again inside the loop, you can the warning you see.
If what you're trying to do is to send an array of labels, then you need to accumulate the array of labels first and then make one call to res.send() to send the final array.
You don't show the whole calling context here, but making the following assumptions:
Somefunctioncallwhoseresponseigetlater() returns a promise that resolves when it is done
You want to accumulate all the labels you collected in your loop
Your Labels variable is an array
Your http request returns a text response. If it returns something else like JSON, then .text() would need to be changed to .json().
then you can do it like this:
const got = require('got');
async function getDataSendResponse(res) {
let allLabels = [];
for (let url of arr) {
let body = await got(url).buffer();
const labels = await Somefunctioncallwhoseresponseigetlater(body);
allLabels.push(...labels);
}
res.send(allLabels);
}
Note, I'm using the got() library instead of the deprecated request() library both because request() is not deprecated and because this type of code is way easier when you have an http library that supports promises (like got() does).

HapiJS reply with readable stream

For one call, I am replying with a huge JSON object which sometimes causes the Node event loop to become blocked. As such, I'm using Big Friendly JSON package to stream JSON instead. My issue is I cannot figure out how to actually reply with the stream
My original code was simply
let searchResults = s3Access.getSavedSearch(guid)).Body;
searchResults = JSON.parse(searchResults.toString());
return reply(searchResults);
Works great but bogs down on huge payloads
I've tried things like, using the Big Friendly JSON package https://gitlab.com/philbooth/bfj
const stream = bfj.streamify(searchResults);
return reply(stream); // according to docs it's a readable stream
But then my browser complained about an empty response. I then tried to add the below to the reply, same result.
.header('content-encoding', 'json')
.header('Content-Length', stream.length);
I also tried return reply(null, stream); but that produced a ton of node errors
Is there some other way I need to organize this? My understanding was I could just reply a readable stream and Hapi would take care of it, but the response keeps showing up as empty.
Did you try to use h.response, here h is reply.
Example:
handler: async (request, h) => {
const { limit, sortBy, order } = request.query;
const queryString = {
where: { status: 1 },
limit,
order: [[sortBy, order]],
};
let userList = {};
try {
userList = await _getList(User, queryString);
} catch (e) {
// throw new Boom(e);
Boom.badRequest(i18n.__('controllers.user.fetchUser'), e);
}
return h.response(userList);
}

BitmapEncoder FlushAsync() never returns

I've scoured the web for this and not found a solution yet. I have a DispatchTimer in my Universal phone app. On each tick, I want to capture a portion of the screen and save it to JPEG. My code seems very straightforward, and there are no crashes -- it simply never returns from the FlushAsync(). It seems like it must be a deadlock scenario, but I haven't been able to find where the conflict is yet:
using (var ms = new MemoryStream())
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(ctrl);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
using (var ras = ms.AsRandomAccessStream())
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ras, propertySet);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint) renderTargetBitmap.PixelWidth,
(uint) renderTargetBitmap.PixelHeight,
logicalDpi, logicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
return ms.ToArray();
}
Any help would be great! I've been at this for hours, trying different ways to get it working with no luck.
I figured it out! Turns out you can't just use MemoryStream.AsRandomAccessStream() as your encoder destination. Turns out you should just use the InMemoryRandomAccessStream, then afterwards get the bytes:
byte[] bytes = new byte[ras.Size];
await ras.AsStream().ReadAsync(bytes, 0, bytes.Length);
return bytes;
Not sure why MemoryStream caused the problem it did, but this is a pretty easy fix! I hope this helps someone else.

ASP.NET MVC 4 return Json resulting in double json or empty data

I am getting either empty Json results or double json results and I don't know why yet?
base line:
http://learn.knockoutjs.com/mail?folder=Inbox
looks like this in chrome F12: {"id":"Inbox","mails":[{"id":1,......}
My Action:
public ActionResult Mail()
{
string qs = "";
foreach (var q in Request.QueryString)
{
qs += string.Format("{0}={1}&", q, Request.QueryString[q.ToString()]);
}
var proxyRequest = "http://learn.knockoutjs.com/mail?" + qs;
var request = WebRequest.Create(proxyRequest);
var response = (HttpWebResponse)request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
var str = reader.ReadToEnd();
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(str);
//var json = JsonConvert.SerializeObject(data);
// Text Visualization looks good {"id":"Inbox","mails":[{"id":1,"from":"Abb....}
// no outside quotes, no escaped quotes
var res = Json(data, JsonRequestBehavior.AllowGet);
return res;
}
So basically I am proxying the call, but the question is why is the result coming back as either not filled in or double jsoned.
using chrome network trace the result of the above looks like.
[[[]],[[[[[]],[[]],[[]],[[]],[[]],...]
valid json, just empty.
when I change the code to look like this
var json = JsonConvert.SerializeObject(data);
// Text Visualization looks good {"id":"Inbox","mails":[{"id":1,"from":"Abb....}
// no outside quotes, no escaped quotes
var res = Json(json, JsonRequestBehavior.AllowGet);
return res;
Chrome network trace has doubled jsoned the data.
"{\"id\":\"Inbox\",\"mails\":[{\"id\":1,\"from\":\"Ab....}"
Since I don't know what the Json actually is, I did newton soft dynamic convert
JsonConvert.DeserializeObject
That may be the problem behind my empty response?
Any help would really be appreciated.
Thanks
Your first method is failing because Json() doesn't understand the dynamic object returned from your JSON reader.
Your second method is failing because Json() is serializing a pre-serialized string.
You can return pre-serialized JSON data using Content(jsonString, "application/json")

Closing stream after using BitmapEncoder with WinJS Metro app

In a Windows 8 Metro application written in JS I open a file, get the stream, write some image data to it using the 'promise - .then' pattern. It works fine - the file is successfully saved to the file system, except after using the BitmapEncoder to flush the stream to the file, the stream is still open. ie; I can't access the file until I kill the application, but the 'stream' variable is out of scope for me to reference, so I can't close() it. Is there something comparable to the C# using statement that could be used?
...then(function (file) {
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
})
.then(function (stream) {
//Create imageencoder object
return Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream);
})
.then(function (encoder) {
//Set the pixel data in the encoder ('canvasImage.data' is an existing image stream)
encoder.setPixelData(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, canvasImage.width, canvasImage.height, 96, 96, canvasImage.data);
//Go do the encoding
return encoder.flushAsync();
//file saved successfully,
//but stream is still open and the stream variable is out of scope.
};
This simple imaging sample from Microsoft might help. Copied below.
It looks like, in your case, you need to declare the stream before the chain of then calls, make sure you don't name-collide with your parameter to your function accepting the stream (note the part where they do _stream = stream), and add a then call to close the stream.
function scenario2GetImageRotationAsync(file) {
var accessMode = Windows.Storage.FileAccessMode.read;
// Keep data in-scope across multiple asynchronous methods
var stream;
var exifRotation;
return file.openAsync(accessMode).then(function (_stream) {
stream = _stream;
return Imaging.BitmapDecoder.createAsync(stream);
}).then(function (decoder) {
// irrelevant stuff to this question
}).then(function () {
if (stream) {
stream.close();
}
return exifRotation;
});
}