plexus-csp
Version:
A Go-inspired async library based on ES6 generators
212 lines (166 loc) • 3.9 kB
JavaScript
var core = require('./core');
var channels = require('./channels');
exports.timeout = function(ms) {
var ch = channels.chan();
var t = setTimeout(function() {
clearTimeout(t);
channels.close(ch);
}, ms);
return ch;
};
exports.ticker = function(ms) {
var ch = channels.chan();
var t;
var step = function() {
clearTimeout(t);
t = setTimeout(step, ms);
core.go(function*() {
if (!(yield channels.push(ch, null)))
clearTimeout(t);
});
};
t = setTimeout(step, ms);
return ch;
};
exports.each = function(fn, input) {
return core.go(function*() {
var val;
while (undefined !== (val = yield channels.pull(input)))
if (fn)
yield fn(val);
});
};
exports.pipe = function(input, output, keepOpen) {
return core.go(function*() {
var val;
while (undefined !== (val = yield input.pull()))
if (!(yield output.push(val)))
break;
if (!keepOpen) {
input.close();
output.close();
}
});
};
exports.createLock = function() {
var _busy = channels.chan();
_busy.push(null);
return {
acquire: function() { return _busy.pull(); },
release: function() { return _busy.push(null); }
};
};
exports.iterate = function(next) {
var _closed = false;
return {
pull: function(client) {
var handler = client || core.defer();
var value;
if (!_closed) {
value = next();
if (value === undefined)
_closed = true;
}
handler.resolve(value);
return handler;
},
close: function() {
_closed = true;
}
};
};
exports.generate = function(genFn) {
var _gen = genFn();
return exports.iterate(function() {
var step = _gen.next();
return step.done ? undefined : step.value;
});
};
exports.fromStream = function(stream, closeStream)
{
var output = channels.chan();
var lock = exports.createLock();
stream.on('readable', function() {
core.go(function*() {
var chunk;
yield lock.acquire();
while (null !== (chunk = stream.read())) {
if (!(yield output.push(chunk))) {
closeStream && closeStream();
break;
}
}
lock.release();
});
});
stream.on('end', function() {
core.go(function*() {
yield lock.acquire();
output.close();
});
});
stream.on('error', function(err) {
throw new Error(err);
});
return output;
};
var forward = function(from, to) {
from.then(
function(val) { to.resolve(val); },
function(err) { to.reject(err); }
);
return to;
};
exports.multiChan = function() {
var _open = true;
var _lock = exports.createLock();
var _outchs = [];
return {
push: function(val, handler) {
if (!_open) {
handler.resolve(false);
return;
} else if (val === undefined) {
handler.reject(new Error("push() requires a value"));
return;
}
var deferred = core.go(function*() {
var i;
yield _lock.acquire();
for (i = 0; i < _outchs.length; ++i)
yield _outchs[i].push(val);
_lock.release();
return true;
});
return handler ? forward(deferred, handler) : deferred;
},
close: function() {
_open = false;
},
tap: function(outch) {
return core.go(function*() {
yield _lock.acquire();
_outchs.push(outch);
_lock.release();
});
},
untap: function(outch) {
return core.go(function*() {
var i;
yield _lock.acquire();
i = _outchs.indexOf(outch);
if (i >= 0)
_outchs.splice(i, 1);
_lock.release();
});
},
untapAll: function() {
return core.go(function*() {
yield _lock.acquire();
_outchs.splice(0);
_lock.release();
});
}
};
};
;