Why do I fail to send response on getJSON's success? [duplicate] - google-chrome-extension

This question already has answers here:
Chrome Extension Message passing: response not sent
(3 answers)
Closed 8 years ago.
I'm working on a simple Chrome extension. I have something like that
/* content script */
chrome.runtime.sendMessage({msg: "marco"}, function(response){
if (response.foo){
console.log(response.foo);
}
});
/* background script */
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
if (request.msg){
// sendResponse({foo: "polo"}); // works fine
// load a local JSON file
$.getJSON("path/to/file.js", function(data){
console.log("success"); // works fine
sendResponse({foo: "polo"}); // does not work
});
}
});
As you can probably see, the call to sendResponse from the body of getJSON's callback does not seem to be sending the response although the call to log right above it executes perfectly. If I call sendResponse from outside the body of getJSON's callback, it sends the response normally.
Any idea of what might be the problem?

In the end of the listener function you must return "true" so the connection to the content script will remain opened.
In async calls listener function will end and the port will be closed immediately so sendResponse function will do nothing.
From the documentation:
This function becomes invalid when the event listener returns, unless
you return true from the event listener to indicate you wish to send a
response asynchronously (this will keep the message channel open to
the other end until sendResponse is called).

Related

Node.JS event loop socket delayed or thread blocked

I have a problem with node.js when sending a lot of concurrent request. The problem is that sometimes it seems it puts some request at the end of the event pool and give me the response after some serious time (60 seconds+, normal is under 10 seconds).
The story goes like this, i have 3 scripts, a CONSOLE, a SERVER and 10 CLIENTS.
console.js
// sending message
client.connect(port, host, function(connect_socket)
{
client.sendMessage(code:301,... some json-socket message ...);
client.on('message', function(message)
{
if(message.code == 304)
{
console.log(... print data ...)
}
});
}
server.js
server = net.createServer(function(socket)
{
socket = new JsonSocket(socket);
socket.on('message', function(message)
{
if(message.code == 301)
{
var client_random = get_random_client();
client_random.sendMessage(code:302,... some json-socket message ...);
}
if(message.code == 303)
{
var client_return = get_client_by_id(message.return_client_id);
client_return.sendMessage(code:304,... some json-socket message ...);
}
});
});
});
client.js
client.connect(port, host, function(connect_socket)
{
client.on('message', function(message)
{
if(message.code == 302)
{
execute_command(message.data, function(result_command)
{
client.sendMessage(code:303,... some json-socket message (good or bad check) ...)
});
}
});
}
Arhitecture concept, console sends message to server, server to a random client, client executes an external program and sends output back to server, server sends response back to the console and console prints it.
console.js => server.js => client.js => server.js => console.js
I open the server, clients are connecting no problem. I open the console and type the command, i get every time the response under 10 seconds.
Now, i made another PHP script that would simulate 600 requests per second. I do the same thing, open console, send command, and once every 10 runs (1 of 10), the console waits, waits and waits, and after 60 seconds it gives me the result (10 was normal).
I made some debug and it seems that server.js do not trigger message event when reciving from client.js and somehow puts it at the very end of the event pool, but never forget it, runs eventually.
I have double check :
console.js every time sends message to server.js (always instant)
server.js every time sends message to client.js (always instant)
client.js every time sends message to server.js (always instant)
[server.js do not fire the event message event instant, and put it
on the very end of the event pool ]
server.js every time sends message to client.js (always instant)
Also i have checked for the possible I/O main thread block, everything is fine. All operations are async, no sync functions.
It is that kind of bug that sometime it is manifesting, sometimes not. Like after a console.js waiting, you can open another terminal and console.js and send messages and see how it responds right away. As i already told, it is like a probability of 1 from 10.
How can i solve this? I had made a lot of debugging.

Meteor methods, trying to call child_process.spawn, getting TypeError: child_process.spawn is not a function

I am trying to call Meteor.method from inside the client component:
Meteor.call('execute', this.parameter);
Meteor.methods have a function which spawns the process as follows:
cp.spawn(pathtoscript, ['-t', parameter.myid], options);
This is a valid process spawn which is executed successfully (it takes up to 30 seconds to complete), however browser console spits out an error immediately after call is made:
Exception while simulating the effect of invoking 'execute' TypeError:
cp.spawn is not a function(…) TypeError: cp.spawn is not a function
I have tried just spawning the process and exiting the function and I have also tried to wait for 'close' event. Both times execution on the backend is successful, but browser console throws exception.
I have also tried to call Meteor.methods asynchronously
Meteor.call('execute', this.parameter, function(error, result) {
if (error) {
alert(error, error.reason);
}
console.log(result);
});*/
While adding return values in Meteor.methods. And it always ends in the same way.
Can you please advise the proper way for spawning processes in such cases?
This is because your method code is in both client and server. It can not run on client because there is no spawn in browser.
To fix this you could simply move your method to server code only or just wrap it inside an if statement with condition Meteor.isServer:
if (Meteor.isServer) {
Meteor.methods({
execute(params) {
//...
}
});
}

Performing Operations while Closing NodeJS

I have a Firebase Connection in nodejs that pushes data to a url while the connection is persistent, when it closes, I want to remove that data (think, I push "hey I'm here", and when I leave, the text disappears)
I made a "runnable" that shows an example of it:
http://web-f6176e84-c073-416f-93af-62a9a9fbfabd.runnable.com
basically, hit "ctrl + c" and it prints out "trying to remove reference" but never actually deletes the data ( the documents say that remove() is equivalent to set(null) which it basically sets the data to null, and since it's null, the entire element should be gone.)
However it's not removing it, I don't see the data ever "disappear". (I'm using a temp Firebase URL, you should be able to duplicate with any URL you can access if this url stops existing).
this is the code I'm using.
var FB_URL = 'https://cuhiqgro1t3.firebaseio-demo.com/test_code';
var Firebase = require('firebase');
var myRootRef = new Firebase(FB_URL);
console.log("created Firebase URL");
process.stdin.resume(); //so the program will not close instantly
function delete_fb_entries() {
return function() {
console.log("Trying to remove reference");
myRootRef.remove();
process.exit();
}
}
//do something when app is closing
process.on('exit', delete_fb_entries());
//catches ctrl+c event
process.on('SIGINT', delete_fb_entries());
//catches uncaught exceptions
process.on('uncaughtException', delete_fb_entries());
EDIT: Additional Information as to the "why", I push my local IP address out to my Firebase URL cause I'm lazy and it's easier to just have a webpage setup I can always access that will show the url of particular devices (and I know using the routers tables would be easier), I actually also have other purposes for this usage as well (if I happen to be inside my network, I can just select a particular device from my webpage and access the data I need, either way, it works, but I just can't get it to remove itself correctly, this used to work at one point in time I believe, so I can only assume the API has changed or something).
EDIT 2: OK removed process.exit() as suggested, and the runnable seemed to delete the data in question, I tried it on my local data (and after some cleaning up and commenting out), it removed the data, however when I hit Ctrl + C it no longer exits the program.....so yay.
I need to figure out if "process.exit()" is necessary or unnecessary at this point.
Edit 3: Ok so I need to use process.exit (as far as I can tell, Ctrl + C no longer exits the program, I have to ctrl + Z, and reboot). I tried adding it right after, but I realized that removing a firebase element is not a synchronus operation, so when I close it I tried (the next attempt) was to use the on complete handler for the remove function (so remove(onComplete), and then adding the process.exit() to the onComplete function).
So finally it looks like this and it seems to be working with my application
var FB_URL = 'https://cuhiqgro1t3.firebaseio-demo.com/test_code';
var Firebase = require('firebase');
var myRootRef = new Firebase(FB_URL);
console.log("created Firebase URL");
function onComplete() {
process.exit();
]
process.stdin.resume(); //so the program will not close instantly
function delete_fb_entries() {
return function() {
console.log("Trying to remove reference");
myRootRef.remove(onComplete);
}
}
//do something when app is closing
process.on('exit', delete_fb_entries());
//catches ctrl+c event
process.on('SIGINT', delete_fb_entries());
//catches uncaught exceptions
process.on('uncaughtException', delete_fb_entries());
EDIT 4: In response to comments below, So I tried modifying a simple program to be the following:
function delete_fb_entries (){
return function () {
console.log("I should quit soon");
}
}
process.stdin.resume(); //so the program will not close instantly
//catches ctrl+c event
process.on('SIGINT', delete_fb_entries());
My program never exited. I don't understand why node would not close in this case, changing to add a process.exit() after the console.log causes nodejs to quit. This is not an async function, so why is it not exiting in this case? (Is this a bug, or a misunderstanding of how this works by me?)
You cannot perform asynchronous operations in a process's exit event handler, only synchronous operations, since the process is exited once all exit event handlers have been executed.

How does the event: 'close' work in Node.js?

I'm experimenting with the close event in Node.js. I'm very new to Node.js so I'm not sure if this is a decent question or a sad one.
Documentation for close event:
http://nodejs.org/api/http.html#http_event_close_2
I want to output to the console a message if the browser is closed before the end event is reached.
While the server ran and before it got to 15 seconds, I tried closing the browser and killing the process through Chrome Tools. No message is output to the console and if I open up other connections by visiting localhost:8080 with other windows, I quickly get a 'hello' indicating my node server thinks there are at least two connections.
I'm either not understanding how to kill processes in Chrome or how the event close works.
Or if End and Close are the same - node.js https no response 'end' event, 'close' instead? - why isn't my "They got impatient!" message still ouput in the console?
How can you output to a console if the process was ended before the event end was reached?
var http = require('http'),
userRequests = 0;
http.createServer(function(request,response){
userRequests++;
response.writeHead(200, {'Content-Type' : 'text/plain'});
if ( userRequests == 1 ){
response.write('1st \n');
setTimeout ( function() {
response.write('2nd Thanks for waiting. \n');
response.on('close', function() {
console.log("They got impatient!");
});
response.end();
}, 15000);
response.write('3rd \n');
}
else {
// Quick response for all connections after first user
response.write('Hello');
response.end();
}
}).listen(8080, function() {
console.log('Server start');
});
Thank you.
First - move the event handler for the close message outside the timeout function - you're not hooking up the close handler until after your timeout expires, and probably missing the event.
Second, you never decrement userRequests anywhere; shouldn't there be a userRequests--; line somewhere? This would be throwing off your logic, since it'll always look like there's more than one request.

Chrome Extension Messaging Timeout

I have a tab with, among other stuff, following content:
<meta http-equiv="refresh" content="0; URL='whatsoever'" />
I also have a plugin running that registers every tab using this technique:
chrome.tabs.onUpdated.addListener(doStuff);
The doStuff-function sends a message to the tab:
function doStuff(tabId, changeInfo, tab){
chrome.tabs.sendMessage(tabId, {'message': 'content'}, function(response){
doOtherStuff(response);
});
}
I have a script registered (not seen here), and in that script, this happens:
function receiveMessage(request, sender, sendResponse){
sendResponse({'content': 'responseData'});
}
chrome.extension.onMessage.addListener(receiveMessage);
My problem is that due to the instantaneous refresh, the response times out, and following error appears in the console:
Could not send response: The chrome.extension.onMessage listener must
return true if you want to send a response after the listener returns
(message was sent by extension XYZ).
Why is that, and how can I circumvent this issue? Thanks in advance.
It says, the function receiveMessage should exit with return true;. Only then the message will continue to be send. On false, it is aborted the moment the function returns. So add return true
see:
This function becomes invalid when the event listener returns, unless
you return true from the event listener to indicate you wish to send a
response asynchronously (this will keep the message channel open to
the other end until sendResponse is called).
from the doc:
https://developer.chrome.com/extensions/runtime#event-onMessage
function receiveMessage(request, sender, sendResponse){
sendResponse({'content': 'responseData'});
return true;
}
chrome.extension.onMessage.addListener(receiveMessage);

Resources