Summary
Presence._handleSubscribe sets subscribed = true even when the server rejects the subscription:
Presence.prototype._handleSubscribe = function(error, seq) {
if (this.wantSubscribe) this.subscribed = true;
Doc._handleSubscribe, by contrast, returns on error before marking itself subscribed.
Repro
- Reject
ps in 'receive' middleware
presence.subscribe(cb): cb gets the error, but presence.subscribed is true
presence.subscribe(cb) again: cb is called with no error, and nothing is sent to the server
- Reconnect:
_resubscribe sends the subscription again, and its rejection is emitted as 'error' on the Presence, which throws if nothing is listening
This also means apps can't reject presence subscriptions in middleware without leaving the client in a broken state. The presence access control docs in #752 recommend filtering in 'sendPresence' for that reason.
Suggested fix
On error, leave subscribed alone and reset wantSubscribe, as Doc does, so a later subscribe() actually retries and a reconnect doesn't re-send a subscription the server already refused.
Summary
Presence._handleSubscribesetssubscribed = trueeven when the server rejects the subscription:Doc._handleSubscribe, by contrast, returns on error before marking itself subscribed.Repro
psin'receive'middlewarepresence.subscribe(cb):cbgets the error, butpresence.subscribedistruepresence.subscribe(cb)again:cbis called with no error, and nothing is sent to the server_resubscribesends the subscription again, and its rejection is emitted as'error'on thePresence, which throws if nothing is listeningThis also means apps can't reject presence subscriptions in middleware without leaving the client in a broken state. The presence access control docs in #752 recommend filtering in
'sendPresence'for that reason.Suggested fix
On error, leave
subscribedalone and resetwantSubscribe, asDocdoes, so a latersubscribe()actually retries and a reconnect doesn't re-send a subscription the server already refused.