locker
Version:
Full-featured client for locker lock server with timeouts support
145 lines (112 loc) • 4.62 kB
JavaScript
(function(module) {
var net = require("net"),
util = require("util"),
events = require("events"),
Lock = require("./Lock"),
LockAction = require("./LockAction");
function Locker(port, host) {
var self = this;
self.port = port;
self.host = host;
self.registry = {};
self.sequence = 0;
self.connect = function(callback) {
var data = new Buffer(0),
temp = new Buffer(0);
self.connection = net.createConnection(port, host);
self.connection.on("error", self.reset.bind(self, 1));
self.connection.on("close", self.reset.bind(self, 2));
self.connection.on("timeout", self.reset.bind(self, 3));
self.connection.on("data", function(part) {
var sequence,
action,
result,
lock;
temp = new Buffer(data.length + part.length);
data.copy(temp, 0);
part.copy(temp, data.length);
data = new Buffer(temp);
while (data.length >= 6) {
sequence = data.readUInt32LE(0);
action = data[4];
result = data[5];
lock = self.registry[sequence];
if (lock) {
if (action == LockAction.ACTION_LOCK) {
if (lock.acquire) {
lock.acquire(result ? undefined : new Error("Failed to acquire lock"));
}
} else if (action == LockAction.ACTION_UNLOCK) {
if (lock.release) {
lock.release(result ? undefined : new Error("Failed to release lock"));
}
}
}
data = data.slice(6);
}
});
self.connection.on("connect", callback);
};
self.reset = function(error) {
self.connection = undefined;
Object.keys(self.registry).forEach(function(key) {
self.registry[key].lock.reset();
});
self.registry = {};
self.emit("reset", error);
};
self.createRequest = function(name, sequence, wait, timeout, type) {
var name = new Buffer(name),
request = new Buffer(1 + 4 + 4 + 4 + 1 + name.length);
request[0] = name.length;
request.writeUInt32LE(sequence, 1);
request.writeUInt32LE(wait, 5);
request.writeUInt32LE(timeout, 9);
request[13] = type;
name.copy(request, 14);
return request;
};
self.requireConnection = function(callback) {
if (!self.connection) {
return self.connect(callback);
}
callback();
};
self.requestAction = function(name, sequence, wait, timeout, action) {
self.requireConnection(function() {
self.connection.write(self.createRequest(name, sequence, wait, timeout, action));
});
};
self.acquire = function(name, sequence, wait, timeout, callback) {
self.requestAction(name, sequence, wait, timeout, LockAction.ACTION_LOCK);
self.registry[sequence].acquire = callback;
};
self.release = function(sequence, callback) {
self.requestAction("", sequence, 0, 0, LockAction.ACTION_UNLOCK);
self.registry[sequence].release = callback;
};
self.createLock = function(name) {
var sequence = ++this.sequence,
acquire = this.acquire,
release = this.release,
registry = this.registry,
lock = new Lock(name, sequence, acquire, release);
lock.on("error", function(error) {
self.emit("error", error, lock);
});
registry[sequence] = {
lock: lock
};
return lock;
};
};
util.inherits(Locker, events.EventEmitter);
Locker.prototype.locked = function(name, wait, timeout, callback) {
var self = this,
lock = self.createLock(name);
lock.acquire(wait, timeout, function(error) {
callback(error, lock.release.bind(lock));
});
};
module.exports = Locker;
})(module);