Fetching a POST request in Meteor via a notification url - javascript

This is something I have no experience with.
On the admin page I'm building it's possible to upload a picture to a service called Cloudinary to have its background removed, a process that takes up to 24 hours, upon which they send a POST request to some url that I send along with the request.
This format doesn't lend itself very well to experimenting, so I need some help.
This is how the picture is uploaded and the request sent:
Cloudinary.upload(image, {
folder: "cutouts",
type: "upload",
notification_url: "someurl.com"
background_removal: "remove_the_background"
}, function(error, result) {
if (!error)
console.dir(result)
}
})
Question: what do I set as the notification_url? Even if it's somewhere on my site, do I need to deploy it before I can check that the code works?
Here's an example of what they will send back, according to their docs:
{
"notification_type": "info",
"info_kind": "remove_the_background",
"info_status": "complete",
"public_id": "wood_chair",
"uploaded_at": "2014-10-26T11:35:22Z",
"version": 1414316122,
"url":
"http://res.cloudinary.com/demo/image/upload/v1393688588/wood_chair.jpg",
"secure_url":
"https://res.cloudinary.com/demo/image/upload/v1393688588/wood_chair.jpg",
"etag": "a56e9e88c2add15cac1775c1f687bf73"
}
So, specifically I need access to the info_status and the url.
Problem is, I can't experiment and I have no idea how to approach this problem since I have no experience with this stuff at all.
Here are their docs if it's any help: http://cloudinary.com/documentation/remove_the_background_image_editing_addon
How do I do this?

On your server side, set up a route (assuming you are using iron-router) to handle the post from cloudinary:
Router.route('/api/cloudinary', { where: 'server' })
.post(function() {
var body = this.request.body; // get the body out of the response
var url = body.url; // based on the JSON you showed
this.response.statusCode = 200; // set the status code to be returned to cloudinary
this.response.end(); // send response
}
);
You can change /api/cloudinary/ to whatever you want. If your site was http://www.example.com, then the cloudinary notification url would be:
http://www.example.com/api/cloudinary

Related

Process multiple unique Express JS requests

I've got a small Express JS api that I'm building to handle and process multiple incoming requests from the browser and am having some trouble figuring out the best approach to handle them.
The use case is that there's a form, with potentially up-to 30 or so people submitting form data to the Express JS api at any given time, the API then POSTS this data of to some place using axios, and each one needs to return a response back to the browser of the person that submitted the data, my endpoint so far is:
app.post('/api/process', (req, res) => {
if (!req.body) {
res.status(400).send({ code: 400, success: false, message: "No data was submitted" })
return
}
const application = req.body.Application
axios.post('https://example.com/api/endpoint', application)
.then(response => {
res.status(200).send({ code: 200, success: true, message: response })
})
.catch(error => {
res.status(200).send({ code: 200, success: false, message: error })
});
})
If John and James submit form data from different browsers to my Express JS api, which is forwarded to another api, I need the respective responses to go back to the respective browsers...
Let's make clear for you, A response of a request will only send to the requester, But if you need to send a process request and send a response like, hey i received your request and you can use another get route to get the result sometimes later, then you need to determine which job you mean. So You can generate a UUID when server receives a process request and send it back to the sender as response, Hey i received your process request, you can check the result of process sometimes later and this UUID is your reference code. Then you need to pass the UUID code as GETparam or query param and server send you the correct result.
This is the usual way when you are usinf WebSockettoo. send a process req to server and server sends back a reference UUID code, sometime later server sends the process result to websocket of requester and says Hey this is the result of that process with that UUID reference code.
I hope i said clear enough.

How to read parameters of Azure function HTTP request and respond with a file from blob storage?

I'm building an Azure Function app and have had some issues trying to proxy requests (for data capture purposes) and still respond with the requested files. Essentially what I'm trying to accomplish is:
Client requests file via GET parameter on an Azure Function endpoint (not its blob storage location)
Function logs some metadata to table storage (e.g. IP address, timestamp, file name, etc.)
Function locates the desired file in blob storage and forwards it to the client as if Step 2 didn't occur
I've tried an approach using Q (outlined here) with no luck, and I haven't been able to narrow the issue down (beyond standard 500 errors).
The tutorial above basically goes as follows:
const rawFile = await q.nfcall(fs.readFile, blobUrl);
const fileBuffer = Buffer.from(rawFile, ‘base64’);
context.res = {
status: 202,
body: fileBuffer,
headers: {
"Content-Disposition": "attachment; examplefile.mp3;"
}
};
context.done();
I've hit a bit of a wall and I'm struggling to find a solution to what I thought would be a common problem (i.e. simply logging download metadata to a table). I'm new to Azure and so far I'm finding things a bit tedious... Is there a simple way of doing this?
Edit: Based on the response I get from context.bindings.myFile.length I think I've been able to retrieve a file from blob storage, but I haven't yet been able to send it back in the response. I've tried the following:
context.res = {
status: 202,
body: context.bindings.myFile,
headers: {
'Content-Type': 'audio/mpeg',
'Content-Disposition': 'attachment;filename=' + fileName,
'Content-Length': context.bindings.myFile.length
}
};
Edit 2: I think this is pretty much solved - I overlooked the methods and route in the HTTP input part of the answer below. Looks like I'm able to dynamically retrieve blobs based on the GET request and use them as inputs, and I've been able to get them sent back to the client as well. My HTTP response now looks like this:
context.res = {
status: 200,
headers: {
'Content-Length': context.bindings.myFile.length,
'Content-Type': 'audio/mpeg'
},
body: context.bindings.myFile,
isRaw: true
};
Let me paraphrase what you asked:
You want just to retrieve blob storage object upon http request.
I think it is worth looking into bindings. They simplify the integration with other Azure services - Storage Accounts, Service Bus, Twilio - and Function Apps.
In your case it should be an input binding for blob storage. As one way to achieve it you need to customize your route in the http trigger part of function.json as follows: file/{fileName}. Then you use fileName in input binding definition in the same function.json.
I think function.json should like this:
{
"bindings": [
{
"type": "httpTrigger",
"name": "req",
"direction": "in",
"methods": [ "get" ],
"route": "file/{fileName}"
},
{
"name": "myFile",
"type": "blob",
"path": "your-container-name/{fileName}",
"connection": "MyStorageConnectionAppSetting",
"direction": "in"
},
{
"type": "http",
"name": "res",
"direction": "out"
}
]
}
With your index.js as follows:
module.exports = function(context, req) {
context.log('Node.js Queue trigger function processed', context.bindings.myFile);
const fileToReturn = context.bindings.myFile;
// you return it here with context.res = ...
context.done();
};
You also superficially mentioned the logging that is not part of your question but is mentioned. I recommend looking into Azure Application Insights. It might serve the purpose.

How can you make an HTTP request to fetch the status.cgi json data from a Ubiquity AirMax or AirFibre radio with javascript?

My goal is to fetch the status data from a UBNT radio (https://www.ubnt.com/) using an HTTP request. The web interface url is formatted as http://192.168.0.120/status.cgi. Making the request requires a authentication cookie. Using the cookie copied from the existing web interface I am able to successfully retrieve the data.
This is my current code using the Meteor framework.
radioHost = "http://192.168.0.120";
HTTP.call("POST", radioHost + "/login.cgi",
{
headers: {
"Content-Type": "multipart/form-data"
},
data: {
username: "ubnt",
password: "ubnt"
}
}, (err, res) = > {
if(err) return console.log(err);
var cookie = res.headers["set-cookie"][0];
HTTP.call("GET", radioHost + "/status.cgi", {
headers: {
cookie
}
}, (err, res) = > {
if(err) return console.log("Error");
console.log(res);
})
})
The above code achieves both request successfully. However the server is responding to the first with a faulty token ("set-cookie" string). Using the cookie from the existing web framework the response is correct.
Here is a library written in Python that I believe does a similar thing. https://github.com/zmousm/ubnt-nagios-plugins
I believe my problem lies within the HTTP request and the web api not cooperating with the username and password.
Thanks in advance for any help.
A direct POST request to a url is not a recommended way. When you open a browser you just don't directly login. You fetch the page and then submit/login
Not simulating this behavior may impact certain sites depending on how the server works.
So if always want to look at the simulating like a real user/browser would do, make a GET request first and then the POST.
Also capture any cookies from the first GET request and then pass the same on to the next one

How to request url with authorized token through API

I am trying to develop a web-app based on girder platform (a data management platform). During development, I get some problem confused me for a long time. Let me briefly explain my work and if anything I understand worry, please point it out coz I just start.
The thing is that,
In the font end I am using AMI(a javascript library) to deal with image virtualization, and the way is to tell (make a request to girder server) AMI the URL address which contains image to display as attachment. (e.g.http://girderDomain:port/api/v1/file/imageID/download?contentDisposition=attachment API of girder)
When this URL does not have any permission, everything works fine. When it needs permission (which is a token generated when authorized user login), purely URL does not work, so I was trying to use ajax to make a request with requestHeader(token) something like below:
$.ajax({
type:'GET',
url:'http://girderDomain:port/api/v1/file/imageWithPermissionID/download?contentDisposition=attachment',
crossDomain:true,
processData: false,
beforeSend:function(xhr){
// xhr.setRequestHeader("Access-Control-Allow-Origin:", "*");
// xhr.setRequestHeader("girderToken", token);
},
success:function (d,s,xhr) {}
});
Although I still get some error not solving yet, but ajax is the only way that in my mind.
and the whole process is like pseudocode below:
//***AMI***//
var t2 = ["imageID",....]; //////No permission need image
files = t2.map(function(v) {
return 'http://girderDomain:port/api/v1/file/' + v+'/download?contentDisposition=attachment';
});
AMI.display(files)
As you can see no permission image display is simple and easy to do, and with permission image through ajax request would be something like:
//***ajax to download permission file first***//
$.ajax({
//url:'http://girderDomain:port/api/v1/file/imageWithPermissionID/download?contentDisposition=attachment'
//set requestHeader("girderToken",token);
//success:function(){
//download this permission file to request domain tempFolder as A
}
});
/***AMI***/
var t2 = ["A"];
files = t2.map(function(v) {
return 'http://requestDomain/tempFolder/A';
});
AMI.display(files);
and that looks stupid, so I am wondering does anyone have any idea to request a file with permission, like maybe save token in cookie or session and using some way to make request with cookie or session, or any other new methods, frameworks.
Since I just start that kind of client-server development, any help truly appreciated.

Node.js progress indicator feedback

I have a question about the progress of sending with Node.js 'request'. I have a Node.js application that acts as a proxy, actually forwarding a body to another server. I want to see the progress of this upload action. Now I am doing this:
BROWSER
-> UPLOAD TO NODE
-> UPLOAD TO 3rd PARTY SERVICE
-> RETURN 3rd PARTY RESPONSE TO BROWSER
If this is possible, I would log it to check in the console.log how much progress is done. But, would it also be possible to return a
res.send(progress)
in the mean time, while waiting for the upload to finish and send the client back the upload has succeeded?
BROWSER
-> UPLOAD TO NODE
-> UPLOAD TO 3rd PARTY SERVICE
-> RETURN progress <-
-> RETURN progress <-
...etc.
-> RETURN 3rd PARTY RESPONSE TO BROWSER
This is the upload code (pretty much straightforward).
var requestOptions = {
timeout: 120000,
url: url, //URL to hit
method: 'post',
headers: headers,
body: payload //Set the body as a string
};
request(requestOptions, function (error, response, body) {
if (error) {
res.send(error);
}
else {
//res.sendStatus(response.statusCode);
console.log("[RETURNING RESPONSE BODY]");
res.send(body);
}
});
Your question contains two parts. One is for getting the progress from request, which can be found here: Upload Progress — Request
The other part would be notifying the browser of the progress. The HTTP protocol does not let you send multiple responses, so using res.send(progress) is not possible.
However, you can keep sending partial responses until it finishes. Writing something to res without closing it is as simple as res.write("string"), but accessing the response can be harder: Accessing partial response using AJAX or WebSockets?
You also need a way to wrap the body (and also errors) from the backing server so that it can fit as the final partial response.
Another solution would be opening another WebSocket request to track the uploading/downloading process. socket.io is a good library for node for this purpose.
Solution for first part was in r.req.connectin.bytesWritten
var r = request(requestOptions, function (error, response, body) {
clearInterval(q);
...
});
var q = setInterval(function () {
console.log("Uploaded: " + r.req.connection.bytesWritten);
}, 250);

Categories