Skip to content

Presence

All collaborative applications require that a user be able to tell who else is available to work and communicate with. In Convergence, a Presence API provides this ability. The most common example of presence is the "buddy list" concept (remember AOL Instant Messenger?), where users can see who is online, who is available, and what their status is. However, various applications implement presence differently, so the Convergence Presence API was designed to be able to handle most likely scenarios.

Availability

Availability indicates whether someone is reachable in the system. At the moment, this roughly equates to whether or not someone is connected to the system or not. Since a user may have more than one session, for a user to be available she only needs to have one session that is available. If a user has no sessions, she will not be available.

Takeaway: Presence is per user, not per session!

User Presence

Most of the Presence API centers around getting the status of one or more users. When obtaining the presence for a user, the result is a UserPresence object:

class UserPresence {
  username: string;
  isAvailable: boolean;
  state: Map<string, any>;
}

PresenceState

Note that each UserPresence object has a state map. Presence state is global across all sessions of a particular user. Any session can set state, but that state is distributed across all sessions for that user.

Streaming vs. One Time Requests

In some cases, users may wish to ask a one-time question inquiring about the current presence of another user. In other cases, users may be interested in any changes to another user's presence that occur in the future. Most methods in the presence API allow for both options.

Own Presence

The Presence Service allows any session to set the presence state for that user. If the user is connected across multiple sessions, that the change to the user's presence will be distributed to all connected sessions. The example below shows how you can set and monitor the presence for the local user.

Publishing State

State is published as key-value pairs. The API will accept any key and value combinations.

var service = domain.presence();
service.setState("status", "away");

Clearing State

You may wish to clear a previously set state. Rather than publishing with an empty value such as undefined or null, use the clear method.

var service = domain.presence();
service.removeState("status");

Listening

To listen for other sessions of the same user triggering presence state changes, simply get the presence for the local user as a stream and listen to it as you would any other user's presence.

var service = domain.presence();
service.events().subscribe((presence) => {
  console.log('New state:', presence.state());
});

Other Users' Presence

Getting A User's Presence

var service = domain.presence();
service.presence("username1").then((presence) => {
  console.log(presence); // UserPresence object
});

Getting Multiple Users' Presences

var service = domain.presence();
service.presence(["username1", "username2"]).then((presences) => {
  presences.forEach((presence) => {
    console.log(presence);
  });
});

Streaming Presence

Use the subscribe method to obtain the current state of the user's presence. From that UserPresenceSubscription object, you can subscribe to an Observable to subscribe to additional changes.

import { distinctUntilKeyChanged } from 'rxjs/operators';

var service = domain.presence();
// Get notified when the user's availability changes
service.subscribe("username1").then((presenceSubscription) => {
  if(!presenceSubscription.available) {
    console.log('waiting...');
    presenceSubscription.asObservable()
      .pipe(
        distinctUntilKeyChanged('available')
      )
      .subscribe((presence) => {
        console.log('username1 here now?', presence.available);
      });
  }
});

Streaming Presence For Multiple Users

Similar to above, but returns an array of UserPresenceSubscription objects. You can use the merge operator in RxJs to combine them.

var service = domain.presence();

// Get notified when anything about a presence changes
service.subscribe(['username1', 'username2']).then((subscriptions) => {
  const streams = subscriptions.map((sub) => {return sub.asObservable()});
  Rx.Observable.merge(streams)
    .subscribe((presence) => {
      console.log('Is', presence.username, 'available?', presence.available);
    });
});