I have been building a youtube video conversion app which streams youtube videos using youtube-dl and saves them, everything was working fine until I attempted to stream a video that was over an hour long. When the task was anywhere between 50% - 100% complete or 40-80seconds in, would be when the entire block of code would get re-run resulting in multiple simultaneous streams occurring. The response can therefor never get sent as it waits for the pipe to finish. Adding next(); outside the stream function allowed the conversion to complete with out any interruption or reruns of the code block, however it resulted in the following error when attempting to send the response:
throw new Error('Can\'t set headers after they are sent.');
This is the Node.js code block in question:
app.post('/convert/', function (req, res, next){
var url = 'http://www.youtube.com/'+req.body.url;
var quality = req.body.quality;
var socketId = req.body.socketId;
stream = youtubedl(url,
['-f ' + quality],
// // Additional options can be given for calling `child_process.execFile()`.
{ cwd: __dirname });
stream.on('info', function(info) {
console.log('Download started');
console.log('filename: ' + info._filename);
console.log('size: ' + info.size);
console.log('format: ' + info.format);
var fileName = info._filename;
var videoId = info.id;
var videoTitle = info.title;
videoTitle = videoTitle.replace(/[^a-zA-Z0-9\s]/g, '');
console.log(videoTitle);
var mp4 = 'downloads/'+videoTitle+'-'+info.format_id+'.mp4';
fs.writeFile(mp4, "file", function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
var stat = fs.statSync(mp4);
var str = progress({
length: info.size,
time: 100
});
str.on('progress', function(progress) {
io.to(global.socketid).emit('progressVideo',{progress: progress.percentage});
console.log(info.size);
console.log(progress.transferred);
console.log(progress.percentage);
console.log(progress.remaining);
});
var pipe = stream.pipe(str).pipe(fs.createWriteStream(mp4));
pipe.on('finish', function () {
console.log("stream finished.");
res.json(videoTitle+'-'+info.format_id+'.mp4');
});
});
});
// next();
});
Called by some Angular code.
// Sends youtube link to backend
$scope.getVideo = function(youtubeLink, resolution){
var cleanedLink = youtubeLink.substring(24);
var url = {url: cleanedLink, quality: resolution};
$http.post('/convert/', url).success(function (response){
// Do some stuff
});
}
Confused as to why it was getting run more then once, I slowly removed more and more code until I was left with this simple test.
app.post('/convert/', function (req, res, next){
console.log('hello!');
});
Which was called by an ng-click event and after waiting a minute or so the console also printed out two and then three hello! statements. I am completely lost as to why this happens. If anyone could shed some light on this for me it would be greatly appreciated.
So after just getting down to a very basic post route and logging out some text but not returning a response, I came to the conclusion the issue resides with node. I decided to record the length of time between the console.log statements which turned out to be every 2 minutes. With this I was able to find out that node has a default timeout of 2 minutes if a response is not sent back to the client.
I was able to set the response to never timeout with the following code:
res.connection.setTimeout(0);
I hope this helps anyone else that needs to hold connections for large periods of times for file conversions/transfers etc...
Related
To provide context, here's the problem I'm attempting to solve:
I've made a giphy bot for a casual groupchat with friends of mine. By typing /giphy [terms] in a message, it will automatically post the top result for [terms]. My friends, being the rambunctious assholes that they are, quickly started abusing it to spam the groupchat. What I would like to do to prevent this is only allow my postMessage function to be called once per minute.
What I've tried:
Using setTimeout(), which doesn't do exactly what I'd like, since it will only call the function after the amount of time specified in the argument has passed. As far as I can tell, this will cause a delay in messages from the time the bot is called, but it won't actually prevent the bot from accepting new postMessage() calls in that time.
Using setInterval(), which just causes the function to be called forever at a certain interval.
What I think might work:
Right now, I'm working with two .js files.
Index.js
var http, director, cool, bot, router, server, port;
http = require('http');
director = require('director');
bot = require('./bot.js');
router = new director.http.Router({
'/' : {
post: bot.respond,
get: ping
}
});
server = http.createServer(function (req, res) {
req.chunks = [];
req.on('data', function (chunk) {
req.chunks.push(chunk.toString());
});
router.dispatch(req, res, function(err) {
res.writeHead(err.status, {"Content-Type": "text/plain"});
res.end(err.message);
});
});
port = Number(process.env.PORT || 5000);
server.listen(port);
function ping() {
this.res.writeHead(200);
this.res.end("This is my giphy side project!");
}
Bot.js
var HTTPS = require('https');
var botID = process.env.BOT_ID;
var giphy = require('giphy-api')();
function respond() {
var request = JSON.parse(this.req.chunks[0]);
var giphyRegex = /^\/giphy (.*)$/;
var botMessage = giphyRegex.exec(request.text);
var offset = Math.floor(Math.random() * 10);
if(request.text && giphyRegex.test(request.text) && botMessage != null) {
this.res.writeHead(200);
giphy.search({
q: botMessage[1],
rating: 'pg-13'
}, function (err, res) {
try {
postMessage(res.data[offset].images.downsized.url);
} catch (err) {
postMessage("There is no gif of that.");
}
});
this.res.end();
} else {
this.res.writeHead(200);
this.res.end();
}
function postMessage(phrase) {
var botResponse, options, body, botReq;
botResponse = phrase;
options = {
hostname: 'api.groupme.com',
path: '/v3/bots/post',
method: 'POST'
};
body = {
"bot_id" : botID,
"text" : botResponse
};
botReq = HTTPS.request(options, function(res) {
if(res.statusCode == 202) {
} else {
console.log('Rejecting bad status code: ' + res.statusCode);
}
});
botReq.on('error', function(err) {
console.log('Error posting message: ' + JSON.stringify(err));
});
botReq.on('timeout', function(err) {
console.log('Timeout posting message: ' + JSON.stringify(err));
});
botReq.end(JSON.stringify(body));
}
exports.respond = respond;
Basically, I'm wondering where would be the ideal place to implement the timer that I'm envisioning. It seems like I would want to have it only listen for /giphy [terms] after one minute, rather than waiting one minute to post.
My Question(s):
Would the best way to go about this be to set a timer on the response() function, since then it will only actually parse the incoming information once per minute? Is there a more elegant place to put this?
How should the timer work on that function? I don't think I can just run response() once every minute, since that seems to mean it'll only parse incoming json from the GroupMe API once per minute, so it could potentially miss incoming messages that I would want it to capture.
Store the time when a request is made and then use that to see if subsequent requests should be ignored if these are executed to fast.
var waitTime = 10*1000; // 10 s in millis
var lastRequestTime = null;
function respond() {
if(lastRequestTime){
var now = new Date();
if(now.getTime() - lastRequestTime.getTime() <= waitTime){
this.res.writeHead(200);
this.res.end("You have to wait "+waitTime/1000+" seconds.");
return;
}
}
lastRequestTime = new Date();
postMessage();
}
currently trying to develop one of my first alexa skills. trying to build a skill that updates the user on who out of their Steam friends, are online.
Curerntly it's pretty messy and not in the format i hope it to be in the end, but for testing purposes, I'm not yet using intents, im just testing using the launchrequest.
So far I've managed to get a users (mine) friends list from steam and put all the friends ids in a url that should be able to grab the details for these
users.
The issue I'm having is performing the second API call to grab the players details using the steamIds. i keep getting an 'undefined' return and am stumped on what i'm doing wrong.
I'm very much new to JS so there's bound to be mistakes in here, but i can work on tidying up later once i've got it working.
This works fine
/**
* Called when the user invokes the skill without specifying what they want.
*/
function onLaunch(launchRequest, session, callback) {
console.log("onLaunch requestId=" + launchRequest.requestId
+ ", sessionId=" + session.sessionId);
var cardTitle = "Hello, World!"
testGet(function (response) {
var speechOutput = "Here is the result of your query: " + response;
var shouldEndSession = true;
callback(session.attributes,
buildSpeechletResponse(cardTitle, speechOutput, "", true));
});
//var speechOutput = "You can tell Hello, World! to say Hello, World!"
//callback(session.attributes,
// buildSpeechletResponse(cardTitle, speechOutput, "", true));
}
This is the function that is grabbing the details from my friendlist
function testGet(response) {
var http = require('http')
var url = " http://api.steampowered.com/ISteamUser/GetFriendList/v0001/?key=XXXXXXXXXX&steamid=76561198068311091&relationship=friend"
http.get(url, function (res) {
// data is streamed in chunks from the server
// so we have to handle the "data" event
var buffer = "",
data,
friendsList,
i,
address,
textResponse,
route;
res.on("data", function (chunk) {
buffer += chunk;
});
res.on("end", function (err) {
// finished transferring data
// dump the raw data
console.log(buffer);
console.log("\n");
data = JSON.parse(buffer);
friendsList = data.friendslist.friends;
textResponse = isOnline(friendsList);
response("Friends online: " + textResponse);
}).on('error', function (e) {
console.log("Error message: " + e.message);
});
})
}
and this is the final function which i'm having difficulties with.
function isOnline(friendsList){
var http = require('http'),
i,
comma,
friendsIDs = "";
// for loop to get all friends ids in string
for (i = 0; i < friendsList.length; i++) {
// if i equals 0 then it is the start of the loop so no
//comma needed, otherwise add a comma to seperate the ids.
if(i === 0) {comma = ""}
else{comma = ","}
//place the ids in a comma seperate string
friendsIDs += comma + friendsList[i].steamid;
}
var playerurl = "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=xxxxx&steamids=" + friendsIDs;
// works fine up to this point
// run the api call to get player details
http.get(playerurl, function (response) {
// data is streamed in chunks from the server
// so we have to handle the "data" event
var buffer = "",
playerdata,
returnText,
textResponse,
friendsInformation,
route;
response.on("playerdata", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
// finished transferring data
// dump the raw data
console.log(buffer);
console.log("\n");
playerdata = JSON.parse(buffer);
friendsInformation = playerdata.response.players;
for (i = 0; i < friendsInformation.length; i++) {
if(friendsInformation[i].personastate == 1) {
returnText += friendsInformation[i].personaname + " chicken";
}
}
return returnText;
}).on('error', function (e) {
console.log("Error message: " + e.message);
});
});
}
Been going round in circles for hours and feel so close to doing this but have no idea where I'm going wrong?!
thanks
I have managed to solve my problem by using javascript promises. I'm completely new to promises so took some trial and error but have managed to get it to work. here is the simplest video i could find to explain the concept, it definately helped me understand how to rearrange my code.
If you wish to do two API calls in an Alexa skill, using the data from the first api call to construct and inform the second call, you will need to use promises to do them sequentially.
it took the code from the isOnline() and testGet() functions and moved them into a promise, which allowed me to complete 1 api call (the original call to get friends list info) before executing the second call (the second api to get player details based on the results of the friendslist api call)
I can now check with alexa to see which of my steam friends are online! Hopefully i'll be able to build in some more functionality (eg what they are playing, if they are offline or just away/busy/snoozing)
thanks for contributing
So I'm working on a text based game where users send post requests to the server written in node.js. However, I need to match 2 players together by letting the first player to wait for the 2nd player before submitting a response. The problem right now is that after I call the post request once, I cannot send another post request for any response. It seems like the first thread is blocking any more future requests. What should in terms of using callbacks and async. I do not want to use sockets if possible as that will limit the languages that players can code in.
var newGame=0;
//joins new game (username,password)
app.post('/game/join', function(req, res) {
var username = req.body.username;
var password = req.body.password;
if(newGame==1){
res.send('Game Started');
newGame=0;
}
else{
newGame=1;
wait(username, function(){
res.send('Game Started'+username);
});
}
});
function wait(username){
while(newGame==1){
console.log(username + newGame);
}
}
So you may have found that once your wait functions starts, nothing else happens. This is because an infinite while loop with a blocking call (console.log) prevents the event loop from doing anything else until it is 'done'. You can include waiting with setTimeout, setInterval, and clearInterval to run a function at some point in the future, run a function on an interval, and stop running a function on an interval, respectively.
var newGame = 0;
app.post('/game/join', function(req, res) {
var username = req.body.username;
var password = req.body.password;
if (newGame === 1) {
res.send('Game started' + username);
} else {
var wait = setInterval(function() {
if (newGame === 1){
clearInterval(wait);
res.send('Game Started');
newGame = 0;
}
}, 5000); // retry every 5 seconds
}
}
});
Node.js is single threaded so your code is preventing your server from processing additional requests. Blocking the event loop is def something you don't want to be doing.
I was going to request using something like Socket.IO or WebRTC but I saw your constraint. I'm not really sure what you meant by "limit the language players can code in"
For me, its not clear that how you pick 2 users to start a match. If it is like, one player is connected and another one is joining and then the match is started between them, I would do something like this.
var waitingResponses = [];
//joins new game (username,password)
app.post('/game/join', function(req, res) {
var username = req.body.username;
var password = req.body.password;
if(pendingJoinRequests.length) {
var waitingPlayerResponse = waitingResponses.shift();
waitingPlayerResponse.send('Game Started'+username);
res.send('Game Started');
}
else {
waitingResponses.push(res);
}
});
I've node application which done spawn(child process) to and application,
the application have host and port:
var exec = require('child_process').spawn;
var child = exec('start app');
console.log("Child Proc ID " + child.pid)
child.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function(data) {
console.log('stdout: ' + data);
});
child.on('close', function(code) {
console.log('closing code: ' + code);
});
some application will start immediately and some application will take some time 10 - 20 sec until they start.
Now I use the node http proxy to run the app and the problem is that Im getting error when the use want to run the app before it up and running.
Any idea how somehow I can solve this issue?
proxy.on('error', function (err, req, res) {
res.end('Cannot run app');
});
Btw, I cannot send response 500 in proxy error due to limitation of our framework. Any other idea how can I track the application maybe with some timeout to see weather it send response 200.
UPDATE - Sample of my logic
httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({});
http.createServer(function (req, res) {
console.log("App proxy new port is: " + 5000)
res.end("Request received on " + 5000);
}).listen(5000);
function proxyRequest(req, res) {
var hostname = req.headers.host.split(":")[0];
proxy.web(req, res, {
target: 'http://' + hostname + ':' + 5000
});
proxy.on('error', function (err, req, res) {
res.end('Cannot run app');
});
}
What you need is to listen for the first response on your proxy and look at its status code to determine whether your app started successfully or not. Here's how you do that:
proxy.on('proxyRes', function (proxyRes, req, res) {
// Your target app is definitely up and running now because it just sent a response;
// Use the status code now to determine whether the app started successfully or not
var status = res.statusCode;
});
Hope this helps.
Not sure if it make sense , In your Main App the experience should start with a html page and each child process should have is own loader.
So basically , you need a http Handler, which linger the request until the the child process is ready. So just make and ajax call from the html , and show loading animation till the service is ready .
//Ajax call for each process and update the UI accordingly
$.get('/services/status/100').then(function(resp) {
$('#service-100').html(resp.responseText);
})
//server side code (express syntax)
app.get('/services/status/:id ', function(req,res) {
// Check if service is ready
serviceManager.isReady(req.params.id, function(err, serviceStats) {
if(err) {
//do logic err here , maybe notify the ui if an error occurred
res.send(err);
return;
}
// notify the ui , that the service is ready to run , and hide loader
res.send(serviceStats);
});
})
I am not sure i understand the question correctly, but you want to wait for a child process to spin on request and you want this request to wait for this child process and then be send to it?
If that is so a simple solution will be to use something like this
var count = 0;//Counter to check
var maxDelay = 45;//In Seconds
var checkEverySeconds = 1;//In seconds
async.whilst(
function () {
return count < maxDelay;
},
function (callback) {
count++;
self.getAppStatus(apiKey, function (err, status) {
if (status != 200) {
return setTimeout(callback, checkEverySeconds * 1000);
}
continueWithRequest();
});
},
function (err) {
if (err) {
return continueWithRequest(new Error('process cannot spin!'));
}
}
);
The function continueWithRequest() will forward the request to the child process and the getAppStatus will return 200 when the child process has started and some other code when it is not. The general idea is that whilst will check every second if the process is running and after 45 second if not it will return an error. Waiting time and check intervals can be easily adjusted. This is a bit crude, but will work for delaying the request and setTimeout will start a new stack and will not block. Hope this helps.
If you know (around) how much time the app takes to get up and running, simply add setTimeout(proxyRequest, <Time it takes the app to start in MS>)
(There are most likely more smart/complicated solutions, but this one is the easiest.)
Why not use event-emitter or messenger?
var eventEmitter = require('event-emitter')
var childStart = require('./someChildProcess').start()
if (childStart !== true) {
eventEmitter.emit('progNotRun', {
data: data
})
}
function proxyRequest(req, res) {
var hostname = req.headers.host.split(":")[0];
proxy.web(req, res, {
target: 'http://' + hostname + ':' + 5000
});
eventEmitter.on('progNotRun', function(data) {
res.end('Cannot run app', data);
})
}
I'm trying to write a simple node.js server with Server Sent Event abilities without socket.io. My code runs well enough, but I ran into a huge problem when I was testing it.
If I connect to the node.js server from my browser, it will receive the server events fine. But when I refresh the connection, the same browser will start to receive the event twice. If I refresh n times, the browser will receive data n+1 times.
The most I tried this out with was 16 times (16 refreshes) before I stopped trying to count it.
See the screenshot below of the console from my browser. After the refresh (it tries to make an AJAX call), it will output "SSE persistent connection established!" and afterwards it will start receiving events.
Note the time when the events arrive. I get the event twice at 19:34:07 (it logs to the console twice -- upon receipt of the event and upon writing of the data to the screen; so you can see four logs there).
I also get the event twice at 19:34:12.
Here's what it looks like at the server side after the client has closed the connection (with source.close() ):
As you can see, it is still trying to send messages to the client! Also, it's trying to send the messages twice (so I know this is a server side problem)!
I know it tries to send twice because it sent two heartbeats when it's only supposed to send once per 30 seconds.
This problem magnifies when open n tabs. What happens is each open tab will receive n*n events. Basically, how I interpret it is this:
Opening the first tab, I subscribe to the server once. Opening the second tab, I subscribe both open tabs to the server once again -- so that's 2 subscriptions per tab. Opening a third tab, I subscribe all three open tabs to the events once more, so 3 subscriptions per tab, total of 9. And so on...
I can't verify this, but my guess is that if I can create one subscription, I should be able to unsubscribe if certain conditions are met (ie, heartbeat fails, I must disconnect). And the reason this is happening is only because of the following:
I started setInterval once, and an instance of it will forever run unless I stop it, or
The server is still trying to send data to the client trying to keep the connection open?
As for 1., I've already tried to kill the setInterval with clearInterval, it doesn't work. As for 2, while it's probably impossible, I'm leaning towards believing that...
Here's server side code snippets of just the relevant parts (editing the code after the suggestions from answers):
server = http.createServer(function(req, res){
heartbeatPulse(res);
}).listen(8888, '127.0.0.1', 511);
server.on("request", function(req, res){
console.log("Request Received!");
var route_origin = url.parse(req.url);
if(route_origin.query !== null){
serveAJAX(res);
} else {
serveSSE(res);
//hbTimerID = timerID.hbID;
//msgTimerID = timerID.msgID;
}
req.on("close", function(){
console.log("close the connection!");
res.end();
clearInterval(res['hbID']);
clearInterval(res['msgID']);
console.log(res['hbID']);
console.log(res['msgID']);
});
});
var attachListeners = function(res){
/*
Adding listeners to the server
These events are triggered only when the server communicates by SSE
*/
// this listener listens for file changes -- needs more modification to accommodate which file changed, what to write
server.addListener("file_changed", function(res){
// replace this with a file reader function
writeUpdate = res.write("data: {\"date\": \"" + Date() + "\", \"test\": \"nowsssss\", \"i\": " + i++ + "}\n\n");
if(writeUpdate){
console.log("Sent SSE!");
} else {
console.log("SSE failed to send!");
}
});
// this listener enables the server to send heartbeats
server.addListener("hb", function(res){
if(res.write("event: hb\ndata:\nretry: 5000\n\n")){
console.log("Sent HB!");
} else {
// this fails. We can't just close the response, we need to close the connection
// how to close a connection upon the client closing the browser??
console.log("HB failed! Closing connection to client...");
res.end();
//console.log(http.IncomingMessage.connection);
//http.IncomingMessage.complete = true;
clearInterval(res['hbID']);
clearInterval(res['msgID']);
console.log(res['hbID']);
console.log(res['msgID']);
console.log("\tConnection Closed.");
}
});
}
var heartbeatPulse = function(res){
res['hbID'] = "";
res['msgID'] = "";
res['hbID'] = setInterval(function(){
server.emit("hb", res);
}, HB_period);
res['msgID'] = setInterval(function(){
server.emit("file_changed", res);
}, 5000);
console.log(res['hbID']);
console.log(res['msgID'])
/*return {
hbID: hbID,
msgID: msgID
};*/
}
var serveSSE = function(res){
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Access-Control-Allow-Origin": "*",
"Connection": "keep-alive"
});
console.log("Establishing Persistent Connection...");
if(res.write("event: connector\ndata:\nretry: 5000\n\n")){
// Only upon receiving the first message will the headers be sent
console.log("Established Persistent Connection!");
}
attachListeners(res);
console.log("\tRequested via SSE!");
}
This is largely a self project for learning, so any comments are definitely welcome.
One issue is that you are storing request-specific variables outside the scope of the http server. So what you could do instead is to just call your setInterval()s once right after you start the http server and not start individual timers per-request.
An alternative to adding event handlers for every request might be to instead add the response object to an array that is looped through inside each setInterval() callback, writing to the response. When the connection closes, remove the response object from the array.
The second issue about detecting a dead connection can be fixed by listening for the close event on the req object. When that is emitted, you remove the server event (e.g. file_changed and hb) listeners you added for that connection and do whatever other necessary cleanup.
Here's how I got it to work:
Made a global heart object that contains the server plus all the methods to modify the server
var http = require("http");
var url = require("url");
var i = 0; // for dev only
var heart = {
server: {},
create: function(object){
if(!object){
return false;
}
this.server = http.createServer().listen(8888, '127.0.0.1');
if(!this.server){
return false;
}
for(each in object){
if(!this.listen("hb", object[each])){
return false;
}
}
return true;
},
listen: function(event, callback){
return this.server.addListener(event, callback);
},
ignore: function(event, callback){
if(!callback){
return this.server.removeAllListeners(event);
} else {
return this.server.removeListener(event, callback);
}
},
emit: function(event){
return this.server.emit(event);
},
on: function(event, callback){
return this.server.on(event, callback);
},
beating: 0,
beatPeriod: 1000,
lastBeat: false,
beat: function(){
if(this.beating === 0){
this.beating = setInterval(function(){
heart.lastBeat = heart.emit("hb");
}, this.beatPeriod);
return true;
} else {
return false;
}
},
stop: function(){ // not applicable if I always want the heart to beat
if(this.beating !== 0){
this.ignore("hb");
clearInterval(this.beating);
this.beating = 0;
return true;
} else {
return false;
}
},
methods: {},
append: function(name, method){
if(this.methods[name] = method){
return true;
}
return false;
}
};
/*
Starting the heart
*/
if(heart.create(object) && heart.beat()){
console.log("Heart is beating!");
} else {
console.log("Failed to start the heart!");
}
I chained the req.on("close", callback) listener on the (essentially) server.on("request", callback) listener, then remove the callback if the close event is triggered
I chained a server.on("heartbeat", callback) listener on the server.on("request", callback) listener and made a res.write() when a heartbeat is triggered
The end result is each response object is being dictated by the server's single heartbeat timer, and will remove its own listeners when the request is closed.
heart.on("request", function(req, res){
console.log("Someone Requested!");
var origin = url.parse(req.url).query;
if(origin === "ajax"){
res.writeHead(200, {
"Content-Type": "text/plain",
"Access-Control-Allow-Origin": "*",
"Connection": "close"
});
res.write("{\"i\":\"" + i + "\",\"now\":\"" + Date() + "\"}"); // this needs to be a file reading function
res.end();
} else {
var hbcallback = function(){
console.log("Heartbeat detected!");
if(!res.write("event: hb\ndata:\n\n")){
console.log("Failed to send heartbeat!");
} else {
console.log("Succeeded in sending heartbeat!");
}
};
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Access-Control-Allow-Origin": "*",
"Connection": "keep-alive"
});
heart.on("hb", hbcallback);
req.on("close", function(){
console.log("The client disconnected!");
heart.ignore("hb", hbcallback);
res.end();
});
}
});