radar_client
Advanced tools
Comparing version 0.14.5 to 0.15.0
@@ -0,1 +1,9 @@ | ||
### 0.15.0 | ||
* Use radar message library | ||
- significant refactor that changes most of the code underlying the public | ||
APIs, which have *not* been changed | ||
- explicitly extracted the message "library" code in the refactor above to a | ||
separate radar_message library | ||
- pin radar_message version (we'll specify versions of package moving forward) | ||
### 0.14.5 | ||
@@ -2,0 +10,0 @@ * Presence resource can set online and include client data (to be broadcasted |
@@ -31,3 +31,3 @@ (function(){function require(e,t){for(var n=[],r=e.split("/"),i,s,o=0;s=r[o++];)".."==s?n.pop():"."!=s&&n.push(s);n=n.join("/"),o=require,s=o.m[t||0],i=s[n+".js"]||s[n+"/index.js"]||s[n];if(s=i.c)i=o.m[t=s][e=i.m];return i.exports||i(i,i.exports={},function(n){return o("."!=n.charAt(0)?n:e+"/../"+n,t)}),i.exports}; | ||
function getClientVersion() { return '0.14.5'; }; | ||
function getClientVersion() { return '0.15.0'; }; | ||
@@ -53,3 +53,5 @@ module.exports = getClientVersion;}, | ||
function(fn) { setTimeout(fn, 1); }, | ||
getClientVersion = require('./client_version.js'); | ||
getClientVersion = require('./client_version.js'), | ||
Request = require('radar_message').Request, | ||
Response = require('radar_message').Response; | ||
@@ -65,3 +67,3 @@ function Client(backend) { | ||
this._restoreRequired = false; | ||
this._queuedMessages = []; | ||
this._queuedRequests = []; | ||
this._isConfigured = false; | ||
@@ -162,200 +164,196 @@ | ||
// Return the chainable scope object for a given message type | ||
Client.prototype.message = function(scope) { | ||
return new Scope('message:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('message', scope, this); | ||
}; | ||
// Access the "presence" chainable operations | ||
Client.prototype.presence = function(scope) { | ||
return new Scope('presence:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('presence', scope, this); | ||
}; | ||
// Access the "status" chainable operations | ||
Client.prototype.status = function(scope) { | ||
return new Scope('status:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('status', scope, this); | ||
}; | ||
Client.prototype.stream = function(scope) { | ||
return new Scope('stream:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('stream', scope, this); | ||
}; | ||
// Access the "control" chainable operations | ||
Client.prototype.control = function(scope) { | ||
return new Scope('control:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('control', scope, this); | ||
}; | ||
// Operations | ||
Client.prototype.nameSync = function(scope, options, callback) { | ||
var message = { op: 'nameSync', to: scope }; | ||
if (typeof options == 'function') { | ||
callback = options; | ||
} else { | ||
message.options = options; | ||
} | ||
return this._write(message, callback); | ||
var request = Request.buildNameSync(scope, options); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.push = function(scope, resource, action, value, callback) { | ||
return this._write({ | ||
op: 'push', | ||
to: scope, | ||
resource: resource, | ||
action: action, | ||
value: value | ||
}, callback); | ||
var request = Request.buildPush(scope, resource, action, value); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.set = function(scope, value, clientData, callback) { | ||
var message = { | ||
op: 'set', | ||
to: scope, | ||
value: value, | ||
key: this._configuration.userId, | ||
type: this._configuration.userType | ||
}; | ||
var request; | ||
if (typeof(clientData) === 'function') { | ||
callback = clientData; | ||
} else { | ||
message.clientData = clientData; | ||
} | ||
callback = _chooseFunction(clientData, callback); | ||
clientData = _nullIfFunction(clientData); | ||
return this._write(message, callback); | ||
request = Request.buildSet(scope, value, | ||
this._configuration.userId, this._configuration.userType, | ||
clientData); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.publish = function(scope, value, callback) { | ||
return this._write({ | ||
op: 'publish', | ||
to: scope, | ||
value: value | ||
}, callback); | ||
var request = Request.buildPublish(scope, value); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.subscribe = function(scope, options, callback) { | ||
var message = { op: 'subscribe', to: scope }; | ||
if (typeof options == 'function') { | ||
callback = options; | ||
} else { | ||
message.options = options; | ||
} | ||
return this._write(message, callback); | ||
callback = _chooseFunction(options, callback); | ||
options = _nullIfFunction(options); | ||
var request = Request.buildSubscribe(scope, options); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.unsubscribe = function(scope, callback) { | ||
return this._write({ op: 'unsubscribe', to: scope }, callback); | ||
var request = Request.buildUnsubscribe(scope); | ||
return this._write(request, callback); | ||
}; | ||
// Sync and get return the actual value of the operation | ||
var init = function(propertyName) { | ||
Client.prototype[propertyName] = function(scope, options, callback) { | ||
var message = { op: propertyName, to: scope }; | ||
// options is an optional argument | ||
if (typeof options == 'function') { | ||
callback = options; | ||
} else { | ||
message.options = options; | ||
// sync returns the actual value of the operation | ||
Client.prototype.sync = function (scope, options, callback) { | ||
var request, onResponse, v1Presence; | ||
callback = _chooseFunction(options, callback); | ||
options = _nullIfFunction(options); | ||
request = Request.buildSync(scope, options); | ||
v1Presence = !options && request.isPresence(); | ||
onResponse = function (message) { | ||
var response = new Response(message); | ||
if (response && response.isFor(request)) { | ||
if (v1Presence) { | ||
response.forceV1Response(); | ||
} | ||
if (callback) { | ||
callback(response.getMessage()); | ||
} | ||
return true; | ||
} | ||
// Sync v1 for presence scopes acts inconsistently. The result should be a | ||
// "get" message, but it is actually a "online" message. | ||
// So force v2 and translate the result to v1 format. | ||
if (propertyName == 'sync' && !message.options && scope.match(/^presence.+/)) { | ||
message.options = { version: 2 }; | ||
this.when('get', function(message) { | ||
var value = {}, userId; | ||
if (!message || !message.to || message.to != scope) { | ||
return false; | ||
} | ||
return false; | ||
}; | ||
for (userId in message.value) { | ||
if (message.value.hasOwnProperty(userId)) { | ||
// Skip when not defined; causes exception in FF for 'Work Offline' | ||
if (!message.value[userId]) { continue; } | ||
value[userId] = message.value[userId].userType; | ||
} | ||
} | ||
message.value = value; | ||
message.op = 'online'; | ||
if (callback) { | ||
callback(message); | ||
} | ||
return true; | ||
}); | ||
} else { | ||
this.when('get', function(message) { | ||
if (!message || !message.to || message.to != scope) { | ||
return false; | ||
} | ||
if (callback) { | ||
callback(message); | ||
} | ||
return true; | ||
}); | ||
this.when('get', onResponse); | ||
// sync does not return ACK (it sends back a data message) | ||
return this._write(request); | ||
}; | ||
// get returns the actual value of the operation | ||
Client.prototype.get = function (scope, options, callback) { | ||
var request; | ||
callback = _chooseFunction(options, callback); | ||
options = _nullIfFunction(options); | ||
request = Request.buildGet(scope, options); | ||
var onResponse = function (message) { | ||
var response = new Response(message); | ||
if (response && response.isFor(request)) { | ||
if (callback) { | ||
callback(response.getMessage()); | ||
} | ||
return true; | ||
} | ||
// sync/get never register or return acks (since they always send back a | ||
// data message) | ||
return this._write(message); | ||
return false; | ||
}; | ||
this.when('get', onResponse); | ||
// get does not return ACK (it sends back a data message) | ||
return this._write(request); | ||
}; | ||
var props = ['get', 'sync']; | ||
for(var i = 0; i < props.length; i++){ | ||
init(props[i]); | ||
} | ||
// Private API | ||
var _chooseFunction = function (options, callback) { | ||
return typeof(options) === 'function' ? options : callback; | ||
}; | ||
var _nullIfFunction = function (options) { | ||
if (typeof(options) === 'function') { | ||
return null; | ||
} | ||
return options; | ||
}; | ||
Client.prototype._addListeners = function () { | ||
// Add authentication data to a message; _write() emits authenticateMessage | ||
// Add authentication data to a request message; _write() emits authenticateMessage | ||
this.on('authenticateMessage', function(message) { | ||
if (this._configuration) { | ||
message.userData = this._configuration.userData; | ||
if (this._configuration.auth) { | ||
message.auth = this._configuration.auth; | ||
message.userId = this._configuration.userId; | ||
message.userType = this._configuration.userType; | ||
message.accountName = this._configuration.accountName; | ||
} | ||
} | ||
this.emit('messageAuthenticated', message); | ||
var request = new Request(message); | ||
request.setAuthData(this._configuration); | ||
this.emit('messageAuthenticated', request.getMessage()); | ||
}); | ||
// Once the message is authenticated, send it to the server | ||
// Once the request is authenticated, send it to the server | ||
this.on('messageAuthenticated', function(message) { | ||
this._sendMessage(message); | ||
var request = new Request(message); | ||
this._sendMessage(request); | ||
}); | ||
}; | ||
Client.prototype._write = function(message, callback) { | ||
var client = this; | ||
Client.prototype._write = function(request, callback) { | ||
var self = this; | ||
if (callback) { | ||
message.ack = this._ackCounter++; | ||
request.setAttr('ack', this._ackCounter++); | ||
// Wait ack | ||
this.when('ack', function(m) { | ||
client.logger().debug('ack', m); | ||
if (!m || !m.value || m.value != message.ack) { | ||
return false; | ||
} | ||
callback(message); | ||
this.when('ack', function(message) { | ||
var response = new Response(message); | ||
self.logger().debug('ack', response); | ||
if (!response.isAckFor(request)) { return false; } | ||
callback(request.getMessage()); | ||
return true; | ||
}); | ||
} | ||
this.emit('authenticateMessage', message); | ||
this.emit('authenticateMessage', request.getMessage()); | ||
return this; | ||
}; | ||
Client.prototype._batch = function(message) { | ||
if (!(message.to && message.value && message.time)) { | ||
Client.prototype._batch = function(response) { | ||
var to = response.getAttr('to'), | ||
value = response.getAttr('value'), | ||
time = response.getAttr('time'); | ||
if (!response.isValid()) { | ||
this.logger().info('response is invalid:', response.getMessage()); | ||
return false; | ||
} | ||
var index = 0, data, time, | ||
length = message.value.length, | ||
newest = message.time, | ||
current = this._channelSyncTimes[message.to] || 0; | ||
var index = 0, data, | ||
length = value.length, | ||
newest = time, | ||
current = this._channelSyncTimes[to] || 0; | ||
for (; index < length; index = index + 2) { | ||
data = JSON.parse(message.value[index]); | ||
time = message.value[index + 1]; | ||
data = JSON.parse(value[index]); | ||
time = value[index + 1]; | ||
if (time > current) { | ||
this.emitNext(message.to, data); | ||
this.emitNext(to, data); | ||
} | ||
@@ -366,21 +364,21 @@ if (time > newest) { | ||
} | ||
this._channelSyncTimes[message.to] = newest; | ||
this._channelSyncTimes[to] = newest; | ||
}; | ||
Client.prototype._createManager = function() { | ||
var client = this, manager = this.manager = StateMachine.create(); | ||
var self = this, manager = this.manager = StateMachine.create(); | ||
manager.on('enterState', function(state) { | ||
client.emit(state); | ||
self.emit(state); | ||
}); | ||
manager.on('event', function(event) { | ||
client.emit(event); | ||
self.emit(event); | ||
}); | ||
manager.on('connect', function(data) { | ||
var socket = client._socket = new client.backend.Socket(client._configuration); | ||
var socket = self._socket = new self.backend.Socket(self._configuration); | ||
socket.once('open', function() { | ||
client.logger().debug("socket open", socket.id); | ||
self.logger().debug("socket open", socket.id); | ||
manager.established(); | ||
@@ -390,5 +388,5 @@ }); | ||
socket.once('close', function(reason, description) { | ||
client.logger().debug('socket closed', socket.id, reason, description); | ||
self.logger().debug('socket closed', socket.id, reason, description); | ||
socket.removeAllListeners('message'); | ||
client._socket = null; | ||
self._socket = null; | ||
@@ -408,4 +406,4 @@ // Patch for polling-xhr continuing to poll after socket close (HTTP:POST | ||
socket.on('message', function(message) { | ||
client._messageReceived(message); | ||
socket.on('message', function (message) { | ||
self._messageReceived(message); | ||
}); | ||
@@ -420,5 +418,5 @@ | ||
manager.on('activate', function() { | ||
client._identitySet(); | ||
client._restore(); | ||
client.emit('ready'); | ||
self._identitySet(); | ||
self._restore(); | ||
self.emit('ready'); | ||
}); | ||
@@ -432,3 +430,3 @@ | ||
manager.on('disconnect', function() { | ||
client._restoreRequired = true; | ||
self._restoreRequired = true; | ||
}); | ||
@@ -439,22 +437,30 @@ }; | ||
// adds to the memorized subscriptions or presences | ||
Client.prototype._memorize = function(message) { | ||
switch(message.op) { | ||
Client.prototype._memorize = function(request) { | ||
var op = request.getAttr('op'), | ||
to = request.getAttr('to'), | ||
value = request.getAttr('value'); | ||
switch(op) { | ||
case 'unsubscribe': | ||
// Remove from queue | ||
if (this._subscriptions[message.to]) { | ||
delete this._subscriptions[message.to]; | ||
if (this._subscriptions[to]) { | ||
delete this._subscriptions[to]; | ||
} | ||
return true; | ||
case 'sync': | ||
case 'subscribe': | ||
if (this._subscriptions[message.to] != 'sync') { | ||
this._subscriptions[message.to] = message.op; | ||
// A catch for when *subscribe* is called after *sync* | ||
if (this._subscriptions[to] != 'sync') { | ||
this._subscriptions[to] = op; | ||
} | ||
return true; | ||
case 'set': | ||
if (message.to.substr(0, 'presence:/'.length) == 'presence:/') { | ||
this._presences[message.to] = message.value; | ||
if (request.isPresence()) { | ||
this._presences[to] = value; | ||
return true; | ||
} | ||
} | ||
return false; | ||
@@ -464,7 +470,6 @@ }; | ||
Client.prototype._restore = function() { | ||
var item, i, to, message, counts = { subscriptions: 0, presences: 0, messages: 0 }; | ||
var item, to, counts = { subscriptions: 0, presences: 0, messages: 0 }; | ||
if (this._restoreRequired) { | ||
this._restoreRequired = false; | ||
for (to in this._subscriptions) { | ||
@@ -485,4 +490,4 @@ if (this._subscriptions.hasOwnProperty(to)) { | ||
while (this._queuedMessages.length) { | ||
this._write(this._queuedMessages.shift()); | ||
while (this._queuedRequests.length) { | ||
this._write(this._queuedRequests.shift()); | ||
counts.messages += 1; | ||
@@ -495,12 +500,14 @@ } | ||
Client.prototype._sendMessage = function(message) { | ||
var memorized = this._memorize(message); | ||
this.emit('message:out', message); | ||
Client.prototype._sendMessage = function(request) { | ||
var memorized = this._memorize(request), | ||
ack = request.getAttr('ack'); | ||
this.emit('message:out', request.getMessage()); | ||
if (this._socket && this.manager.is('activated')) { | ||
this._socket.sendPacket('message', JSON.stringify(message)); | ||
this._socket.sendPacket('message', request.payload()); | ||
} else if (this._isConfigured) { | ||
this._restoreRequired = true; | ||
if (!memorized || message.ack) { | ||
this._queuedMessages.push(message); | ||
if (!memorized || ack) { | ||
this._queuedRequests.push(request); | ||
} | ||
@@ -512,15 +519,21 @@ this.manager.connectWhenAble(); | ||
Client.prototype._messageReceived = function (msg) { | ||
var message = JSON.parse(msg); | ||
this.emit('message:in', message); | ||
switch (message.op) { | ||
var response = new Response(JSON.parse(msg)), | ||
op = response.getAttr('op'), | ||
to = response.getAttr('to'); | ||
this.emit('message:in', response.getMessage()); | ||
switch (op) { | ||
case 'err': | ||
case 'ack': | ||
case 'get': | ||
this.emitNext(message.op, message); | ||
this.emitNext(op, response.getMessage()); | ||
break; | ||
case 'sync': | ||
this._batch(message); | ||
this._batch(response); | ||
break; | ||
default: | ||
this.emitNext(message.to, message); | ||
this.emitNext(to, response.getMessage()); | ||
} | ||
@@ -530,4 +543,4 @@ }; | ||
Client.prototype.emitNext = function() { | ||
var args = Array.prototype.slice.call(arguments), client = this; | ||
immediate(function(){ client.emit.apply(client, args); }); | ||
var args = Array.prototype.slice.call(arguments), self = this; | ||
immediate(function(){ self.emit.apply(self, args); }); | ||
}; | ||
@@ -544,4 +557,7 @@ | ||
var options = { association: association, clientVersion: clientVersion }; | ||
var self = this; | ||
this.control('clientName').nameSync(options); | ||
this.control('clientName').nameSync(options, function (message) { | ||
self.logger('nameSync message: ' + JSON.stringify(message)); | ||
}); | ||
}; | ||
@@ -566,5 +582,5 @@ | ||
}, | ||
"lib/scope.js": function(module, exports, require){function Scope(prefix, client) { | ||
this.prefix = prefix; | ||
"lib/scope.js": function(module, exports, require){function Scope(typeName, scope, client) { | ||
this.client = client; | ||
this.prefix = this._buildScopePrefix(typeName, scope, client.configuration('accountName')); | ||
} | ||
@@ -575,3 +591,3 @@ | ||
var init = function(name) { | ||
var init = function (name) { | ||
Scope.prototype[name] = function () { | ||
@@ -585,6 +601,10 @@ var args = Array.prototype.slice.apply(arguments); | ||
for(var i = 0; i < props.length; i++){ | ||
for (var i = 0; i < props.length; i++) { | ||
init(props[i]); | ||
} | ||
Scope.prototype._buildScopePrefix = function (typeName, scope, accountName) { | ||
return typeName + ':/' + accountName + '/' + scope; | ||
}; | ||
module.exports = Scope; | ||
@@ -591,0 +611,0 @@ }, |
// Auto-generated file, overwritten by scripts/add_package_version.js | ||
function getClientVersion() { return '0.14.5'; }; | ||
function getClientVersion() { return '0.15.0'; }; | ||
module.exports = getClientVersion; |
@@ -8,3 +8,5 @@ /* globals setImmediate */ | ||
function(fn) { setTimeout(fn, 1); }, | ||
getClientVersion = require('./client_version.js'); | ||
getClientVersion = require('./client_version.js'), | ||
Request = require('radar_message').Request, | ||
Response = require('radar_message').Response; | ||
@@ -20,3 +22,3 @@ function Client(backend) { | ||
this._restoreRequired = false; | ||
this._queuedMessages = []; | ||
this._queuedRequests = []; | ||
this._isConfigured = false; | ||
@@ -117,200 +119,196 @@ | ||
// Return the chainable scope object for a given message type | ||
Client.prototype.message = function(scope) { | ||
return new Scope('message:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('message', scope, this); | ||
}; | ||
// Access the "presence" chainable operations | ||
Client.prototype.presence = function(scope) { | ||
return new Scope('presence:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('presence', scope, this); | ||
}; | ||
// Access the "status" chainable operations | ||
Client.prototype.status = function(scope) { | ||
return new Scope('status:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('status', scope, this); | ||
}; | ||
Client.prototype.stream = function(scope) { | ||
return new Scope('stream:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('stream', scope, this); | ||
}; | ||
// Access the "control" chainable operations | ||
Client.prototype.control = function(scope) { | ||
return new Scope('control:/'+this._configuration.accountName+'/'+scope, this); | ||
return new Scope('control', scope, this); | ||
}; | ||
// Operations | ||
Client.prototype.nameSync = function(scope, options, callback) { | ||
var message = { op: 'nameSync', to: scope }; | ||
if (typeof options == 'function') { | ||
callback = options; | ||
} else { | ||
message.options = options; | ||
} | ||
return this._write(message, callback); | ||
var request = Request.buildNameSync(scope, options); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.push = function(scope, resource, action, value, callback) { | ||
return this._write({ | ||
op: 'push', | ||
to: scope, | ||
resource: resource, | ||
action: action, | ||
value: value | ||
}, callback); | ||
var request = Request.buildPush(scope, resource, action, value); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.set = function(scope, value, clientData, callback) { | ||
var message = { | ||
op: 'set', | ||
to: scope, | ||
value: value, | ||
key: this._configuration.userId, | ||
type: this._configuration.userType | ||
}; | ||
var request; | ||
if (typeof(clientData) === 'function') { | ||
callback = clientData; | ||
} else { | ||
message.clientData = clientData; | ||
} | ||
callback = _chooseFunction(clientData, callback); | ||
clientData = _nullIfFunction(clientData); | ||
return this._write(message, callback); | ||
request = Request.buildSet(scope, value, | ||
this._configuration.userId, this._configuration.userType, | ||
clientData); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.publish = function(scope, value, callback) { | ||
return this._write({ | ||
op: 'publish', | ||
to: scope, | ||
value: value | ||
}, callback); | ||
var request = Request.buildPublish(scope, value); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.subscribe = function(scope, options, callback) { | ||
var message = { op: 'subscribe', to: scope }; | ||
if (typeof options == 'function') { | ||
callback = options; | ||
} else { | ||
message.options = options; | ||
} | ||
return this._write(message, callback); | ||
callback = _chooseFunction(options, callback); | ||
options = _nullIfFunction(options); | ||
var request = Request.buildSubscribe(scope, options); | ||
return this._write(request, callback); | ||
}; | ||
Client.prototype.unsubscribe = function(scope, callback) { | ||
return this._write({ op: 'unsubscribe', to: scope }, callback); | ||
var request = Request.buildUnsubscribe(scope); | ||
return this._write(request, callback); | ||
}; | ||
// Sync and get return the actual value of the operation | ||
var init = function(propertyName) { | ||
Client.prototype[propertyName] = function(scope, options, callback) { | ||
var message = { op: propertyName, to: scope }; | ||
// options is an optional argument | ||
if (typeof options == 'function') { | ||
callback = options; | ||
} else { | ||
message.options = options; | ||
// sync returns the actual value of the operation | ||
Client.prototype.sync = function (scope, options, callback) { | ||
var request, onResponse, v1Presence; | ||
callback = _chooseFunction(options, callback); | ||
options = _nullIfFunction(options); | ||
request = Request.buildSync(scope, options); | ||
v1Presence = !options && request.isPresence(); | ||
onResponse = function (message) { | ||
var response = new Response(message); | ||
if (response && response.isFor(request)) { | ||
if (v1Presence) { | ||
response.forceV1Response(); | ||
} | ||
if (callback) { | ||
callback(response.getMessage()); | ||
} | ||
return true; | ||
} | ||
// Sync v1 for presence scopes acts inconsistently. The result should be a | ||
// "get" message, but it is actually a "online" message. | ||
// So force v2 and translate the result to v1 format. | ||
if (propertyName == 'sync' && !message.options && scope.match(/^presence.+/)) { | ||
message.options = { version: 2 }; | ||
this.when('get', function(message) { | ||
var value = {}, userId; | ||
if (!message || !message.to || message.to != scope) { | ||
return false; | ||
} | ||
return false; | ||
}; | ||
for (userId in message.value) { | ||
if (message.value.hasOwnProperty(userId)) { | ||
// Skip when not defined; causes exception in FF for 'Work Offline' | ||
if (!message.value[userId]) { continue; } | ||
value[userId] = message.value[userId].userType; | ||
} | ||
} | ||
message.value = value; | ||
message.op = 'online'; | ||
if (callback) { | ||
callback(message); | ||
} | ||
return true; | ||
}); | ||
} else { | ||
this.when('get', function(message) { | ||
if (!message || !message.to || message.to != scope) { | ||
return false; | ||
} | ||
if (callback) { | ||
callback(message); | ||
} | ||
return true; | ||
}); | ||
this.when('get', onResponse); | ||
// sync does not return ACK (it sends back a data message) | ||
return this._write(request); | ||
}; | ||
// get returns the actual value of the operation | ||
Client.prototype.get = function (scope, options, callback) { | ||
var request; | ||
callback = _chooseFunction(options, callback); | ||
options = _nullIfFunction(options); | ||
request = Request.buildGet(scope, options); | ||
var onResponse = function (message) { | ||
var response = new Response(message); | ||
if (response && response.isFor(request)) { | ||
if (callback) { | ||
callback(response.getMessage()); | ||
} | ||
return true; | ||
} | ||
// sync/get never register or return acks (since they always send back a | ||
// data message) | ||
return this._write(message); | ||
return false; | ||
}; | ||
this.when('get', onResponse); | ||
// get does not return ACK (it sends back a data message) | ||
return this._write(request); | ||
}; | ||
var props = ['get', 'sync']; | ||
for(var i = 0; i < props.length; i++){ | ||
init(props[i]); | ||
} | ||
// Private API | ||
var _chooseFunction = function (options, callback) { | ||
return typeof(options) === 'function' ? options : callback; | ||
}; | ||
var _nullIfFunction = function (options) { | ||
if (typeof(options) === 'function') { | ||
return null; | ||
} | ||
return options; | ||
}; | ||
Client.prototype._addListeners = function () { | ||
// Add authentication data to a message; _write() emits authenticateMessage | ||
// Add authentication data to a request message; _write() emits authenticateMessage | ||
this.on('authenticateMessage', function(message) { | ||
if (this._configuration) { | ||
message.userData = this._configuration.userData; | ||
if (this._configuration.auth) { | ||
message.auth = this._configuration.auth; | ||
message.userId = this._configuration.userId; | ||
message.userType = this._configuration.userType; | ||
message.accountName = this._configuration.accountName; | ||
} | ||
} | ||
this.emit('messageAuthenticated', message); | ||
var request = new Request(message); | ||
request.setAuthData(this._configuration); | ||
this.emit('messageAuthenticated', request.getMessage()); | ||
}); | ||
// Once the message is authenticated, send it to the server | ||
// Once the request is authenticated, send it to the server | ||
this.on('messageAuthenticated', function(message) { | ||
this._sendMessage(message); | ||
var request = new Request(message); | ||
this._sendMessage(request); | ||
}); | ||
}; | ||
Client.prototype._write = function(message, callback) { | ||
var client = this; | ||
Client.prototype._write = function(request, callback) { | ||
var self = this; | ||
if (callback) { | ||
message.ack = this._ackCounter++; | ||
request.setAttr('ack', this._ackCounter++); | ||
// Wait ack | ||
this.when('ack', function(m) { | ||
client.logger().debug('ack', m); | ||
if (!m || !m.value || m.value != message.ack) { | ||
return false; | ||
} | ||
callback(message); | ||
this.when('ack', function(message) { | ||
var response = new Response(message); | ||
self.logger().debug('ack', response); | ||
if (!response.isAckFor(request)) { return false; } | ||
callback(request.getMessage()); | ||
return true; | ||
}); | ||
} | ||
this.emit('authenticateMessage', message); | ||
this.emit('authenticateMessage', request.getMessage()); | ||
return this; | ||
}; | ||
Client.prototype._batch = function(message) { | ||
if (!(message.to && message.value && message.time)) { | ||
Client.prototype._batch = function(response) { | ||
var to = response.getAttr('to'), | ||
value = response.getAttr('value'), | ||
time = response.getAttr('time'); | ||
if (!response.isValid()) { | ||
this.logger().info('response is invalid:', response.getMessage()); | ||
return false; | ||
} | ||
var index = 0, data, time, | ||
length = message.value.length, | ||
newest = message.time, | ||
current = this._channelSyncTimes[message.to] || 0; | ||
var index = 0, data, | ||
length = value.length, | ||
newest = time, | ||
current = this._channelSyncTimes[to] || 0; | ||
for (; index < length; index = index + 2) { | ||
data = JSON.parse(message.value[index]); | ||
time = message.value[index + 1]; | ||
data = JSON.parse(value[index]); | ||
time = value[index + 1]; | ||
if (time > current) { | ||
this.emitNext(message.to, data); | ||
this.emitNext(to, data); | ||
} | ||
@@ -321,21 +319,21 @@ if (time > newest) { | ||
} | ||
this._channelSyncTimes[message.to] = newest; | ||
this._channelSyncTimes[to] = newest; | ||
}; | ||
Client.prototype._createManager = function() { | ||
var client = this, manager = this.manager = StateMachine.create(); | ||
var self = this, manager = this.manager = StateMachine.create(); | ||
manager.on('enterState', function(state) { | ||
client.emit(state); | ||
self.emit(state); | ||
}); | ||
manager.on('event', function(event) { | ||
client.emit(event); | ||
self.emit(event); | ||
}); | ||
manager.on('connect', function(data) { | ||
var socket = client._socket = new client.backend.Socket(client._configuration); | ||
var socket = self._socket = new self.backend.Socket(self._configuration); | ||
socket.once('open', function() { | ||
client.logger().debug("socket open", socket.id); | ||
self.logger().debug("socket open", socket.id); | ||
manager.established(); | ||
@@ -345,5 +343,5 @@ }); | ||
socket.once('close', function(reason, description) { | ||
client.logger().debug('socket closed', socket.id, reason, description); | ||
self.logger().debug('socket closed', socket.id, reason, description); | ||
socket.removeAllListeners('message'); | ||
client._socket = null; | ||
self._socket = null; | ||
@@ -363,4 +361,4 @@ // Patch for polling-xhr continuing to poll after socket close (HTTP:POST | ||
socket.on('message', function(message) { | ||
client._messageReceived(message); | ||
socket.on('message', function (message) { | ||
self._messageReceived(message); | ||
}); | ||
@@ -375,5 +373,5 @@ | ||
manager.on('activate', function() { | ||
client._identitySet(); | ||
client._restore(); | ||
client.emit('ready'); | ||
self._identitySet(); | ||
self._restore(); | ||
self.emit('ready'); | ||
}); | ||
@@ -387,3 +385,3 @@ | ||
manager.on('disconnect', function() { | ||
client._restoreRequired = true; | ||
self._restoreRequired = true; | ||
}); | ||
@@ -394,22 +392,30 @@ }; | ||
// adds to the memorized subscriptions or presences | ||
Client.prototype._memorize = function(message) { | ||
switch(message.op) { | ||
Client.prototype._memorize = function(request) { | ||
var op = request.getAttr('op'), | ||
to = request.getAttr('to'), | ||
value = request.getAttr('value'); | ||
switch(op) { | ||
case 'unsubscribe': | ||
// Remove from queue | ||
if (this._subscriptions[message.to]) { | ||
delete this._subscriptions[message.to]; | ||
if (this._subscriptions[to]) { | ||
delete this._subscriptions[to]; | ||
} | ||
return true; | ||
case 'sync': | ||
case 'subscribe': | ||
if (this._subscriptions[message.to] != 'sync') { | ||
this._subscriptions[message.to] = message.op; | ||
// A catch for when *subscribe* is called after *sync* | ||
if (this._subscriptions[to] != 'sync') { | ||
this._subscriptions[to] = op; | ||
} | ||
return true; | ||
case 'set': | ||
if (message.to.substr(0, 'presence:/'.length) == 'presence:/') { | ||
this._presences[message.to] = message.value; | ||
if (request.isPresence()) { | ||
this._presences[to] = value; | ||
return true; | ||
} | ||
} | ||
return false; | ||
@@ -419,7 +425,6 @@ }; | ||
Client.prototype._restore = function() { | ||
var item, i, to, message, counts = { subscriptions: 0, presences: 0, messages: 0 }; | ||
var item, to, counts = { subscriptions: 0, presences: 0, messages: 0 }; | ||
if (this._restoreRequired) { | ||
this._restoreRequired = false; | ||
for (to in this._subscriptions) { | ||
@@ -440,4 +445,4 @@ if (this._subscriptions.hasOwnProperty(to)) { | ||
while (this._queuedMessages.length) { | ||
this._write(this._queuedMessages.shift()); | ||
while (this._queuedRequests.length) { | ||
this._write(this._queuedRequests.shift()); | ||
counts.messages += 1; | ||
@@ -450,12 +455,14 @@ } | ||
Client.prototype._sendMessage = function(message) { | ||
var memorized = this._memorize(message); | ||
this.emit('message:out', message); | ||
Client.prototype._sendMessage = function(request) { | ||
var memorized = this._memorize(request), | ||
ack = request.getAttr('ack'); | ||
this.emit('message:out', request.getMessage()); | ||
if (this._socket && this.manager.is('activated')) { | ||
this._socket.sendPacket('message', JSON.stringify(message)); | ||
this._socket.sendPacket('message', request.payload()); | ||
} else if (this._isConfigured) { | ||
this._restoreRequired = true; | ||
if (!memorized || message.ack) { | ||
this._queuedMessages.push(message); | ||
if (!memorized || ack) { | ||
this._queuedRequests.push(request); | ||
} | ||
@@ -467,15 +474,21 @@ this.manager.connectWhenAble(); | ||
Client.prototype._messageReceived = function (msg) { | ||
var message = JSON.parse(msg); | ||
this.emit('message:in', message); | ||
switch (message.op) { | ||
var response = new Response(JSON.parse(msg)), | ||
op = response.getAttr('op'), | ||
to = response.getAttr('to'); | ||
this.emit('message:in', response.getMessage()); | ||
switch (op) { | ||
case 'err': | ||
case 'ack': | ||
case 'get': | ||
this.emitNext(message.op, message); | ||
this.emitNext(op, response.getMessage()); | ||
break; | ||
case 'sync': | ||
this._batch(message); | ||
this._batch(response); | ||
break; | ||
default: | ||
this.emitNext(message.to, message); | ||
this.emitNext(to, response.getMessage()); | ||
} | ||
@@ -485,4 +498,4 @@ }; | ||
Client.prototype.emitNext = function() { | ||
var args = Array.prototype.slice.call(arguments), client = this; | ||
immediate(function(){ client.emit.apply(client, args); }); | ||
var args = Array.prototype.slice.call(arguments), self = this; | ||
immediate(function(){ self.emit.apply(self, args); }); | ||
}; | ||
@@ -499,4 +512,7 @@ | ||
var options = { association: association, clientVersion: clientVersion }; | ||
var self = this; | ||
this.control('clientName').nameSync(options); | ||
this.control('clientName').nameSync(options, function (message) { | ||
self.logger('nameSync message: ' + JSON.stringify(message)); | ||
}); | ||
}; | ||
@@ -503,0 +519,0 @@ |
@@ -1,4 +0,4 @@ | ||
function Scope(prefix, client) { | ||
this.prefix = prefix; | ||
function Scope(typeName, scope, client) { | ||
this.client = client; | ||
this.prefix = this._buildScopePrefix(typeName, scope, client.configuration('accountName')); | ||
} | ||
@@ -9,3 +9,3 @@ | ||
var init = function(name) { | ||
var init = function (name) { | ||
Scope.prototype[name] = function () { | ||
@@ -19,6 +19,10 @@ var args = Array.prototype.slice.apply(arguments); | ||
for(var i = 0; i < props.length; i++){ | ||
for (var i = 0; i < props.length; i++) { | ||
init(props[i]); | ||
} | ||
Scope.prototype._buildScopePrefix = function (typeName, scope, accountName) { | ||
return typeName + ':/' + accountName + '/' + scope; | ||
}; | ||
module.exports = Scope; |
{ | ||
"name": "radar_client", | ||
"description": "Realtime apps with a high level API based on engine.io", | ||
"version": "0.14.5", | ||
"version": "0.15.0", | ||
"author": "Mikito Takada <mikito.takada@gmail.com>", | ||
@@ -36,3 +36,4 @@ "contributors": [ | ||
"engine.io-client": "1.4.2", | ||
"sfsm": "0.0.4" | ||
"sfsm": "0.0.4", | ||
"radar_message": "1.0.1" | ||
}, | ||
@@ -39,0 +40,0 @@ "devDependencies": { |
var assert = require('assert'), | ||
RadarClient = require('../lib/radar_client.js'), | ||
MockEngine = require('./lib/engine.js'), | ||
Response = require('radar_message').Response, | ||
client; | ||
@@ -75,4 +76,4 @@ | ||
assert.equal(MockEngine.current._written.length, 1); | ||
assert.equal(client._queuedMessages.length, 1); | ||
assert.deepEqual(client._queuedMessages[0], { | ||
assert.equal(client._queuedRequests.length, 1); | ||
assert.deepEqual(client._queuedRequests[0].message, { | ||
op: 'set', | ||
@@ -83,4 +84,3 @@ to: 'status:/test/tickets/21', | ||
type: 2, | ||
userData: undefined, | ||
clientData: undefined | ||
userData: undefined | ||
}); | ||
@@ -91,3 +91,3 @@ }); | ||
assert.ok(connected); | ||
assert.equal(client._queuedMessages.length, 0); | ||
assert.equal(client._queuedRequests.length, 0); | ||
assert.ok( | ||
@@ -304,3 +304,3 @@ MockEngine.current._written.some(function(message) { | ||
'if a authentication token is set, it gets sent on each operation': function(done) { | ||
client.configure({ userId: 123, accountName: 'dev', auth: 'AUTH'}); | ||
client.configure({ userId: 123, accountName: 'dev', auth: 'AUTH', userType: 2 }); | ||
client.message('user/123').publish('hello world'); | ||
@@ -323,7 +323,9 @@ | ||
'synchronization batch filters out duplicate messages to the same channel by time': function(done) { | ||
var received = []; | ||
var received = [], | ||
msg1, msg2, response1, response2; | ||
client.on('foo', function(msg) { | ||
received.push(msg); | ||
}); | ||
client._batch({ | ||
msg1 = { | ||
op: 'subscribe', | ||
to: 'foo', | ||
@@ -339,4 +341,8 @@ value: [ | ||
time: 1 | ||
}); | ||
client._batch({ | ||
}; | ||
response1 = new Response(msg1); | ||
client._batch(response1); | ||
msg2 = { | ||
op: 'subscribe', | ||
to: 'foo', | ||
@@ -352,3 +358,6 @@ value: [ | ||
time: 2 | ||
}); | ||
}; | ||
response2 = new Response(msg2); | ||
client._batch(response2); | ||
setTimeout(function() { | ||
@@ -355,0 +364,0 @@ assert.equal(4, received.length); |
var assert = require('assert'), | ||
RadarClient = require('../lib/radar_client.js'), | ||
MockEngine = require('./lib/engine.js'), | ||
Request = require('radar_message').Request, | ||
Response = require('radar_message').Response, | ||
HOUR = 1000 * 60 * 60, | ||
@@ -127,5 +129,5 @@ client; | ||
client._write = function(hash, fn) { | ||
client._write = function(request, fn) { | ||
called = true; | ||
assert.deepEqual(hash, { | ||
assert.deepEqual(request.getMessage(), { | ||
op: 'set', | ||
@@ -151,3 +153,3 @@ to: 'status:/test/account/1', | ||
assert.ok(!client.manager.is('activated')); | ||
assert.equal(client._queuedMessages.length, 0); | ||
assert.equal(client._queuedRequests.length, 0); | ||
assert.deepEqual(client._presences, { 'presence:/test/account/1': 'online' }); | ||
@@ -162,3 +164,3 @@ }, | ||
assert.ok(!client.manager.is('activated')); | ||
assert.equal(client._queuedMessages.length, 1); | ||
assert.equal(client._queuedRequests.length, 1); | ||
assert.deepEqual(client._presences, { 'presence:/test/account/1': 'online' }); | ||
@@ -172,7 +174,7 @@ } | ||
client._write = function(hash, fn) { | ||
client._write = function(request, fn) { | ||
called = true; | ||
assert.deepEqual(hash, { | ||
assert.deepEqual(request.getMessage(), { | ||
op: 'publish', | ||
to: 'status:/test/account/1', | ||
to: 'message:/test/account/1', | ||
value: 'whatever' | ||
@@ -184,3 +186,3 @@ }); | ||
client.configure({ accountName: 'test', userId: 123, userType: 0 }); | ||
client.publish('status:/test/account/1', 'whatever', callback); | ||
client.publish('message:/test/account/1', 'whatever', callback); | ||
assert.ok(called); | ||
@@ -194,7 +196,7 @@ } | ||
client._write = function(hash, fn) { | ||
client._write = function(request, fn) { | ||
called = true; | ||
assert.deepEqual(hash, { | ||
assert.deepEqual(request.getMessage(), { | ||
op: 'subscribe', | ||
to: 'status:/test/account/1', | ||
to: 'status:/test/account/1' | ||
}); | ||
@@ -215,3 +217,3 @@ assert.equal(fn, callback); | ||
assert.ok(!client.manager.is('activated')); | ||
assert.equal(client._queuedMessages.length, 0); | ||
assert.equal(client._queuedRequests.length, 0); | ||
assert.deepEqual(client._subscriptions, { 'status:/test/account/1': 'subscribe' }); | ||
@@ -226,3 +228,3 @@ }, | ||
assert.ok(!client.manager.is('activated')); | ||
assert.equal(client._queuedMessages.length, 1); | ||
assert.equal(client._queuedRequests.length, 1); | ||
assert.deepEqual(client._subscriptions, { 'status:/test/account/1': 'subscribe' }); | ||
@@ -237,3 +239,3 @@ }, | ||
assert.ok(!client.manager.is('activated')); | ||
assert.equal(client._queuedMessages.length, 0); | ||
assert.equal(client._queuedRequests.length, 0); | ||
assert.deepEqual(client._subscriptions, { 'presence:/test/account/1': 'sync' }); | ||
@@ -247,5 +249,5 @@ } | ||
client._write = function(hash, fn) { | ||
client._write = function(request, fn) { | ||
called = true; | ||
assert.deepEqual(hash, { | ||
assert.deepEqual(request.getMessage(), { | ||
op: 'unsubscribe', | ||
@@ -268,3 +270,3 @@ to: 'status:/test/account/1', | ||
assert.ok(!client.manager.is('activated')); | ||
assert.equal(client._queuedMessages.length, 0); | ||
assert.equal(client._queuedRequests.length, 0); | ||
assert.deepEqual(client._subscriptions, {}); | ||
@@ -279,3 +281,3 @@ }, | ||
assert.ok(!client.manager.is('activated')); | ||
assert.equal(client._queuedMessages.length, 1); | ||
assert.equal(client._queuedRequests.length, 1); | ||
assert.deepEqual(client._subscriptions, {}); | ||
@@ -289,8 +291,7 @@ } | ||
client._write = function(hash) { | ||
client._write = function(request) { | ||
called = true; | ||
assert.deepEqual(hash, { | ||
assert.deepEqual(request.getMessage(), { | ||
op: 'get', | ||
to: 'status:/test/account/1', | ||
options: undefined | ||
to: 'status:/test/account/1' | ||
}); | ||
@@ -319,3 +320,3 @@ }; | ||
scope = 'status:/test/account/1', | ||
message = { to: scope }, | ||
message = { op: 'get', to: scope }, | ||
callback = function(msg) { | ||
@@ -339,3 +340,3 @@ passed = true; | ||
passed = true, | ||
message = { to: 'status:/test/account/2' }, | ||
message = { op: 'get', to: 'status:/test/account/2' }, | ||
callback = function(msg) { | ||
@@ -360,8 +361,7 @@ passed = false; | ||
client._write = function(hash) { | ||
client._write = function(request) { | ||
called = true; | ||
assert.deepEqual(hash, { | ||
assert.deepEqual(request.getMessage(), { | ||
op: 'sync', | ||
to: 'status:/test/account/1', | ||
options: undefined | ||
to: 'status:/test/account/1' | ||
}); | ||
@@ -391,3 +391,3 @@ }; | ||
scope = 'presence:/test/account/1', | ||
message = { to: scope }, | ||
message = { op: 'sync', to: scope }, | ||
callback = function(msg) { | ||
@@ -411,3 +411,4 @@ passed = true; | ||
passed = true, | ||
message = { to: 'presence:/test/account/2' }, | ||
message = { op: 'sync', to: 'presence:/test/account/2' }, | ||
response = new Response(message), | ||
callback = function(msg) { | ||
@@ -419,3 +420,3 @@ passed = false; | ||
called = true; | ||
fn(message); | ||
fn(response); | ||
}; | ||
@@ -448,3 +449,3 @@ | ||
client.emit('get', { | ||
var message = { | ||
op: 'get', to: scope, | ||
@@ -455,3 +456,5 @@ value: { | ||
} | ||
}); | ||
}; | ||
client.emit('get', message); | ||
} | ||
@@ -461,14 +464,18 @@ } | ||
'internal methods': { | ||
'_memorize' : { | ||
'memorizing a sync/subscribe should work': function(done) { | ||
var request; | ||
assert.equal(0, Object.keys(client._subscriptions).length); | ||
client._memorize({ op: 'subscribe', to: 'foo'}); | ||
request = Request.buildSubscribe('presence:/test/ticket/1'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
client._memorize({ op: 'sync', to: 'bar'}); | ||
request = Request.buildSync('status:/test/ticket/1'); | ||
client._memorize(request); | ||
assert.equal(2, Object.keys(client._subscriptions).length); | ||
client._memorize({ op: 'get', to: 'bar' }); | ||
request = Request.buildGet('status:/test/ticket/1'); | ||
client._memorize(request); | ||
// Should be a no-op | ||
@@ -481,11 +488,15 @@ assert.equal(2, Object.keys(client._subscriptions).length); | ||
'memorizing a set(online) and unmemorizing a set(offline) should work': function(done) { | ||
var request; | ||
assert.equal(0, Object.keys(client._presences).length); | ||
client._memorize({ op: 'set', to: 'presence:/foo/bar', value: 'online' }); | ||
request = Request.buildSet('presence:/foo/bar', 'online'); | ||
client._memorize(request); | ||
assert.equal('online', client._presences['presence:/foo/bar']); | ||
assert.equal(1, Object.keys(client._presences).length); | ||
// Duplicate should be ignored | ||
client._memorize({ op: 'set', to: 'presence:/foo/bar', value: 'online' }); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._presences).length); | ||
client._memorize({ op: 'set', to: 'presence:/foo/bar', value: 'offline' }); | ||
request = Request.buildSet('presence:/foo/bar', 'offline'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._presences).length); | ||
@@ -498,9 +509,14 @@ assert.equal('offline', client._presences['presence:/foo/bar']); | ||
// Set up | ||
client._memorize({ op: 'subscribe', to: 'foo'}); | ||
client._memorize({ op: 'sync', to: 'bar'}); | ||
var request = Request.buildSubscribe('status:/test/ticket/1'); | ||
client._memorize(request); | ||
request = Request.buildSync('status:/test/ticket/2'); | ||
client._memorize(request); | ||
assert.equal(2, Object.keys(client._subscriptions).length); | ||
// Unsubscribe | ||
client._memorize({ op: 'unsubscribe', to: 'foo'}); | ||
request = Request.buildUnsubscribe('status:/test/ticket/1'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
client._memorize({ op: 'unsubscribe', to: 'bar'}); | ||
request = Request.buildUnsubscribe('status:/test/ticket/2'); | ||
client._memorize(request); | ||
assert.equal(0, Object.keys(client._subscriptions).length); | ||
@@ -512,5 +528,6 @@ done(); | ||
// Simple duplicates | ||
client._memorize({ op: 'subscribe', to: 'foo'}); | ||
var request = Request.buildSubscribe('status:/test/ticket/1'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
client._memorize({ op: 'subscribe', to: 'foo'}); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
@@ -521,5 +538,6 @@ | ||
// Simple duplicates | ||
client._memorize({ op: 'sync', to: 'abc'}); | ||
request = Request.buildSync('status:/test/ticket/2'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
client._memorize({ op: 'sync', to: 'abc'}); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
@@ -529,17 +547,21 @@ | ||
// Sync after subscribe | ||
client._memorize({ op: 'sync', to: 'bar'}); | ||
request = Request.buildSubscribe('status:/test/ticket/3'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
client._memorize({ op: 'sync', to: 'bar'}); | ||
request = Request.buildSync('status:/test/ticket/3'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
assert.equal('sync', client._subscriptions.bar); | ||
assert.equal('sync', client._subscriptions['status:/test/ticket/3']); | ||
client._subscriptions = {}; | ||
// Subscribe after sync | ||
client._memorize({ op: 'sync', to: 'baz'}); | ||
request = Request.buildSync('status:/test/ticket/4'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
assert.equal('sync', client._subscriptions.baz); | ||
assert.equal('sync', client._subscriptions['status:/test/ticket/4']); | ||
// When we sync and subscribe, it means just sync | ||
client._memorize({ op: 'subscribe', to: 'baz'}); | ||
request = Request.buildSubscribe('status:/test/ticket/4'); | ||
client._memorize(request); | ||
assert.equal(1, Object.keys(client._subscriptions).length); | ||
assert.equal('sync', client._subscriptions.baz); | ||
assert.equal('sync', client._subscriptions['status:/test/ticket/4']); | ||
@@ -549,7 +571,10 @@ done(); | ||
}, | ||
'_restore' : { | ||
'restore presences' : function(done){ | ||
MockEngine.current._written = []; | ||
client._memorize({ op: 'set', to: 'presence:/foo/bar', value: 'online' }); | ||
client._memorize({ op: 'set', to: 'presence:/foo/bar2', value: 'offline' }); | ||
var request = Request.buildSet('presence:/foo/bar', 'online'); | ||
client._memorize(request); | ||
request = Request.buildSet('presence:/foo/bar2', 'offline'); | ||
client._memorize(request); | ||
client._restoreRequired = true; | ||
@@ -572,6 +597,9 @@ client.configure({ accountName: 'foo', userId: 123, userType: 2 }); | ||
}, | ||
'restore subscriptions' : function(done){ | ||
MockEngine.current._written = []; | ||
client._memorize({ op: 'subscribe', to: 'status:/foo/bar' }); | ||
client._memorize({ op: 'subscribe', to: 'message:/foo/bar2' }); | ||
var request = Request.buildSubscribe('status:/foo/bar'); | ||
client._memorize(request); | ||
request = Request.buildSubscribe('message:/foo/bar2'); | ||
client._memorize(request); | ||
client._restoreRequired = true; | ||
@@ -596,3 +624,4 @@ client.configure({ accountName: 'foo', userId: 123, userType: 2 }); | ||
var called = false, | ||
message = { op: 'something', to: 'wherever:/account/scope/1' }; | ||
message = { op: 'subscribe', to: 'status:/account/scope/1'}, | ||
request = Request.buildSubscribe(message.to); | ||
@@ -605,3 +634,4 @@ client.emit = function(name, data) { | ||
client._write(message); | ||
//client._write(request.getMessage()); | ||
client._write(request); | ||
assert.ok(called); | ||
@@ -613,7 +643,7 @@ }, | ||
passed = false, | ||
message = { op: 'something', to: 'wherever:/account/scope/1' }, | ||
request = Request.buildSubscribe('status:/account/scope/1'), | ||
ackMessage = { value: -2 }, | ||
callback = function(msg) { | ||
passed = true; | ||
assert.deepEqual(msg, message); | ||
assert.deepEqual(msg, request.getMessage()); | ||
}; | ||
@@ -624,7 +654,8 @@ | ||
assert.equal(name, 'ack'); | ||
ackMessage.value = message.ack; | ||
ackMessage.op = 'ack'; | ||
ackMessage.value = request.getAttr('ack'); | ||
fn(ackMessage); | ||
}; | ||
client._write(message, callback); | ||
client._write(request, callback); | ||
assert.ok(called); | ||
@@ -637,4 +668,5 @@ assert.ok(passed); | ||
passed = true, | ||
message = { op: 'something', to: 'wherever:/account/scope/1' }, | ||
ackMessage = { value: -2 }, | ||
request = Request.buildSubscribe('status:/account/scope/1'), | ||
ackMessage = { op: 'ack', value: -2 }, | ||
response = new Response(ackMessage), | ||
callback = function(msg) { passed = false; }; | ||
@@ -645,6 +677,6 @@ | ||
assert.equal(name, 'ack'); | ||
fn(message); | ||
fn(response); | ||
}; | ||
client._write(message, callback); | ||
client._write(request, callback); | ||
assert.ok(called); | ||
@@ -657,4 +689,15 @@ assert.ok(passed); | ||
'should ignore messages without the appropriate properties': { | ||
'op': function() { | ||
var message = { to: 'status:/dev/ticket/1', value: 'x', time: new Date() / 1000 }, | ||
response; | ||
response = new Response(message); | ||
assert.deepEqual(client._channelSyncTimes, {}); | ||
}, | ||
'to': function() { | ||
assert.ok(!client._batch({ value: 'x', time: new Date() / 1000 })); | ||
var message = { op: 'subscribe', value: 'x', time: new Date() / 1000 }, | ||
response; | ||
response = new Response(message); | ||
assert.deepEqual(client._channelSyncTimes, {}); | ||
@@ -664,4 +707,7 @@ }, | ||
'value': function() { | ||
var message = { op: 'subscribe', to: 'you', value: 'x'}, | ||
response = new Response(message); | ||
assert.equal(client._channelSyncTimes.you, undefined); | ||
assert.ok(!client._batch({ value: 'x', to: 'you' })); | ||
assert.ok(!client._batch(response)); | ||
assert.equal(client._channelSyncTimes.you, undefined); | ||
@@ -671,4 +717,7 @@ }, | ||
'time': function() { | ||
var message = { op: 'subscribe', to: 'you', value: 'x' }, | ||
response = new Response(message); | ||
assert.equal(client._channelSyncTimes.you, undefined); | ||
assert.ok(!client._batch({ value: 'x', to: 'you' })); | ||
assert.ok(!client._batch(response)); | ||
assert.equal(client._channelSyncTimes.you, undefined); | ||
@@ -681,9 +730,11 @@ } | ||
message = { | ||
op: 'subscribe', | ||
to: 'you', | ||
value: [ '{}', now ], | ||
time: now | ||
}; | ||
}, | ||
response = new Response(message); | ||
assert.equal(client._channelSyncTimes.you, undefined); | ||
assert.notEqual(client._batch(message), false); | ||
assert.notEqual(client._batch(response), false); | ||
assert.equal(client._channelSyncTimes.you, now); | ||
@@ -696,6 +747,8 @@ }, | ||
message = { | ||
op: 'subscribe', | ||
to: 'you', | ||
value: [ '{ "something": 1 }', now ], | ||
time: now | ||
}; | ||
}, | ||
response = new Response(message); | ||
@@ -706,7 +759,7 @@ client._channelSyncTimes.you = now - HOUR; | ||
called = true; | ||
assert.equal(name, message.to); | ||
assert.deepEqual(data, JSON.parse(message.value[0])); | ||
assert.equal(name, response.getAttr('to')); | ||
assert.deepEqual(data, JSON.parse(response.getAttr('value')[0])); | ||
}; | ||
assert.notEqual(client._batch(message), false); | ||
assert.notEqual(client._batch(response), false); | ||
assert.equal(client._channelSyncTimes.you, now); | ||
@@ -874,3 +927,3 @@ assert.ok(called); | ||
while (count < 10) { | ||
client._queuedMessages.push({ test: count++ }); | ||
client._queuedRequests.push({ test: count++ }); | ||
} | ||
@@ -911,3 +964,3 @@ | ||
var called = false, | ||
message = { test: 1 }; | ||
request = Request.buildSubscribe('status:/test/ticket/1'); | ||
@@ -920,7 +973,7 @@ client.manager.is = function(state) { return state == 'activated'; }; | ||
assert.equal(name, 'message'); | ||
assert.equal(data, JSON.stringify(message)); | ||
assert.equal(data, JSON.stringify(request.getMessage())); | ||
} | ||
}; | ||
client._sendMessage(message); | ||
client._sendMessage(request); | ||
assert.ok(called); | ||
@@ -930,15 +983,15 @@ }, | ||
'should queue the message if the client has been configured, but is not activated': function() { | ||
var message = { test: 1 }; | ||
var request = Request.buildSet('status:/test/ticket/1', 'any_value'); | ||
client.configure({}); | ||
client._sendMessage(message); | ||
assert.deepEqual(message, client._queuedMessages[0]); | ||
client._sendMessage(request); | ||
assert.deepEqual(request, client._queuedRequests[0]); | ||
}, | ||
'should ignore the message if the client has not been configured': function() { | ||
var message = { test: 1 }; | ||
var request = Request.buildSet('status:/test/ticket/1', 'any_value'); | ||
assert.ok(!client._isConfigured); | ||
client._sendMessage(message); | ||
assert.equal(client._queuedMessages.length, 0); | ||
client._sendMessage(request); | ||
assert.equal(client._queuedRequests.length, 0); | ||
} | ||
@@ -971,2 +1024,3 @@ }, | ||
op: 'ack', | ||
value: 1 | ||
}, | ||
@@ -990,2 +1044,3 @@ json = JSON.stringify(message); | ||
op: 'get', | ||
to: 'staus:/test/ticket/1' | ||
}, | ||
@@ -1009,2 +1064,3 @@ json = JSON.stringify(message); | ||
op: 'sync', | ||
to: 'staus:/test/ticket/1' | ||
}, | ||
@@ -1015,3 +1071,3 @@ json = JSON.stringify(message); | ||
called = true; | ||
assert.deepEqual(msg, message); | ||
assert.deepEqual(msg.message, message); | ||
}; | ||
@@ -1018,0 +1074,0 @@ |
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
116686
24
2958
5
5
+ Addedradar_message@1.0.1
+ Addedradar_message@1.0.1(transitive)