UNPKG

mutual

Version:

Scala-inspired Actors that use Redis as a message transport

465 lines (438 loc) 16.8 kB
// Generated by CoffeeScript 1.12.7 (function() { var DurableChannel, EventChannel, Redis, RemoteQueue, Transport, randomKey, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; randomKey = require("key-forge").randomKey; Redis = require("pirate").Redis; EventChannel = require("./event-channel"); RemoteQueue = require("./remote-queue"); Transport = require("./redis-transport"); DurableChannel = (function(superClass) { extend(DurableChannel, superClass); function DurableChannel(options) { DurableChannel.__super__.constructor.apply(this, arguments); this.ending = false; this.name = options.name, this.timeoutMonitorFrequency = options.timeoutMonitorFrequency, this.transport = options.transport; if (this.name == null) { throw new Error("Durable channels cannot be anonymous"); } this.timeoutMonitor = null; if (this.timeoutMonitorFrequency == null) { this.timeoutMonitorFrequency = 1000; } this.events = new EventChannel; this.isTransportShared = true; if (this.transport == null) { this.isTransportShared = false; this.transport = new Transport({ host: options.redis.host, port: options.redis.port }); this.transport.events.forward(this.events); } this.queue = new RemoteQueue({ name: this.name + ".queue", transport: this.transport }); this.monitorTimeouts(); setImmediate((function(_this) { return function() { return _this.fire({ event: "ready" }); }; })(this)); } DurableChannel.prototype["package"] = function(arg) { var content, message, requestId, timeout, to; content = arg.content, to = arg.to, requestId = arg.requestId, timeout = arg.timeout; return message = { id: randomKey(16), requestId: requestId, from: this.name, to: to, timeout: timeout, content: content }; }; DurableChannel.prototype.getMessage = function(channel, id) { return this.events.source((function(_this) { return function(events) { return _this.transport._acquire(function(client) { return client.hget(channel + ".messages", id, function(err, data) { _this.transport._release(client); return events.callback(err, data != null ? JSON.parse(data) : null); }); }); }; })(this)); }; DurableChannel.prototype.putMessage = function(channel, id, message) { return this.events.source((function(_this) { return function(events) { return _this.transport._acquire(function(client) { return client.hset(channel + ".messages", id, JSON.stringify(message), function(err, data) { _this.transport._release(client); return events.callback(err, data); }); }); }; })(this)); }; DurableChannel.prototype.deleteMessage = function(channel, id) { return this.events.source((function(_this) { return function(events) { return _this.transport._acquire(function(client) { return client.hdel(channel + ".messages", id, function(err, data) { _this.transport._release(client); return events.callback(err, data); }); }); }; })(this)); }; DurableChannel.prototype.getDestinationQueue = function(name) { var queue; return queue = new RemoteQueue({ name: name + ".queue", transport: this.transport }); }; DurableChannel.prototype.setMessageTimeout = function(name, channel, id, timeout) { var client, serverTime; if ((channel != null) && (id != null) && (timeout != null)) { client = null; serverTime = 0; return this.events.serially((function(_this) { return function(go) { go(function() { return _this.events.source(function(events) { return _this.transport._acquire(function(_client) { client = _client; return events.callback(); }); }); }); go(function() { return _this.events.source(function(events) { return client.time(function(err, data) { if (err != null) { _this.transport._release(client); } else { serverTime = data[0] * 1000; } return events.callback(err, data); }); }); }); return go(function() { return _this.events.source(function(events) { return client.zadd([name + ".pending", serverTime + timeout, channel + "::" + id], function(err, data) { _this.transport._release(client); return events.callback(err, data); }); }); }); }; })(this))(); } }; DurableChannel.prototype.clearMessageTimeout = function(name, channel, id) { if (id != null) { return this.events.source((function(_this) { return function(events) { return _this.transport._acquire(function(client) { return client.zrem([name + ".pending", channel + "::" + id], function(err, data) { _this.transport._release(client); return events.callback(err, data); }); }); }; })(this)); } }; DurableChannel.prototype.getMessageTimeout = function(name, channel, id) { if (id != null) { return this.events.source((function(_this) { return function(events) { return _this.transport._acquire(function(client) { return client.zscore([name + ".pending", channel + "::" + id], function(err, data) { _this.transport._release(client); return events.callback(err, data); }); }); }; })(this)); } }; DurableChannel.prototype.monitorTimeouts = function() { var loopToMonitor; loopToMonitor = (function(_this) { return function() { return _this.events.serially(function(go) { var client, serverTime; client = null; serverTime = 0; go(function() { return _this.events.source(function(events) { return _this.transport._acquire(function(_client) { client = _client; return events.callback(); }); }); }); go(function() { return _this.events.source(function(events) { return client.time(function(err, data) { if (err != null) { _this.transport._release(client); } else { serverTime = data[0] * 1000; } return events.callback(err, data); }); }); }); go(function() { return _this.events.source(function(events) { return client.zrangebyscore([_this.name + ".pending", 0, serverTime], function(err, data) { _this.transport._release(client); return events.callback(err, data); }); }); }); go(function(expiredMessages) { if (expiredMessages.length === 0) { return; } return _this.events.source(function(events) { var iterate, iterationCount; iterationCount = 0; return (iterate = function() { var _events, expiredMessageTokens; if (iterationCount < expiredMessages.length) { expiredMessageTokens = expiredMessages[iterationCount].split("::"); iterationCount++; _events = _this.expireMessage(expiredMessageTokens[0], expiredMessageTokens[1]); _events.on("success", function() { return iterate(); }); return _events.on("error", function() { return iterate(); }); } else { return events.emit("success"); } })(); }); }); return go(function() { if (!_this.ending) { return _this.timeoutMonitor = setTimeout(loopToMonitor, _this.timeoutMonitorFrequency); } }); })(); }; })(this); return this.timeoutMonitor = setTimeout(loopToMonitor, this.timeoutMonitorFrequency); }; DurableChannel.prototype.expireMessage = function(channel, id) { var message; message = null; return this.events.serially((function(_this) { return function(go) { go(function() { return _this.getMessage(channel, id); }); go(function(_message) { message = _message; return _this.getMessageTimeout(_this.name, channel, id); }); return go(function(timeout) { if (timeout == null) { return; } return _this.events.serially(function(go) { go(function() { if (message != null) { return _this.deleteMessage(channel, id); } }); go(function() { return _this.clearMessageTimeout(_this.name, channel, id); }); return go(function() { if (message != null) { return _this.fire({ event: "timeout", content: { content: message.content, requestId: message.requestId } }); } }); })(); }); }; })(this))(); }; DurableChannel.prototype.send = function(arg) { var content, message, timeout, to; content = arg.content, to = arg.to, timeout = arg.timeout; message = this["package"]({ content: content, to: to, timeout: timeout }); return this.events.serially((function(_this) { return function(go) { go(function() { return _this.putMessage(to, message.id, message); }); go(function() { return _this.setMessageTimeout(_this.name, to, message.id, message.timeout); }); return go(function() { return _this.getDestinationQueue(to).emit("message", message.id); }); }; })(this))(); }; DurableChannel.prototype.reply = function(arg) { var message, response, timeout; message = arg.message, response = arg.response, timeout = arg.timeout; return this.events.serially((function(_this) { return function(go) { go(function() { return _this.getMessage(_this.name, message.requestId); }); return go(function(request) { if (request == null) { return null; } message = _this["package"]({ content: response, to: request.from, requestId: message.requestId, timeout: timeout }); return _this.events.serially(function(go) { go(function() { return _this.clearMessageTimeout(request.from, _this.name, message.requestId); }); go(function() { return _this.putMessage(request.from, message.id, message); }); go(function() { return _this.setMessageTimeout(_this.name, request.from, message.id, message.timeout); }); return go(function() { return _this.getDestinationQueue(request.from).emit("message", message.id); }); })(); }); }; })(this))(); }; DurableChannel.prototype.close = function(message) { return this.events.serially((function(_this) { return function(go) { go(function() { return _this.deleteMessage(_this.name, message.responseId); }); return go(function() { return _this.clearMessageTimeout(message.to, message.from, message.responseId); }); }; })(this))(); }; DurableChannel.prototype.listen = function() { return this.events.source((function(_this) { return function(events) { return _this.queue.listen().on("success", function() { var messageHandler; messageHandler = function(messageId) { return _this.events.serially(function(go) { go(function() { return _this.getMessage(_this.name, messageId); }); go(function(message) { if (message == null) { return null; } if (message.requestId == null) { return message; } return _this.events.source(function(events) { return _this.events.serially(function(go) { go(function() { return _this.getMessage(message.from, message.requestId); }); return go(function(request) { return _this.events.serially(function(go) { go(function() { if (request != null) { return _this.deleteMessage(message.from, message.requestId); } else { return _this.deleteMessage(_this.name, messageId); } }); return go(function() { return events.emit("success", (request != null ? message : null)); }); })(); }); })(); }); }); go(function(message) { var _message; if (message != null) { _message = { content: message.content }; _message.from = message.requestId != null ? message.to : message.from; _message.to = message.requestId != null ? message.from : message.to; _message.requestId = message.requestId != null ? message.requestId : message.id; if (message.requestId != null) { _message.responseId = message.id; } return _this.fire({ event: "message", content: _message }); } }); return go(function() { var ref, ref1; if (((ref = _this.channels["message"]) != null ? (ref1 = ref.handlers) != null ? ref1.length : void 0 : void 0) > 0) { return _this.queue.once("message", messageHandler); } }); })(); }; if (_this.superOn == null) { _this.superOn = _this.on; } _this.on = function(event, handler) { _this.superOn(event, handler); if (event === "message") { return _this.queue.once("message", messageHandler); } }; return events.emit("success"); }); }; })(this)); }; DurableChannel.prototype.end = function() { this.ending = true; clearTimeout(this.timeoutMonitor); return this.transport.end(this.name + ".queue", !this.isTransportShared); }; return DurableChannel; })(EventChannel); module.exports = DurableChannel; }).call(this);