spectcl

0.6.3 • Public • Published

spectcl Build Status Coverage Status Dependencies NPM Follow Spectcl

spectcl (pronounced spectacle) is a node.js module for spawning child applications (such as ssh) and seamlessly controlling them using javascript callbacks. spectcl is based on the ideas of the Expect library by Don Libes and the pexpect library by Noah Spurrier.

Note that this module is under initial development. The API is subject to change until we reach the v1.0.0 Milestone.

Motivation

Node.js has good built in control for spawning child processes. nexpect built on those methods that allowed developers to easily pipe data to child processes and assert the expected response.

spectl stands on the shoulders of nexpect; one of this module's main goals is to more closely emulate the Expect extensions built into the Tcl language. Its concentration is to map the functionality and features of the Expect library as closely as possible, while adhering to an event-driven control flow.

Installation

  $ npm install --save spectcl

Usage

var Spectcl = require('spectcl')
  , session = new Spectcl()
 
session.spawn('node --interactive')
session.expect([
    '>', function(match, matched, cb){
        session.send('process.version\n')
        cb()
    }
], function(err){
    session.expect([
        '>', function(match, matched, cb){
            session.send('process.exit()\n')
            cb()
        }
    ], function(err){
        var version = session.expect_out.buffer.match(/(v[0-9]\.[0-9]+\.[0-9]+)/)[1]
        console.log('version is: %s', version)
    })
})

In the example above, we spawn a node interactive interpreter, have it output the value of process.version, and send process.exit(). We capture the results from the expect_out buffer, as well as the input string that was matched, and close the session, printing the version in the final callback.

Compare to this Tcl Expect block:

package require Expect
 
log_user 0
 
spawn node "--interactive"
expect ">" {
    exp_send "process.version\n"
}
expect ">" {
    exp_send "process.exit()\n"
}
regexp {(v[0-9]\.[0-9]+\.[0-9]+)} $expect_out(buffer) -> version
puts "version is: $version"

Getting Started

var session = new Spectcl()

A spectcl object exposes two main functions: spawn and expect. A Spectcl object is intended to only have one spawned child at a time. To operate concurrently on many sessions, you will need to spawn an object for each concurrent session.

spawn()

This function is used to spawn the child session that you'll be expecting on. Note that like Tcl Expect, by default your child will be wrapped in a pseudoterminal. Some sessions, like Telnet, are not sensitive to having a pty, and as such can be spawned without a pty if desired. You can do that like so:

session.spawn('echo', ['hello'], {}, {noPty: true})

The Spectcl object will emit exit when the child is complete, and error if there is an issue spawning the child.

expect()

This function will wait for data from the stream to match one of the expectations you specify. It takes an array and a final callback, structured like so:

session.expect([
    'hello', function(){
        // handle hello here
        cb()
    }
], function(){
    console.log('all done!')
})

The array needs to be even in length. The even indices are your "expectations". These can be of type String or Regexp, and are things that you want to match on. The odd indices will be the handler functions for the expectation that precedes it. In the example above, we are going to match on /hello/. When we do, the handler function is called.

The handler functions will be called with the match object (Either a String or the Match object from the RegExp test), the String or object that is a result of the successful match ("Matched"), and the final callback. For example, if the Match object is /he([a-z])lo/ and the input is "hello," the Matched object will be ["hello","l"]. If the Match object is a String, the Matched parameter is the same as the Match: e.g. 'hello', 'hello'.

Like Tcl Expect, expect() will wait until a match occurs, a specified period of time has elapsed, or EOF is seen. The timeout period can be specified when creating the Spectcl object by specifying a timeout property in the options object. The default period is 30s.

This specifies the timeout period, in ms:

var session = new Spectcl({timeout: 5000})

...and you can expect TIMEOUT or EOF like so:

session.expect([
    session.TIMEOUT, function(match, cb){
        cb(new Error('timeout'))
    },
    session.EOF, function(match, cb){
        cb(new Error('eof'))
    }
], function(err){
    if(err){ console.log(err) }
})

In the above sample, we are expecting to see either a TIMEOUT or an EOF, and can handle it appropriately. It is important to note that if you do not expect TIMEOUT or EOF and one occurs, the final callback will be called, with no Error:

session.expect([
    /foo/, function(match, matched, cb){
        // do things
        cb()
    }
], function(err){
    if(err){ console.log(err) }
})

In the above example, if the session is ended abruptly or if it is inactive for the specified period of time, then the final callback will be called directly, since no handler was specified for either case.

This design mirrors Tcl Expect's expect procedure, which returns immediately for these cases if they are not expected.

Examples

The examples directory contains spectcl code examples, as well as their Tcl Expect equivalents.

API Reference

The Spectcl API is documented on spectcl.github.io.

Tests

All tests are written with mocha:

  $ npm test

Authors

Greg Cochard and Ryan Milbourne

Originally forked from nodejitsu/nexpect by Elijah Insua, Marak Squires, and Charlie Robbins.

Package Sidebar

Install

npm i spectcl

Weekly Downloads

1

Version

0.6.3

License

MIT

Last publish

Collaborators

  • gcochard
  • rmilbourne