diff --git a/common/lib/client/realtimechannel.js b/common/lib/client/realtimechannel.js index 2b7cc83a39..2339d7f468 100644 --- a/common/lib/client/realtimechannel.js +++ b/common/lib/client/realtimechannel.js @@ -7,6 +7,7 @@ var RealtimeChannel = (function() { function RealtimeChannel(realtime, name, options) { Logger.logAction(Logger.LOG_MINOR, 'RealtimeChannel()', 'started; name = ' + name); Channel.call(this, realtime, name, options); + this.realtime = realtime; this.presence = new RealtimePresence(this, realtime.options); this.connectionManager = realtime.connection.connectionManager; this.state = 'initialized'; @@ -14,7 +15,6 @@ var RealtimeChannel = (function() { this.pendingEvents = []; this.syncChannelSerial = undefined; this.attachSerial = undefined; - this.realtime = realtime; this.setOptions(options); } Utils.inherits(RealtimeChannel, Channel); diff --git a/common/lib/client/realtimepresence.js b/common/lib/client/realtimepresence.js index 4f0bfd6bc4..76e3e52030 100644 --- a/common/lib/client/realtimepresence.js +++ b/common/lib/client/realtimepresence.js @@ -7,6 +7,10 @@ var RealtimePresence = (function() { return item.clientId + ':' + item.connectionId; } + function getClientId(realtimePresence) { + return realtimePresence.channel.realtime.auth.clientId; + } + function waitAttached(channel, callback, action) { switch(channel.state) { case 'attached': @@ -28,22 +32,20 @@ var RealtimePresence = (function() { function RealtimePresence(channel, options) { Presence.call(this, channel); - this.clientId = options.clientId; this.members = new PresenceMap(this); this.subscriptions = new EventEmitter(); } Utils.inherits(RealtimePresence, Presence); RealtimePresence.prototype.enter = function(data, callback) { - if(!this.clientId) - throw new Error('clientId must be specified to enter a presence channel'); + if(!getClientId(this)) + throw new ErrorInfo('clientId must be specified to enter a presence channel', 40012, 400); this._enterOrUpdateClient(undefined, data, callback, 'enter'); }; RealtimePresence.prototype.update = function(data, callback) { - if(!this.clientId) { - throw new Error('clientId must be specified to update presence data'); - } + if(!getClientId(this)) + throw new Error('clientId must be specified to update presence data', 40012, 400); this._enterOrUpdateClient(undefined, data, callback, 'update'); }; @@ -66,7 +68,7 @@ var RealtimePresence = (function() { } Logger.logAction(Logger.LOG_MICRO, 'RealtimePresence.' + action + 'Client()', - action + 'ing; channel = ' + this.channel.name + ', client = ' + clientId || '(implicit) ' + this.clientId); + action + 'ing; channel = ' + this.channel.name + ', client = ' + clientId || '(implicit) ' + getClientId(this)); var presence = PresenceMessage.fromValues({ action : presenceAction[action.toUpperCase()], @@ -98,15 +100,15 @@ var RealtimePresence = (function() { }; break; default: - var err = new Error('Unable to ' + action + ' presence channel (incompatible state)'); + var err = new ErrorInfo('Unable to ' + action + ' presence channel (incompatible state)', 90001); err.code = 90001; callback(err); } }; RealtimePresence.prototype.leave = function(data, callback) { - if(!this.clientId) - throw new Error('clientId must have been specified to enter or leave a presence channel'); + if(!getClientId(this)) + throw new ErrorInfo('clientId must have been specified to enter or leave a presence channel', 40012, 400); this.leaveClient(undefined, data, callback); }; @@ -142,8 +144,7 @@ var RealtimePresence = (function() { /* we're not attached; therefore we let any entered status * timeout by itself instead of attaching just in order to leave */ this.pendingPresence = null; - var err = new Error('Unable to leave presence channel (incompatible state)'); - err.code = 90001; + var err = new ErrorInfo('Unable to leave presence channel (incompatible state)', 90001); callback(err); break; default: diff --git a/spec/realtime/presence.test.js b/spec/realtime/presence.test.js index 22e0235c48..f529d22e1d 100644 --- a/spec/realtime/presence.test.js +++ b/spec/realtime/presence.test.js @@ -1226,5 +1226,39 @@ define(['ably', 'shared_helper', 'async'], function(Ably, helper, async) { }); } + /* + * Request a token using clientId, then initialize a connection without one, + * and check that can enter presence with the clientId inherited from tokenDetails + */ + exports.presence_enter_inherited_clientid = function(test) { + test.expect(3); + var channelName = "enter_inherited_clientid" + + var authCallback = function(tokenParams, callback) { + rest.auth.requestToken({clientId: testClientId}, function(err, tokenDetails) { + if(err) { + test.ok(false, displayError(err)); + test.done(); + return; + } + callback(null, tokenDetails); + }); + }; + + var enterInheritedClientId = function(cb) { + var realtime = helper.AblyRealtime({ authCallback: authCallback }); + var channel = realtime.channels.get(channelName); + realtime.connection.on('connected', function() { + test.equal(realtime.auth.clientId, testClientId); + channel.presence.enter("test data", function(err) { + cb(err, realtime); + }); + }); + monitorConnection(test, realtime); + } + + runTestWithEventListener(test, channelName, listenerFor('enter', testClientId), enterInheritedClientId); + }; + return module.exports = helper.withTimeout(exports); });