I'm using a nodejs telnet implementation which uses an event to provide notification each time data is received from a telnet client, which can be subscribed as follows:
client.on('data', [callback]);
I'm also using a generator runner (generator-runner on npm) to execute workflows.
The problem I'm having is that yielding values in this way requires something more like a promise: a single delegate passed on to process a single value. How would I go about writing a function which could be placed in the generator yield statements, and could be repeated every time I want to yield more input?
I've tried using Baconjs for this, but I don't think there's a way to block waiting for a single value on a stream, at least I can't find such a method.
I'm open to any advice. My only real requirement is that I be able to place my workflows in a flat block of code without chaining promises.
Here's the code I've got mocked up, which simply doesn't work:
var requirejs = require('requirejs');
requirejs(['telnet', 'baconjs', 'colourise', 'lodash', 'generator-runner'], function(Telnet, Bacon, Colourise, _, Async) {
var configureClient = client => {
client.do.transmit_binary();
};
Telnet.createServer(client => {
var session = {
connectedAt: Date.now(),
user: { }
},
write = _.compose(_.bind(client.write, client), Colourise.encode),
readStream = Bacon.fromBinder(function (sink) {
client.on('data', function (data) {
sink({ client : client, data : data, session : session });
})}),
read = () => readStream.take(1).toPromise();
configureClient(client);
write("%xxWelcome!\r\n")
Async(function*(){
write("Username: ");
var user = yield read();
console.write("Username entered: " + user);
write("Password: ");
var password = yield read();
console.write("Password entered: " + password);
});
}).listen(8100);
});
I've gotten this working by using 'fromEvent' in Baconjs and using 'firstToPromise'. I was getting exceptions thrown from 'fromBinding', so I don't know what was up there, but it slowed down my progress a lot.
Below is the simplified and working code. Requires ES6 (I used node flags --harmony and --harmony_generators.)
On a side note, I'm hugely excited about the implications of this technique!
var requirejs = require('requirejs');
requirejs(['telnet', 'baconjs', 'generator-runner', 'lodash'],
function(Telnet, Bacon, Async, _) {
var configureClient = client => {
client.do.transmit_binary();
};
Telnet.createServer(client => {
var write = _.bind(client.write, client),
readStream = Bacon.fromEvent(client, 'data'),
readAsync = () => readStream.firstToPromise();
configureClient(client);
write("Welcome!\r\n")
Async(function*(){
write("Username: ");
var user = yield readAsync();
console.log("Username entered: " + user);
write("Password: ");
var password = yield readAsync();
console.log("Password entered: " + password);
});
}).listen(8100);
}
);