anonymous name anonymous name - 4 months ago 51
Node.js Question

Node.js readline-sync freeze my server (windows)

Node.js readline-sync pause my server ,how can I do that the server will work and print me information ,while it's waiting for commands?

Maybe something with multithreading ,or 2 cmd but that less good.

This is my server code:

'use strict';

var http = require('http'),
fs = require('fs');
var PORT = 8080;
var requestIp = require('request-ip');
var os = require('os');
var hostname = os.hostname();
var readlineSync = require('readline-sync');

//get client ip
var ipMiddleware = function(request, response) {
var clientIp = requestIp.getClientIp(request);
return clientIp.slice(7);
};

//print function
function msg(msg){
msg = msg.charAt(0).toUpperCase() + msg.slice(1);
console.log("> "+msg);
console.log();
}

//command function
function inpt(){
var command = readlineSync.question('> ');//this is the line that freezing all
console.log();
if(command === "exit" || command === "stop" || command === "end" ){
msg(command+"ing server...");
process.exit();
}if(command.substring(0, 14) === "switch port to " && command.length === 18 && parseInt(command.substring(14,18)).isInteger > 0){
PORT = parseInt(command.substring(14,18));
msg("port changed to "+PORT);
http.createServer(onRequest).listen(PORT);
msg("LAN server running on "+addresses[0]+":"+PORT);
}

else{
msg("sorry but "+command+" is an unknown command.");
}
//after receiving command its's ask again for input
inpt();
}

//get server ip
var interfaces = os.networkInterfaces();
var addresses = [];
for (var k in interfaces) {
for (var k2 in interfaces[k]) {
var address = interfaces[k][k2];
if (address.family === 'IPv4' && !address.internal) {
addresses.push(address.address);
}
}
}

//404 Response
function send404Response(request,response) {
msg("Error 404 "+ipMiddleware(request,response));
response.writeHeader(404, {"Content-Type": "text/html"});
fs.createReadStream('./404.html').pipe(response);
}

//write html file to client by name
function sendFileResponse(name,request,response) {
msg(name+" page "+ipMiddleware(request,response));
response.writeHeader(200, {"Content-Type": "text/html"});
fs.createReadStream('./'+name+'.html').pipe(response);
}

//handle request
function onRequest(request, response) {
if(request.method == 'GET' && request.url == '/'){
msg("Home page "+ipMiddleware(request,response));
response.writeHeader(200, {"Content-Type": "text/html"});
fs.createReadStream('./index.html').pipe(response);
}else if(request.url.length > 1){
var name = request.url.slice(1);
if(fs.existsSync("./"+name+".html")){
sendFileResponse(name,request,response);
}else{
send404Response(request,response);
}
}else{
send404Response(request,response);
}
}

//start
msg("Server ip: "+addresses[0]);
msg("Hostname: "+hostname);
http.createServer(onRequest).listen(PORT);
msg("LAN server running on "+addresses[0]+":"+PORT);
//on start the cmd will ask for commands
inpt();

Answer

readlineSync() is synchronous. By definition everything will wait until that call finishes. If you can't have that behavior, then use readline().

See https://nodejs.org/api/readline.html#readline_rl_question_query_callback

You might try something like this:

    function inpt(){
    readline.question('> ', function( command ) {
      console.log();
      if(command === "exit" || command === "stop" || command === "end" ){
          msg(command+"ing server...");
          process.exit();
      }if(command.substring(0, 14) === "switch port to " && command.length === 18 && parseInt(command.substring(14,18)).isInteger > 0){
          PORT = parseInt(command.substring(14,18));
          msg("port changed to "+PORT);
          http.createServer(onRequest).listen(PORT);
          msg("LAN server running on "+addresses[0]+":"+PORT);
      }

      else{
          msg("sorry but "+command+" is an unknown command.");
      }
      //after receiving command its's ask again for input
      inpt();
  }
});

You may need to rework the internals a bit, I just put the rest of the code into the callback, so it'll run after command has been assigned.