How to implement progress bar during HTTP Client request call - javascript

Just a question I'm confused about how I could achieve this. I just want to implement progress bar on how long the response from HTTP client request call. I saw a lot of tutorials on how to implement this progress bar but it all centered to a file being downloaded from the server. I want to ask what would be the best approach to do this.
This is my situation. I have a web API that generates a zip file that contains multiple word file that was generated base on the parameters from the calling site. Basically, a lot of things happening from pulling the records from the database and generating these files that's why it took time for the response to be sent and I want to at least show progress bar out of this so that when our user click the button to generate this file they can see the progress of the report to be generated.
This is how i consume the API:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri ("MYBASEURI");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/zip"));
var content = new StringContent(strModel, Encoding.UTF8, "application/json");
var response = await client.PostAsync("API_URI", content);
if (!response.IsSuccessStatusCode)
{
ExceptionResponse ex = await response.ExceptionResponse();
return null;
}
var data = await response.Content.ReadAsStreamAsync();
return File(data, "application/zip", "File.zip");
}
I'm calling this method on form submit since it has parameters needed for the report to generate.

Related

Synchronize critical section in API for each user in JavaScript

I wanted to swap a profile picture of a user. For this, I have to check the database to see if a picture has already been saved, if so, it should be deleted. Then the new one should be saved and entered into the database.
Here is a simplified (pseudo) code of that:
async function changePic(user, file) {
// remove old pic
if (await database.hasPic(user)) {
let oldPath = await database.getPicOfUser(user);
filesystem.remove(oldPath);
}
// save new pic
let path = "some/new/generated/path.png";
file = await Image.modify(file);
await Promise.all([
filesystem.save(path, file),
database.saveThatUserHasNewPic(user, path)
]);
return "I'm done!";
}
I ran into the following problem with it:
If the user calls the API twice in a short time, serious errors occur. The database queries and the functions in between are asynchronous, causing that the changes of the first API call weren't applied when the second API checks for a profile pic to delete. So I'm left with a filesystem.remove request for an already unexisting file and an unremoved image in the filesystem.
I would like to safely handle that situation by synchronizing this critical section of code. I don't want to reject requests only because the server hasn't finished the previous one and I also want to synchronize it for each user, so users aren't bothered by the actions of other users.
Is there a clean way to achieve this in JavaScript? Some sort of monitor like you know it from Java would be nice.
You could use a library like p-limit to control your concurrency. Use a map to track the active/pending requests for each user. Use their ID (which I assume exists) as the key and the limit instance as the value:
const pLimit = require('p-limit');
const limits = new Map();
function changePic(user, file) {
async function impl(user, file) {
// your implementation from above
}
const { id } = user // or similar to distinguish them
if (!limits.has(id)) {
limits.set(id, pLimit(1)); // only one active request per user
}
const limit = limits.get(id);
return limit(impl, user, file); // schedule impl for execution
}
// TODO clean up limits to prevent memory leak?

API Request Loop Node.js and LiveChat API

As a side project at work, I am currently working on implementing a LiveChat Report web app. Basically, it will download all of our LiveChat data to .csv files for analysis, etc.
I have the entire thing working quite well; however, I am having a hard time wrapping my head around how to loop though requests based on pages of results returned. For example, I want certain information from each chat. LiveChat API only returns 25 chats on each page. Unfortunately, I cannot call each page at a time and depending on the date range parameters, the number of pages varies each time. I want to get all of these pages on 1 csv, if possible.
My request looks like:
function chatListReport() {
document.getElementById('chat_list_submit').addEventListener('click', function(event) {
var req = new XMLHttpRequest();
var params = {date_from:null,date_to:null, page:null};
params.date_from = document.getElementById('date_from').value;
params.date_to = document.getElementById('date_to').value;
params.page = document.getElementById('page').value;
req.onreadystatechange = function() { //when response received
if (req.readyState == 4 && req.status == 200) {
var response = (req.responseText);
var final = "data:text/csv;charset=utf-8," + encodeURI(response);
var link = document.createElement('a');
link.setAttribute('href', final);
link.setAttribute('download', 'ChatListSurveyReport.csv');
link.click();
}}
req.open('POST', '/chat_list_report', true); //submit update via POST to server
req.setRequestHeader('Content-Type', 'application/json'); //set request header
req.send(JSON.stringify(params));
event.preventDefault();
});
My server side looks like this (using NPM liveChatAPI):
app.post('/chat_list_report', function(req, res){
var params = req.body;
api.chats.list(params, function(data){
var headers = 'Chat Date,Agent,PostChat Survey Rating,Comments';
var result = (data.chats || [])
.filter(function(chat) {return chat.type === "chat"})
.map(function(chat) {
var postSurvey = chat.postchat_survey || [];
return [
chat.ended.replace(",", ""),
chat.agents[0].display_name,
(postSurvey[0] || {}).value || "",
(postSurvey[1] || {}).value || "",
].join(',');
});
result.unshift(headers);
res.send(result.join('\n'));
});
});
I am able to return the number of pages. That is included in the returned JSON. So in short, is there a way to return that page number response back to the request and loop through the request X amount of times and then create 1 csv with all of the information? Right now I am limited to only 25 chats per single request.
Thanks! Any help is greatly appreciated.
We see two possible solutions:
1:
A. Front-end sends a request to the backend, and then the backend returns ID of a job, which the front-end must store on it’s side, for example in the localStorage.
B. At this time, back-end works on the jobs on its own, and tries to finish it, as a complete task.
C. Front-end sends a request to the back-end every few seconds about the task, giving it’s ID. While the task is not complete, back-end replies with 'in-progress',
and front-end continues to enquire about the task until its finished.
D. If the front-end enquires about the task, and on this time receive notification
that the task is completed, then back-end returns a message like finished' with
further completed information.
E.
GUI should notify:
o Waiting for response
o Response successful, link to download a file.
---------OR----------
2:
A. Front-end sends request to back-end, back-end registers the task and after
completing the task sends an e-mail with the completed data.
B. Front-end informs that the task has been added to the ‘queue’ and only when it is
completed will an email be sent with the results of the task.
C. Requires adding additional input on the front end side : e-mail and handling some sort of API for e-mails e.g e,g,:https://postmarkapp.com/
Let me know how it works,
Cheers,
Adam

Cache HTML using request-promise and Node.js

I'm looking for a simple way to cache HTML that I pull using the request-promise library.
The way I've done this in the past is specify a time-to-live say one day. Then I take the parameters passed into request and I hash them. Then whenever a request is made I save the HTML contents on the file-system in a specific folder and name the file the name of the hash and the unix timestamp. Then when a request is made for the using the same parameters I check if the cache is still relevant via timestamp and pull it or make a new request.
Is there any library that can help with this that can wrap around request? Does request have a method of doing this natively?
I went with the recco in the comments and used Redis. Note this only works for get requests.
/* cached requests */
async function cacheRequest(options){
let stringOptions = JSON.stringify(options)
let optionsHashed = crypto.createHash('md5').update(stringOptions).digest('hex')
let get = await client.getAsync(optionsHashed)
if (get) return get
let HTML = await request.get(options)
await client.setAsync(optionsHashed, HTML)
return HTML
}

How do I publish FB posts on my website with the same display of the facebook page?

I know how to retrieve the posts data from FB.api, and already menage to parse the data and display the inner data of each posts. but i want each feed to look the same as the facebook home page feeds look like.
thanks :)
https://developers.facebook.com/docs/reference/plugins/like-box/ takes the feed from a Page and displays it in the same format as on Facebook.
Otherwise you'll need to style it yourself manually, making sure it doesn't look confusingly similar to Facebook's own interface.
You can do it using Open Graph. The result is a JSON data feed, which you can stream to your site as html or load is up into a webpage. I would recommend using ajax or loading it as RAW JSON using JavaScript to render it...
var Appid = 12341234; // User the one FB gave you
var AppSecret = "YOUR_APP_SECRET"; // Use the one FB gave You
var PageIdOrName = "matt.j.crawford"; // This could be a number or an offical name
var tokenRequest = String.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=client_credentials", Appid, AppSecret);
var token = new System.Net.WebClient().DownloadString(tokenRequest).Split(new char[] { '=' })[1];
var feedRequest = String.Format("https://graph.facebook.com/{0}/feed?access_token={1}", PageIdOrName, token);
var feed = new System.Net.WebClient().DownloadString(feedRequest).Replace("\\/", "/");
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
var finalObject = jss.Deserialize<dynamic>(feed);
These wasn't any real documentation on this so... I just figured it out.
Don't load this before rendering the page as it takes a few seconds to complete the loading, one option is to use an IHttpHandler and load it as a JavaScript file and render it server side....
Another option is use ajax to load rendered html after page load.

Using Google Cloud Datastore and AJAX(blobs)-python

Hi I have some images stored as BlobProperty in Google Cloud Datastore. I am trying to load these images via ajax into my template. For eg:- a user has an image and a name. Now the image and name area gets populated via an AJAX get call to the server. I am not understanding how to I send these images to the client , JSON wont support binary data. However googling around tells me of something called base 64.(I am quite new to all this, so let me admit , I am a noob).
Is this the only way to handle this or is there some other better way.
This thread suggests that if you just create an image element, set its src, and add it to your page using Javascript, the browser will take care of making an HTTP request for the image:
http://bytes.com/topic/javascript/answers/472046-using-ajax-xmlhttprequest-load-images
If you do want to do it with 'pure' AJAX, then base64 is probably the best thing: it's a way of encoding binary data (like images) as text, so you can send it as a long string in json.
This is how I do it, it's in flask but nonetheless it's python
this way, you create a request handler to display the images.
So all you need to do to get the image via ajax is getting the image id to be served. It's simpler and you can manipulate the size as well on the fly
from flask import request
from google.appengine.api import taskqueue, images, mail
from google.appengine.ext import db
#app.route('/image/<img_id>')
def imgshow(img_id):
imageuse = Image.all().filter("image_id =", img_id).get()
if imageuse:
response = Response(response=imageuse.content)
#you can use any type over here
response.headers['Content-Type']='image/png'
return response
else:
return
this is what I do to manipulate the size
#app.route('/thumb/<img_id>')
def thumbshow(img_id):
imageuse = Image.all().filter("image_id =", img_id).get()
if imageuse:
thbimg = images.resize(imageuse.content, 80)
response = Response(thbimg)
response.headers['Content-Type']='image/png'
return response
else:
return
hope that helps

Categories

Resources