0

Link to a similar problem that has no answers, but written in C

I'm using NodeJS to parse output from ark-server-tools, which is a layer on top of SteamCMD. What I'd like to do is parse the progress of the update and assign it to a variable, which I'll return as a GET call that the client can use to check progress of the update.

I put the log results of an update into a file to run my code against, which I've put in a PasteBin for brevity.

update.js

app.get('/update', function(req, res) {
  var toReturn;
  var outputSoFar;
  var total;
  var startPos;
  var endPos = 0;

  //var proc = spawn('arkmanager', ['update', '--safe']);
  var proc = spawn('./update-log.sh'); //for testing purposes
  proc.stdout.on('data', function(data){
    outputSoFar += data.toString();


    //if server is already updated
    if (outputSoFar.indexOf('Your server is already up to date!') !== -1) {
      toReturn = 'Server is already up-to-date.';
    }

    //find update progress
    if (outputSoFar.indexOf('progress:') !== -1) {
      for(var line in outputSoFar.split('\n')){
        console.log('found progress');
        startPos = outputSoFar[line].indexOf('progress:', endPos) + 10; //get the value right after progress:_, which should be a number
        endPos = outputSoFar[line].indexOf(' (', startPos); // find the end of this value, which is signified by space + (
        console.log(outputSoFar[line].substring(startPos, endPos).trim());
        updatePercent = outputSoFar[line].substring(startPos, endPos).trim(); //returned to the `checkUpdateProgress` endpoint
      }

      toReturn = 'Updating...';
    }
  });

  proc.stderr.on('data', function(data){
    console.log(data);
  });

  proc.on('close', function (code, signal) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write(JSON.stringify(toReturn));
    res.end();
  });
}

/*
 * Returns progress of an update
 */
app.get('/updateProgress', function(req, res){
    console.log('updatePercent: ' + updatePercent);
    res.send(JSON.stringify(updatePercent));
});

Couple questions:

1) Is this the best way to architect my RESTful API? One call for the action of updating and another for checking the progress of the update?

2) I'd love a better way to test the function, as echoing the console log returns the data in one piece, as opposed to a data stream. How do I do this?

3) I'm pretty sure the parsing function itself isn't quite right, but I'm having a hard time testing it because of #2.

If you want to take a look at the project in its entirety, here's the repo. Thanks in advance for your help!

Community
  • 1
  • 1
Samuel Hill
  • 176
  • 1
  • 13

1 Answers1

1

For one of your questions:

Is this the best way to architect my RESTful API? One call for the action of updating and another for checking the progress of the update?

As implemented now, I don't think your service can support concurrent requests correctly. updatePercent is a shared global variable. If i hit /update endpoint with a single client, it will start the ./update-log.sh command.

If I request /update again, it will start another update and overwrite the global updateProgress. There doesn't seem to be anything mapping an updatePercent with the correct process

Additionally, there could be serious performance issues to each request spawning a new process. Node might be able to handle hundreds or thousands of concurrent connections using a single thread, but each request is going to spawn a new process, just something to profile

dm03514
  • 54,664
  • 18
  • 108
  • 145
  • Great point - should I be checking if an update is already in progress first, then? And return 'update is already in progress' if true? – Samuel Hill Oct 21 '15 at 21:04