Loop/Architecture/Rooms: Difference between revisions
Line 254: | Line 254: | ||
} | } | ||
* '''operation''' - | * '''operation''' - For refreshing the soft state relationship, this will be "refresh". | ||
HTTP/1.1 200 OK | HTTP/1.1 200 OK | ||
Line 266: | Line 266: | ||
} | } | ||
* '''expires''' - | * '''expires''' - The number of seconds within which the client must send another POST to this endpoint to remain a participant in this room. See [[#Room Membership and Soft State]] | ||
==== Leaving a Room ==== | ==== Leaving a Room ==== |
Revision as of 18:27, 10 September 2014
This is still under construction, is missing important details, and may change substantially as scenarios are fleshed out further. Do not implement.
Based on early user feedback, we will be adding a "rooms" metaphor to the Loop product. Initially, this will be based on a "link as a room" model, although we will likely explore link-free rooms experiences for logged-in users in the future.
Many of the network operations required for rooms are very similar to those we currently use for link-based calling (that is, the "/call-url" and "/calls" endpoints). However, the parameters and behaviors are sufficiently different that re-using those codepaths would have caused more confusion and work than simply defining new ones. However, the conceptual model that developers have around how these endpoints work can be useful in understanding the rooms design. Consequently, the network API for rooms uses "/room-url" and "/rooms" endpoints in a way that is congruent with the "/call-url" and "/calls" endpoints. Note, however, that no websockets connection is necessary, as call progress information is not conveyed.
Similar to the call-url design, users can generate rooms both when logged in to FxA and when not logged in.
Note that we do not want to remove the link-based calling functionality from the server at this point. Potential future use-cases include things like "click to call" URLs associated with small and medium businesses. The existing link-based calling functions will be important for implementing this and similar use cases.
Date | Author | Changes |
---|---|---|
Wed Sep 10 09:11:58 CDT 2014 | Adam Roach | Initial version |
Mapping to TokBox Concepts
The TokBox toolkit is based on a model of indestructible sessions (identified by a Session ID), which clients join by being issued session tokens, which expire after a predetermined period of time. API-wise, sessions are designed to support an arbitrary number of participants.
The rooms implementation will map each Loop room to a single session, which is created when the room is first created. Once a room is created, this room-to-session binding will remain constant throughout the lifetime of the room.
Each time a user joins a room, he will be issued a new session token to do so. If a user leaves a room and re-joins, he is issued a new token.
User Identification in a Room
When the Loop server generates a new token for a user, it optionally includes a "data" field. This field is then communicated to other participants in the room when the corresponding user joins the room: the ConnectionEvent on Session contains a Connection object, which includes a "data" field. This is the same "data" as was provided by the server when the token was created.
The Loop server, when generating a toke for a user in a room, will set the contents of the "data" field to a JSON string, containing the following information:
{ "displayName": "Alexis", "account": "alexis@example.com", "id": "2a1787a6-4a73-43b5-ae3e-906ec1e763cb" }
- displayName - The user-friendly name that should be displayed for this participant
- account - If the user is logged in, this is the FxA account name or MSISDN that was used to authenticate the user for this session
- id - An id, unique within the room for the lifetime of the room, used to identify a participant for the duration of one instance of joining the room. If the user departs and re-joins, this id will change. Note that this document uses a UUID in its examples, since they can be used in this fashion without having to store additional state; however, anything that is unique within a room for its entire lifetime (e.g., a constantly increasing integer) would be suitable as well.
Room Size Handling
For the initial release of room, clients are expected to handle only two participants per room. However, to allow for a smooth transition to multiparty rooms, this interface is being designed to accommodate rooms with an arbitrary number of participants.
When rooms are initially created, the creator will specify the maximum number of participants supported by the room at any given time. The Loop server is responsible for tracking the number of users in a room, and for declining to issue new tokens once the room has reached capacity.
Additionally, due to device constraints (as well as due to the potential to have multiple versions of the client deployed simultaneously), it is possible in the future to have clients that support fewer participants in a room than the room has been configured to support. To deal with this situation, when a client attempts to join a room, it includes the maximum number of participants it is capable of handling at one time. When determining whether to admit a new user, the Loop server takes into consideration both the configured room maximum size and the client capabilities of those clients currently in (and attempting to join) the session.
For example: consider a configured to support up to 4 users.
- A first user joins with a client that supports up to 3 users. His presence temporarily reduces the room capacity to 3.
- A second user joins with a client that supports up to 3 clients. The server admits this user, since the room is not yet full.
- A third user attempts to join, but indicates the ability to support only two users. The third user is refused entry, since his joining would reduce the supported capacity to two, but result in a total of three users.
- The second user departs, leaving only the first user in the room.
- The third user reattempts joining. His presence temporarily reduces the room capacity to 2. He is admitted, and the room now contains two users.
- The second user attempts to rejoin. Since the room capacity is temporarily reduced to 2, he is refused entry.
- The third user departs, and the room capacity returns to 3.
- The first user departs. The room is empty, so its capacity returns to the configured value of 4.
When communicating room sizes to clients, we indicate these values as "maxSize" (for the configured maximum), and "clientMaxSize" (for the largest value that can be currently supported due to the capabilities of the clients participating in the room).
Room Membership and Soft State
In order to track the number of users in a session, the Loop server needs to be kept up-to-date with the list of current participants. This means that client will explicitly indicate to the server when they are departing a session (and whenever they experience a detectable failure locally). The server will add users to the list of room participants as they join, and remove them as they depart.
However, to avoid circumstances in which clients depart unexpectedly (e.g. crashes, loss of network connectivity) from keeping them in the list of room participants, we need to employ a soft-state mechanism. Once a client joins a room, it need to periodically contact the Loop server to indicate that it is still a member of that room. If the client goes significantly longer than expected to perform this periodic action, they are considered to be no longer part of the session, and are removed from the participant list.
This scheme works as follows: when a user initially joins a room (using "POST /rooms/{token}"), the response indicates an expiration time, measured in seconds, during which the client must perform another POST to the same "/rooms/{token}" endpoint. If the this number of seconds (plus some grace period, on the order of 30 seconds) passes without a subsequent POST, then the user is removed from the list of participants.
This refresh period is communicated by the server each time it receives a POST. The duration selected for this refresh period is a trade-off between server load and responsiveness to users departing unexpectedly. While it is initially anticipated that the value will be a static configuration, the server may choose to adjust it dynamically based on server load (thus providing rapid recovery when it has the capacity to do so, but shedding load when necessary during periods of heavy use).
The suggested period for this timer for initial deployment is 600 seconds (10 minutes).
Removing Participants from a Room
When the server generates a session participant token, it can also select a participant role. When creating a token for the room owner, the server must include a "role" of "moderator," which will allow the room owner to remove participants from rooms.
To remove a user from a room, the owner then uses the forceDisconnect method on the Sessionto remove a user from the room. Upon receiving a disconnection event for their own connection with a reason of "forceDisconnect," the removed client will remove himself from the session by calling POST /rooms/{token}.
Room Owner Notification
When the status of a room changes (e.g., a user joins or leaves), and the owner is not a member of the room, then the Loop server will cause a notification to be sent to the room owner by way of a push notification. The room owners' client can then retrieve a list of the users' rooms (that is, all those rooms that have changed on or after the indicated version), and take appropriate action. For the current UX, these actions include an unobtrusive audio notification when a user joins a room that the owner is not yet in, as well as (probably) a count of users and/or rooms waiting for the owner to join.
Loop Server API Additions
To accommodate rooms, the Loop Server API will need the following additions.
POST /room-url
This generates a new room and returns the associated URL that can be used to join the room.
POST /room-url HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Authorization: <stripped> Content-Type: application/json; charset=utf-8 Host: localhost:5000 { "roomName": "UX Discussion", "expiresIn": "5", "roomOwner": "Alexis", "maxSize": "2" }
- roomName - The room-owner-assigned name used to identify this room.
- expiresIn - The number of hours for which the room will exist.
- roomOwner - The user-friendly display name indicating the name of the room's owner.
- maxSize - The maximum number of users allowed in the room at one time.
HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Wed, 16 Jul 2014 13:09:40 GMT Server-Authorization: <stripped> { "roomToken": "_nxD4V4FflQ", "roomUrl": "http://localhost:3000/room/_nxD4V4FflQ", "expiresAt": 1405534180 }
- roomToken - The token used to identify this room.
- roomUrl - A URL that can be given to other users to allow them to join the room.
- expiresAt - The date after which the room will no longer be valid (in seconds since the Unix epoch).
Server implementation note: The Loop server should contact the TokBox servers and retrieve a sessionId for the room at room creation time. This sessionId should be stored persistently with rest of the information associated with the room.
PUT /room-url/{token}
The "PUT /room-url/{token}" endpoint is used to update information about an existing room.
PUT /room-url HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Authorization: <stripped> Content-Type: application/json; charset=utf-8 Host: localhost:5000 { "roomName": "Follow-up from UX Discussion", "expiresIn": "24" }
The parameters for this endpoint are the same as for "POST /room-url". Any omitted parameters are not updated.
HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Wed, 16 Jul 2014 13:09:40 GMT Server-Authorization: <stripped> { "expiresAt": 1405534180 }
- expiresAt - The date after which the room will no longer be valid (in seconds since the Unix epoch).
DELETE /room-url/{token}
Destroys a previously-created room.
DELETE /room-url/_nxD4V4FflQ HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Authorization: <stripped> Content-Length: 0 Host: localhost:5000
HTTP/1.1 204 No Content Connection: keep-alive Date: Wed, 16 Jul 2014 13:12:46 GMT Server-Authorization: <stripped>
Client implementation note: Before deleting a room, the client should check room membership and forceDisconnect() all current participants
GET /rooms/{token}
This endpoint is used to retrieve information about a single room, including a list of room participants.
GET /rooms/3jKS_Els9IU HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Host: localhost:5000
HTTP/1.1 200 OK Connection: keep-alive Content-Length: 30 Content-Type: application/json; charset=utf-8 Date: Wed, 16 Jul 2014 13:23:04 GMT ETag: W/"1e-2896316483" Timestamp: 1405516984 { "roomName": "UX Discussion", "roomOwner": "Alexis", "maxSize": "2", "clientMaxSize": "2", "urlCreationDate": 1405517546, "expiresAt": 1405534180, "participants": [ { "displayName": "Alexis", "account": "alexis@example.com", "id": "2a1787a6-4a73-43b5-ae3e-906ec1e763cb" }, { "displayName": "Adam", "id": "781f012b-f1ea-4ce1-9105-7cfc36fb4ec7" } ] }
- roomName - The room-owner-assigned name used to identify this room.
- roomOwner - The user-friendly display name indicating the name of the room's owner.
- maxSize - The maximum number of users allowed in the room at one time (as configured by the room owner).
- clientMaxSize - The current maximum number of users allowed in the room, as constrained by the clients currently participating in the session. If no client has a supported size smaller than "maxSize", then this will be equal to "maxSize". Under no circumstances can "clientMaxSize" be larger than "maxSize".
- urlCreationDate - The time (in seconds since the Unix epoch) at which the room was created.
- expiresAt - The time (in seconds since the Unix epoch) at which the room goes away.
- participants - An array containing a list of the current room participants. Each participant is formatted with the same fields as described in #User Identification in a Room.
POST /rooms/{token}
The "POST /rooms/{token}" endpoint is used for a variety of purposes. The JSON object in its body contains an "operation" parameter to indicate which of these purposes the operation is being used for.
Joining a Room
Server implementation note: associate user token with sessionToken here. Room owner must have "moderator" privileges.
POST /rooms/QzBbvGmIZWU HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Content-Type: application/json; charset=utf-8 Host: localhost:5000 { "operation": "join", "displayName": "Adam", "clientMaxSize": "2" }
- operation - For joining a room, will be set to "join"
- displayName - User-friendly display name for the joining user.
- clientMaxSize - Maximum number of room participants the user's client is capable of supporting.
HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Wed, 16 Jul 2014 13:37:39 GMT Timestamp: 1405517859 { "apiKey": "44669102", "sessionId": "1_MX40NDY2OTEwMn5-V2VkIEp1bCAxNiAwNjo", "sessionToken": "T1==cGFydG5lcl9pZD00NDY2OTEwMiZzaW", "expires": "600" }
- apiKey - The provider public api Key
- sessionId - The provider session identifier
- sessionToken - The provider session token (for the room participant)
- expires - The number of seconds within which the client must send another POST to this endpoint to remain a participant in this room. See #Room Membership and Soft State
Refreshing Membership in a Room
POST /rooms/QzBbvGmIZWU HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Content-Type: application/json; charset=utf-8 Host: localhost:5000 { "operation": "refresh" }
- operation - For refreshing the soft state relationship, this will be "refresh".
HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Wed, 16 Jul 2014 13:47:39 GMT Timestamp: 1405517859 { "expires": "600" }
- expires - The number of seconds within which the client must send another POST to this endpoint to remain a participant in this room. See #Room Membership and Soft State
Leaving a Room
POST /rooms/QzBbvGmIZWU HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Content-Type: application/json; charset=utf-8 Host: localhost:5000 { "operation": "leave" }
- operation -
HTTP/1.1 204 No Content Connection: keep-alive Server-Authorization: <stripped>
GET /rooms
List all rooms associated with account
GET /rooms?version=<version> HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Host: localhost:5000
- version -
HTTP/1.1 200 OK Connection: keep-alive Content-Length: 30 Content-Type: application/json; charset=utf-8 Date: Wed, 16 Jul 2014 13:23:04 GMT ETag: W/"1e-2896316483" Timestamp: 1405516984 [ { "roomToken": "_nxD4V4FflQ", "roomName": "First Room Name", "maxSize": "2", "currSize": "0", "lastUsed": "1405517546" }, { "roomToken": "QzBbvGmIZWU", "roomName": "Second Room Name", "maxSize": "2", "currSize": "0", "lastUsed": "1405517418" }, { "roomToken": "3jKS_Els9IU", "roomName": "Third Room Name", "maxSize": "3", "clientMaxSize": "2", "currSize": "1", "lastUsed": "1405518241" } ]
- roomToken -
- roomName -
- maxSize -
- clientMaxSize -
- currSize -
- lastUsed -