0

I need to know how do I execute line(s) of code after every callback function has ended.

I'm using rcon package to send a rcon command to a Half-Life Dedicated Server(HLDS) hosting Counter Strike 1.6 server and get the response back. Problem is sometimes the response is divided into parts(I think its due to connection with UDP, TCP doesn't work). First I used res.send() in conn.on() with event 'response' callback function but I got error saying can't send HTTP headers. I got to know about res.write(), it can save what I need and then use res.send() later. But I don't know where is the proper place in post I can use res.send() after all 'response' has come back. I tried using the command after conn.connect() and other places but it hasn't worked.

const express = require('express');
var Rcon = require('rcon');

const app = express();
const port = 3000;
app.use(express.urlencoded({extended: true}));

app.get("/", function(req,res){
  res.sendFile(__dirname + "/index.html");
});

app.post("/", function(req, res) {

    var resp = "";
    var ip = req.body.serverip;
    var pass = req.body.pass;
    var command = req.body.command;

    var options = {
      tcp: false,
      challenge: true
    };

    var conn = new Rcon(ip, 27015, pass, options);

    conn.on('auth', function () {
      // You must wait until this event is fired before sending any commands,
      // otherwise those commands will fail.
      console.log("Authenticated");
      console.log("Sending command:" + command);
      conn.send(command);

    });

    res.setHeader("Content-Type", "text/html; charset=UTF-8");
    res.write("<!DOCTYPE html><html><body>")
    conn.on('response', function(str)  {
        console.log("Response: "+str);
        res.write(str);
    });

    conn.on('error', function (err) {
      console.log("Error: " + err);
    });

    conn.on('end', function () {
      console.log("Connection closed");
      process.exit();
    });

    conn.connect();
    res.end("Done</body></html>");
});

app.listen(port, function(){
  console.log("Server is listening on port " +port);
});


});
  • 1
    The RCON client establishes a connection to the RCON server _once_ and then receives _many_ responses. By contrast, an HTTP client makes _one_ request and receives _one_ response. It is unclear how you want to bring these two together. What HTTP response do you want to construct with the code that you shared in response to a `POST /` request? – Heiko Theißen Nov 01 '22 at 09:08
  • I want to get all the responses back and send them with to a simple HTML page. For example, using the status command with rcon when the server has many players or is full, the response is divided into multiple parts, this is fine for console. I want to know how I can use the multiple responses after they've finished and send them together at once. – shiro_1941 Nov 01 '22 at 09:37
  • 1
    If there are multiple parts, how do you recognize the last part? – Heiko Theißen Nov 01 '22 at 09:38
  • I can recognize it visually because each new response starts with the "Response" line due to being in console.log() If I do use res.write() and then use res.send() outside the function I get an empty response in HTML page. I'm not sure if its the library dividing in multiple parts or rcon itself. I'm new to js and node so I can't figure it out, I used the [example that was given](https://github.com/pushrax/node-rcon/blob/master/examples/basic.js). I have updated and added full code if that helps – shiro_1941 Nov 01 '22 at 10:24
  • You finish your page with a synchronous `res.end` before a response can come in asynchronously. See my edited answer. – Heiko Theißen Nov 01 '22 at 10:42
  • Does this answer your question? [How to make a function wait until a callback has been called using node.js](https://stackoverflow.com/questions/5010288/how-to-make-a-function-wait-until-a-callback-has-been-called-using-node-js) – derpirscher Nov 01 '22 at 10:43

2 Answers2

0

If you want to "stream" the response parts to an HTML page, you can use the following:

res.setHeader("Content-Type", "text/html; charset=UTF-8");
res.write("<!DOCTYPE html><html><body>"); // start an HTML page
conn.on('response', function(str) {
  res.write(str);
});

The rudimentary start of the HTML page, which you issue even before the first response comes in, causes the browser to display the text of incoming responses as you write them to the page. (See also here.)

If you can recognize the last response, you could finish the page with

conn.on('response', function(str) {
  res.write(str);
  if (str is the last response)
    res.end("</body></html>");
});

but the "response streaming" works even if there is no "last" response: in this case, the browser keeps waiting for more, so the page never finishes, but you can still read what is on it so far.

Heiko Theißen
  • 12,807
  • 2
  • 7
  • 31
  • It would be hard to figure out the response since different commands will have different response. I was able to find an answer to my problem and posted it. – shiro_1941 Nov 01 '22 at 12:18
0

Looking at this answer made me figure it out. I simply needed to remove conn.send() from auth and use it with a timeout after conn.connect(). Same with the response, a timeout and then use res.end(); While its not what I originally asked for in the title which is due to my mistake, it is what I was looking to do, make it work

app.post("/", function(req, res) {

    var ip = req.body.serverip;
    var pass = req.body.pass;
    var command = req.body.command;

    var options = {
      tcp: false,
      challenge: true
    };

    var conn = new Rcon(ip, 27015, pass, options);


    conn.on('auth', function () {
      // You must wait until this event is fired before sending any commands,
      // otherwise those commands will fail.
      console.log("Authenticated");
      console.log("Sending command:" + command);
      // conn.send(command);

    });
    conn.on('response', function(str)  {
        console.log("Response: "+str);
        res.write("Response: "+str);
    });
    conn.on('error', function (err) {
      console.log("Error: " + err);
      res.sendFile(__dirname + "/failure.html");
    });
    conn.on('end', function () {
      // res.end("Done</body></html>");
      console.log("Connection closed");
      process.exit();
    });

    res.setHeader("Content-Type", "text/html; charset=UTF-8");
    res.write("<!DOCTYPE html><html><body><pre>")  
    conn.connect();
    setTimeout(function(){
      conn.send(command);
    },1000);

    setTimeout(function(){
      res.end("Done</pre></body></html>");
    }, 2000);
});