0

I have this game I run with shell script. When the game is running through terminal, it actively prints informations like "Connected to Server" or "Disconnected" and so on.

const app = Application.currentApplication()
app.includeStandardAdditions = true

const terminalOutput = app.doShellScript('pathToGame');
console.log(terminalOutput);

This code only prints out when the application stops/quits. Just the last statement is printed. I was trying to find a way to get every statement printed. Whether its in a log file or as a return value everything it prints something while the process is running, without having to stop/quit it.

01:21:22: Application Running
01:21:23: Request connection to "ip address"
01:21:24: Connected to server "ip address"
01:45:01: Disconnected from server "ip address"
//Here my script would detect and try to log in again

For example: I open the game. The game prints "Application Running", now with that value, I know the game is open and I can tell my script to log in. Then, if somehow the game prints "Disconnected from server" my app will detect that stdout and will fall into a function where it is going to try to log in again.

Is getting stdout while the app is still running possible?

RobC
  • 22,977
  • 20
  • 73
  • 80

1 Answers1

0

This is not possible using just plain JXA doing so as doShellScript is somewhat very limited.

Fully process execution can still be achieved leveraging Objective-C bridge. Following is how I execute a command as a subprocess in my project to get the attaching terminal columns.

// Import `Foundation` to be able use `NSTask`.
ObjC.import('Foundation');

// Launch `NSTask` `tput cols` to get number of cols.
const { pipe } = $.NSPipe;
const file = pipe.fileHandleForReading;
const task = $.NSTask.alloc.init;

task.launchPath = '/bin/sh';
task.arguments = ['-c', 'tput cols'];
task.standardOutput = pipe;

task.launch; // Run the task.

let data = file.readDataToEndOfFile; // Read the task's output.
file.closeFile;

// Parse the task's output.
data = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding);
const result = ObjC.unwrap(data); // Unwrap `NSString`.
return parseInt(result, 10);

For your case, check out https://developer.apple.com/documentation/foundation/pipe/1414352-filehandleforreading to see the documentation on how to receive data from the pipe.fileHandleForReading.

Following is my example solution though it isn't tested yet.

// Import `Foundation` to be able use `NSTask`.
ObjC.import('Foundation');

// Launch `NSTask`.
const { pipe } = $.NSPipe;
const file = pipe.fileHandleForReading;
const task = $.NSTask.alloc.init;

task.launchPath = '/bin/sh';
task.arguments = ['-c', 'pathToYourGame'];
task.standardOutput = pipe;

task.launch; // Run the task.

let data;
for(;;) {
  data = file.availableData; // Read the task's output.
  if(!data) {
    file.closeFile;
    break;
  }

  // Parse the task's output.
  data = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding);
  const result = ObjC.unwrap(data);

  // Process your streaming data.
  doSomething(result);
}
phuctm97
  • 136
  • 1
  • 9