Wednesday, February 8, 2012

String that Process

So a comment from Florian Loitsch on my previous post indicated that as opposed to creating a new string from character codes as I was doing for handling output of the process, I can use the existing StringInputStream to automatically wrap the basic input stream into a string. As indicated by the API I can then pull the strings on a per-line basis or as a string chunk. I've revised my example to put both methods to use. Before commenting on it, lets see the code:
#import("dart:io");

void main() {
  // Create a new process with list of arguments and start it.
  Process proc = new Process.start('/usr/bin/snmpget', ['-v', '2c', '-c', 'public', '127.0.0.1', '.1.3.6.1.2.1.1.1.0']);
  
  // Once started, handle the process including receiving input.
  proc.startHandler = beginHandle() {
    print("Inside of start Handler");
    
    // Create StringInputStreams from the basic input streams of the process.
    StringInputStream res = new StringInputStream(proc.stdout);
    StringInputStream err = new StringInputStream(proc.stderr);
    
    // A handle a new line of text added to the input stream (stdout).
    // readLine does not include the terminating new-line character
    res.lineHandler = showLine() {
      print("Inside InputStringStream lineHandler");
      print(res.readLine());
    };
    
    // Handle new data sent to the input stream (stderr)
    // This happens whenever any data is available and does not
    // wait for a new line.
    err.dataHandler = errRead() {
      print("Inside InputStringStream dataHandler");
      print(err.read());
    };
  }; // End off Proc.startHandler
  
  // When the process has ended this handler is called
  // passes process's exit code.
  proc.exitHandler = exitHandle(int exitCode) {
    print("Inside of exit Handler");
    print("Exit code is: ${exitCode}");
    proc.close();
  };
  
  // Called when an error occurs when spawning the process.
  proc.errorHandler = errorHandle(ProcessException errorMsg) {
    print("Inside of Error Handler");
    print(errorMsg);
  };
}

I've also added some comments to the above to help clear it up a little as well. With the particular process I'm launching generally I'm only interested in parsing one return line at a time. So as such with my StringInputStream for stdout I decided to use the lineHandler method. Because stderr may produce more than one line of error, I used the dataHandler trigger the reads. Note that the two are mutually exclusive. That is the same StringInputStream can only define a lineHandler or a dataHandler. Not both.

The lineHandler is called each time a new line is available to the stream. dataHandler is called anytime there's new data available, no matter if it contains a new line or not. This is good if you want to receive a bulk of a string, or potentially expect an unterminated string.

Note I also did not methods for the errorHandlers in this simple example, nor verify if the stream is currently open. Using both this method and the previous one of directly using the basic InputStreams are roughly the same size, however unless you explicitly require the raw character codes, I would personally suggest using the StringInputStream over the basic InputStream for potential performance gains and to help future-proof your code against any internal library chances which make affect results or performance down the road with the InputStream and string from character codes.

No comments:

Post a Comment