diff --git a/content/client-lib-development-guide/features.textile b/content/client-lib-development-guide/features.textile index 0dacfb8ef3..8ccd9f7773 100644 --- a/content/client-lib-development-guide/features.textile +++ b/content/client-lib-development-guide/features.textile @@ -459,7 +459,7 @@ h3(#realtime-channels). Channels h3(#realtime-channel). Channel -* @(RTL1)@ As soon as a @Channel@ becomes attached, all incoming messages and presence messages are processed and emitted where applicable. @PRESENCE@ and @SYNC@ messages are passed to the @Presence@ object ensuring it maintains a map of current members on a channel in realtime +* @(RTL1)@ As soon as a @Channel@ becomes attached, all incoming messages and presence messages (where 'incoming' is defined as 'received from Ably over the realtime transport') are processed and emitted where applicable. @PRESENCE@ and @SYNC@ messages are passed to the @Presence@ object ensuring it maintains a map of current members on a channel in realtime * @(RTL2)@ The @Channel@ implements @EventEmitter@ and emits @ChannelEvent@ events, where a @ChannelEvent@ is either a @ChannelState@ or @UPDATE@, and a @ChannelState@ is either @INITIALIZED@, @ATTACHING@, @ATTACHED@, @DETACHING@, @DETACHED@, @SUSPENDED@ and @FAILED@ ** @(RTL2a)@ It emits a @ChannelState@ @ChannelEvent@ for every channel state change ** @(RTL2g)@ It emits an @UPDATE@ @ChannelEvent@ for changes to channel conditions for which the @ChannelState@ (e.g. @ATTACHED@) does not change. (The library must never emit a @ChannelState@ @ChannelEvent@ for a state equal to the previous state) @@ -571,18 +571,19 @@ h3(#realtime-presence). Presence ** @(RTP18c)@ a @SYNC@ may also be sent with no @channelSerial@ attribute. In this case, the sync data is entirely contained within that @ProtocolMessage@ * @(RTP19)@ If the @PresenceMap@ has existing members when a @SYNC@ is started, the client library must ensure that members no longer present on the channel are removed from the local @PresenceMap@ once the sync is complete. In order to do this, the client library must keep track of any members that have not been added or updated in the @PresenceMap@ during the sync process. Note that a member can be added or updated when received in a @SYNC@ message or when received in a @PRESENCE@ message during the sync process. Once the sync is complete, the members in the @PresenceMap@ that have not been added or updated should be removed from the @PresenceMap@ and a @LEAVE@ event should be published for each. The @PresenceMessage@ published should contain the original attributes of the presence member with the @action@ set to @LEAVE@, @PresenceMessage#id@ set to @null@, and the @timestamp@ set to the current time. This behavior should be tested as follows: @ENTER@ presence on a channel, wait for @SYNC@ to complete, inject a member directly into the local @PresenceMap@ so that it only exists locally and not on the server, send a @SYNC@ message with the @channel@ attribute populated with the current channel which will trigger a server initiated @SYNC@. A @LEAVE@ event should then be published for the injected member, and checking the @PresenceMap@ should reveal that the member was removed and the valid member entered for this connection is still present ** @(RTP19a)@ If the @PresenceMap@ has existing members when an @ATTACHED@ message is received without a @HAS_PRESENCE@ flag, the client library should emit a @LEAVE@ event for each existing member, and the @PresenceMessage@ published should contain the original attributes of the presence member with the @action@ set to @LEAVE@, @PresenceMessage#id@ set to @null@, and the @timestamp@ set to the current time. Once complete, all members in the @PresenceMap@ should be removed as there are no members present on the channel -* @(RTP17)@ The Presence object is also responsible for keeping a separate copy of an object logically equivalent to the @PresenceMap@ containing only members that match the current @connectionId@. Any incoming presence message that satisfies @RTP17b@ should be applied to this object in the same way as for the normal @PresenceMap@. This object should be private and is used to maintain a list of members that need to be automatically re-entered by the @Presence@ object when required to by @RTP5c2@. +* @(RTP17)@ The Presence object should also keep a second @PresenceMap@ containing only members that match the current @connectionId@. Any incoming presence message that satisfies @RTP17b@ should be applied to this object in the same way as for the normal @PresenceMap@. This object should be private and is used to maintain a list of members that need to be automatically re-entered by the @Presence@ object when required to by @RTP17c@. ** @(RTP17a)@ All members belonging to the current connection are published as a @PresenceMessage@ on the @Channel@ by the server irrespective of whether the client has permission to subscribe or the @Channel@ is configured to publish presence events. A test should exist that attaches to a @Channel@ with a @presence@ capability and without a @subscribe@ capability. It should then enter the @Channel@ and ensure that the member entered from the current connection is present in the internal and public presence set available via "@Presence#get@":#RTP11 ** @(RTP17b)@ The events that should be applied to the @RTP17@ presence map are: any @ENTER@, @PRESENT@ or @UPDATE@ event with a @connectionId@ that matches the current client's @connectionId@; any @LEAVE@ event with a @connectionId@ that matches the current client's @connectionId@ and is not a 'synthesized leave' (an event that has a connectionId which is not an initial substring of its id, per "@RTP2b1@":#RTP2b1 ) +** @(RTP17c)@ The Presence object should perform automatic re-entry in the following situations: +*** @(RTP17c1)@ After a @SYNC@ operation has completed, per "@RTP18b@":#RTP18b +*** @(RTP17c2)@ When an @ATTACHED@ message is received with no "@HAS_PRESENCE@":#TR3a flag (so no @SYNC@ is expected as the server does not believe anyone is currently present) +** @(RTP17d)@ Automatic re-entry consists of, for each member of the @RTP17@ internal @PresenceMap@ whose @memberKey@ is not also a member of the normal @PresenceMap@, publishing a @PresenceMessage@ with an @ENTER@ action using the @clientId@ and @data@ attributes from that member, and removing that member from the internal @PresenceMap@ +** @(RTP17e)@ If the publish attempt fails for an automatic presence @ENTER@ (for example, by Ably rejecting it with a @NACK@), an @UPDATE@ event should be emitted on the channel with @resumed@ set to true and @reason@ set to an @ErrorInfo@ object with @code@ @91004@, a @message@ indicating that an automatic re-enter has failed and indicating the @clientId@, and @cause@ set to the the reason for the enter failure. The error should also be logged at @warn@ level or higher. * @(RTP4)@ Ensure a test exists that enters 250 members using @Presence#enterClient@ on a single connection, and checks for @PRESENT@ events to be emitted on another connection for each member, and once sync is complete, all 250 members should be present in a @Presence#get@ request * @(RTP5)@ Channel state change side effects: ** @(RTP5a)@ If the channel enters the @DETACHED@ or @FAILED@ state then all queued presence messages will fail immediately, and the @PresenceMap@ and "internal PresenceMap (see RTP17)":#RTP17 is cleared. The latter ensures members are not automatically re-entered if the @Channel@ later becomes attached. Since channels in the @DETACHED@ and @FAILED@ states will not receive any presence updates from Ably, presence events (specifically @LEAVE@) should not be emitted when the @PresenceMap@ is cleared as each presence member's state is unknown ** @(RTP5f)@ If the channel enters the @SUSPENDED@ state then all queued presence messages will fail immediately, and the @PresenceMap@ is maintained. This ensures that if the channel later becomes @ATTACHED@, it will only publish presence events for the changes in the @PresenceMap@ that have occurred whilst the client was disconnected. A test should exist for a channel that is in the @SUSPENDED@ state containing presence members to transition to the @ATTACHED@ state, and following the @SYNC@ process after attaching, any members present before and after the sync should not emit presence events, all other changes should be reflected in the @PresenceMap@ and should emit presence events on the channel -** @(RTP5b)@ If a channel enters the @ATTACHED@ state then all queued presence messages will be sent immediately and a presence @SYNC@ may be initiated by the Ably service or the Ably service may indicate there is no @SYNC@ necessary -** @(RTP5c)@ In addition, when a channel becomes @ATTACHED@, the following must happen in regards to @Presence@: -*** @(RTP5c1)@ If the "@resumed@ flag":#TH4 is true and no @SYNC@ is initiated as part of the attach, do nothing as there is no loss of continuity on the channel and no change to presence. The @PresenceMap@ is not affected and no members need to be re-entered -*** @(RTP5c2)@ If either a @SYNC@ is initiated as part of the attach and the @SYNC@ is complete, or if the @resumed@ flag is false and a @SYNC@ is not expected, all members not present in the @PresenceMap@ but present in the "internal @PresenceMap@":#RTP17 must be re-entered automatically by the client using the @clientId@ and @data@ attributes from each. The members re-entered automatically must be removed from the "internal @PresenceMap@":#RTP17 ensuring that members present on the channel are constructed from presence events sent from Ably since the channel became @ATTACHED@ -*** @(RTP5c3)@ If any of the automatic @ENTER@ presence messages published in "RTP5c2":#RTP5c2 fail, then an @UPDATE@ event should be emitted on the channel with @resumed@ set to true and @reason@ set to an @ErrorInfo@ object with error @code@ value @91004@ and the error @message@ string containing the message received from Ably (if applicable), the @code@ received from Ably (if applicable) and the explicit or implicit @client_id@ of the @PresenceMessage@ +** @(RTP5b)@ If a channel enters the @ATTACHED@ state then all queued presence messages will be sent immediately. A presence @SYNC@ may be initiated per "@RTP1@":#RTP1 * @(RTP16)@ Connection state conditions: ** @(RTP16a)@ If the connection is @CONNECTED@ and the channel is @ATTACHED@ then all presence messages are published immediately ** @(RTP16b)@ If the connection is @INITIALIZED@, @CONNECTING@ or @DISCONNECTED@ or the channel is @ATTACHING@ or @INITIALIZED@, and @ClientOptions#queueMessages@ has not been explicitly set to false, then all presence messages will be queued and delivered as soon as the connection state returns to @CONNECTED@ and the channel is @ATTACHED@