Just a second...

Working with session properties

A client session with the appropriate permissions can view, request, or update the session properties of another client session.

Session properties

Each client session has a number of properties associated with it. Properties are keys and values. Both the key and the value are case sensitive. These session properties can be used by other clients to select sets of client session to perform actions on.

For more information, see Session properties.

Receiving notifications of client session events and their session properties

Required permissions:view_session, register_handler

To receive notifications when any client session opens, closes, or is updated, register a session event listener to listen for these events:

JavaScript
const listener = {
    onSessionOpen: (event) => {
        // The action to take on a client session open notification
    },
    onSessionClose: (event) => {
        // The action to take on a client session close notification
    },
    onSessionEvent: (event) => {
        // The action to take on a client session update notification
    },
    onActive: () => {
        // The listener is active
    },
    onClose: () => {
        // The listener is closed
    },
    onError: (err) => {
        // An error occurred
    },
};

// Register a listener for session properties
try {
    await session.clients.setSessionPropertiesListener(diffusion.clients.PropertyKeys.ALL_FIXED_PROPERTIES, listener);
} catch (err) {
    console.log('An error occurred when trying to set the listener');
}
.NET
clientControl.SetSessionPropertiesListener(new SessionPropertiesListener(), string.Empty);


...


/// <summary>
/// The handler for session properties listener notifications.
/// </summary>
private class SessionPropertiesListener : ISessionPropertiesListener
{
    /// <summary>
    /// Called if the handler is closed.
    /// </summary>
    public void OnClose()
    {
        Console.WriteLine($"The listener was closed.");
    }

    /// <summary>
    /// Notification of a contextual error related to this handler.
    /// </summary>
    /// <param name="errorReason"></param>
    public void OnError(ErrorReason errorReason)
    {
        Console.WriteLine($"An error has occured : {errorReason}.");
    }

    /// <summary>
    /// Called when the handler has been successfully registered with the server.
    /// </summary>
    /// <param name="registration"></param>
    public void OnRegistered(IRegistration registration)
    {
        Console.WriteLine($"The listener has been registered.");
    }

    /// <summary>
    /// Notification that a client session has closed.
    /// </summary>
    /// <param name="sessionId"></param>
    /// <param name="properties"></param>
    /// <param name="closeReason"></param>
    public void OnSessionClose(ISessionId sessionId, IDictionary<string, string> properties, CloseReason closeReason)
    {
        Console.WriteLine($"Session with id '{sessionId}' has been closed.");
    }

    /// <summary>
    /// Notification of a session event that can result in a change of properties.
    /// </summary>
    /// <param name="sessionId"></param>
    /// <param name="eventType"></param>
    /// <param name="properties"></param>
    /// <param name="previousValues"></param>
    public void OnSessionEvent(ISessionId sessionId, SessionPropertiesListenerEventType? eventType, IDictionary<string, string> properties, IDictionary<string, string> previousValues)
    {
        if (eventType.HasValue)
        {
            Console.WriteLine($"Session with id '{sessionId}' was {eventType.Value}.");
        }
    }

    /// <summary>
    /// Notification that a new client session has been opened.
    /// </summary>
    /// <param name="sessionId"></param>
    /// <param name="properties"></param>
    public void OnSessionOpen(ISessionId sessionId, IDictionary<string, string> properties)
    {
        Console.WriteLine($"Session with id '{sessionId}' has been opened.");
    }
}
Java and Android
final Registration registration =
session.feature(ClientControl.class).addSessionEventListener(
    new ClientControl.SessionEventStream.Default() {
        @Override
        public void onSessionEvent(Event event) {
            System.out.println(event);
        }
    },
    Diffusion.newSessionEventParametersBuilder()
        .properties(Session.ALL_FIXED_PROPERTIES)
        .filter("$Principal NE 'admin'")
        .build()).get(10, TimeUnit.SECONDS);
C
static int on_registered(
        SESSION_T *session,
        void *context)
{
        // session properties listener has been registered
        return HANDLER_SUCCESS;
}


static int on_registration_error(
        SESSION_T *session,
        const DIFFUSION_ERROR_T *error)
{
        // an error has occurred while registering the
        // session properties listener
        return HANDLER_SUCCESS;
}


static int on_session_open(
        SESSION_T *session,
        const SESSION_PROPERTIES_EVENT_T *event,
        void *context)
{
        // a new session has connected
        return HANDLER_SUCCESS;
}


static int on_session_close(
        SESSION_T *session,
        const SESSION_PROPERTIES_EVENT_T *event,
        void *context)
{
        // a session has closed
        return HANDLER_SUCCESS;
}


static int on_session_update(
        SESSION_T *session,
        const SESSION_PROPERTIES_EVENT_T *event,
        void *context)
{
        // a session has updated its session properties
        return HANDLER_SUCCESS;
}


void register_session_properties_listener(SESSION_T *session) {

        /*
         * Register a session properties listener.
         *
         * Requests all "fixed" properties, i.e. those defined by
         * Diffusion rather than user-defined properties.
         */
        SET_T *required_properties = set_new_string(5);
        set_add(required_properties, PROPERTIES_SELECTOR_ALL_FIXED_PROPERTIES);

        // Set the parameters to callbacks previously defined
        SESSION_PROPERTIES_REGISTRATION_PARAMS_T params = {
                .on_registered = on_registered,
                .on_registration_error = on_registration_error,
                .on_session_open = on_session_open,
                .on_session_close = on_session_close,
                .on_session_update = on_session_update,
                .required_properties = required_properties
        };
        session_properties_listener_register(session, params);
        set_free(required_properties);
}
Apple
class SessionPropertiesHandler: PTDiffusionSessionPropertiesDelegate {
    func diffusionSessionPropertiesListenerRegistration(_ registration: PTDiffusionSessionPropertiesListenerRegistration,
                                                        sessionOpened sessionId: PTDiffusionSessionId,
                                                        withProperties properties: [String : Any]) {
        print("Session %@ has been opened with the following properties: %@",
              sessionId,
              properties)
    }

    func diffusionSessionPropertiesListenerRegistration(_ registration: PTDiffusionSessionPropertiesListenerRegistration,
                                                        sessionClosed sessionId: PTDiffusionSessionId,
                                                        with closeReason: PTDiffusionCloseReason,
                                                        andProperties properties: [String : Any]) {
        print("Session %@ has been closed due to %@ with the following properties: %@",
              sessionId,
              closeReason,
              properties)
    }

    func diffusionSessionPropertiesListenerRegistration(_ registration: PTDiffusionSessionPropertiesListenerRegistration,
                                                        sessionUpdated sessionId: PTDiffusionSessionId,
                                                        withProperties properties: [String : Any]) {
        print("Session %@ has had its session properties updated: %@",
              sessionId,
              properties)
    }

    func diffusionSessionPropertiesListenerRegistration(_ registration: PTDiffusionSessionPropertiesListenerRegistration,
                                                        sessionDisconnected sessionId: PTDiffusionSessionId,
                                                        withProperties properties: [String : Any]) {
        print("Session %@ has disconnected with the following properties: %@",
              sessionId,
              properties)
    }

    func diffusionSessionPropertiesListenerRegistration(_ registration: PTDiffusionSessionPropertiesListenerRegistration,
                                                        sessionReconnected sessionId: PTDiffusionSessionId,
                                                        withProperties properties: [String : Any]) {
        print("Session %@ has reconnected with the following properties: %@",
              sessionId,
              properties)
    }

    func diffusionSessionPropertiesListenerRegistration(_ registration: PTDiffusionSessionPropertiesListenerRegistration,
                                                        sessionFailedOver sessionId: PTDiffusionSessionId,
                                                        withProperties properties: [String : Any]) {
        print("Session %@ has failed over with the following properties: %@",
              sessionId,
              properties)
    }

    func diffusionSessionPropertiesListenerRegistrationDidClose(_ registration: PTDiffusionSessionPropertiesListenerRegistration) {
        print("Session Properties Listener has been closed")
    }

    func diffusionSessionPropertiesListenerRegistration(_ registration: PTDiffusionSessionPropertiesListenerRegistration,
                                                        didFailWithError error: Error) {
        print("Session Properties Listener failed with error: %@",
              error.localizedDescription)
    }
}

// create a handler to receive the session properties related events
let handler = SessionPropertiesHandler();
let properties = [PTDiffusionSession.allFixedProperties()]

session.clientControl.addSessionPropertiesListener(handler,
                                                   forProperties: properties) { (registration, error) in
    if (error != nil) {
        print("An error occurred while adding the session properties listener: %@",
              error!.localizedDescription)
    }
    else {
        print("Session properties listener has been successfully registered")
    }
}

The listener will be notified of all sessions that satisfy the requirements indicated by the supplied parameters. If the client is connected to a Diffusion cluster, sessions at all nodes within the cluster will be notified to the listener.

The parameters can stipulate which session properties are required, which sessions are required (according to a session filter), and whether only sessions that start(ed) after a specified time are to be notified.

If no start time is specified then state events will be notified for all sessions that are currently connected immediately upon adding the listener. If there are a large number of connected sessions this may cause a significant amount of network traffic when the listener is first added.

The event delivered may indicate a change in the session state, or a change to the session properties. The property values delivered will be those requested in the parameters. When a session is closed, the event will also indicate the reason it was closed. For more details see the API documentation.

A client may add any number of listeners, with different parameters, but users should be cognisant of the amount of network traffic (and intra cluster traffic) that such events may cause.

When a listener is no longer required it may be closed using the registration returned when adding it.

Getting properties of specific client sessions

Required permissions: view_session

A client can make an asynchronous request the session properties of any client session from Diffusion™ Cloud , providing the requesting client knows the session ID of the target client.

JavaScript
// Get fixed session properties
const properties = await session.clients.getSessionProperties(sessionID, diffusion.clients.PropertyKeys.ALL_FIXED_PROPERTIES);
.NET
Console.WriteLine($"Session with id '{session.SessionId}' created.");

var requiredProperties = new List<string> { SessionProperty.ALL_FIXED_PROPERTIES, SessionProperty.ALL_USER_PROPERTIES };

try
{
    await clientControl.GetSessionPropertiesAsync(session.SessionId, requiredProperties);
}
catch (Exception ex)
{
    Console.WriteLine($"Failed to get properties of session with id '{session.SessionId}' : {ex}.");
}
Java and Android
// Get fixed session properties
final ClientControl clientControl = session.feature(ClientControl.class);

clientControl.getSessionProperties(
    session.getSessionId(),
    Collections.singleton(Session.ALL_FIXED_PROPERTIES)
);
C
static int on_session_properties(
        SESSION_T *session,
        const SVC_GET_SESSION_PROPERTIES_RESPONSE_T *response,
        void *context)
{
        // read the received session properties in response->properties
        return HANDLER_SUCCESS;
}


void get_session_properties_session_id(SESSION_T *session, SESSION_ID_T *session_id)
{
        SET_T *selected_properties = set_new(1);
        set_add(selected_properties, PROPERTIES_SELECTOR_ALL_FIXED_PROPERTIES);

        GET_SESSION_PROPERTIES_PARAMS_T params = {
                .on_session_properties = on_session_properties,
                .session_id = session_id,
                .required_properties = selected_properties
        };

        get_session_properties(session, params);
        set_free(selected_properties);
}
Apple
let properties = [PTDiffusionSession.allFixedProperties()]

session.clientControl.getSessionProperties(properties,
                                           forSession: sessionId) { (result, error) in
    if (error != nil) {
        print("An error has occurred while retrieving the session properties of session '%@': %@",
              sessionId,
              error!.localizedDescription)
    }
    else
    {
        print("Received the following session properties for session '%@': %@", sessionId, result!.properties);

    }
}

Update the properties of specific client sessions

Required permissions:view_session, modify_session

A client session with the appropriate permissions can update the value of existing user-defined session properties or add new user-defined properties for any client session or set of client sessions.

As part of the update session properties request, provide a map of the keys for the session properties you want to update or add and the new values. If you provide a null value for a session property, that property is deleted from the session. A successful update session properties request returns a map of the updated properties and their old values.

Specify a single session to change the user-defined session properties for the session by providing the session ID.

JavaScript
const newProperties = await session.clients.setSessionProperties(sessionID, { PROPERTY: 'value'});
.NET
WriteLine($"Session with id '{session.SessionId}' created.");

Dictionary<string, string> properties = new Dictionary<string, string> { { "$Latitude", "51.509865" } };

try
{
    var changedProperties = await clientControl.SetSessionPropertiesAsync(session.SessionId, properties);

    foreach (var changedProperty in changedProperties)
    {
        var value = string.IsNullOrEmpty(changedProperty.Value) ? "[not set]" : $"'{changedProperty.Value}'";
        WriteLine($"Session property {changedProperty.Key} changed from {value} to '{properties[changedProperty.Key]}'");
    }
}
catch (Exception ex)
{
    WriteLine($"Failed to set properties of session with id '{session.SessionId}' : {ex}.");
}
Java and Android
// Change the session properties of a single session
final ClientControl clientControl = session.feature(ClientControl.class);

clientControl.setSessionProperties(
    session.getSessionId(),
    Collections.singletonMap("$Country", "CA")
);
C
static int on_session_properties_set(
        const HASH_T *properties,
        void *context)
{
        // ...
        return HANDLER_SUCCESS;
}


void set_session_properties(SESSION_T *session, SESSION_ID_T *session_id)
{
        HASH_T *properties = hash_new(1);
        hash_add(properties, strdup("foo"), strdup("bar"));

        DIFFUSION_SET_SESSION_PROPERTIES_PARAMS_T params = {
                .session_id = session_id,
                .properties = properties,
                .on_session_properties_set = on_session_properties_set
        };

        diffusion_set_session_properties(session, params, NULL);
        hash_free(properties, free, free);
}
Apple
let properties = ["property": "value"]

session.clientControl.setSessionProperties(properties, forSession: sessionId) { (result, error) in
    if (error != nil) {
        print("An error has occurred while setting the session properties of session '%@': %@",
              sessionId,
              error!.localizedDescription)
    }
    else {
        print("Session properties of session '%@' have been successfully set", sessionId)
        print("The following properties have been added: %@", result!.addedProperties)
        print("The following properties have been changed: %@", result!.changedProperties)
    }
}

Specify a set of client sessions to change the user-defined session properties for by providing a filter query expression. For more information about filter query expressions, see Session filtering.

JavaScript
const numSessionsAffected = await session.clients.setSessionPropertiesByFilter(filter, { PROPERTY: 'value'});
.NET
Dictionary<string, string> properties = new Dictionary<string, string> { { "$Latitude", "-51.509865" } };

WriteLine($"Changing session property $Latitude to '-51.509865'.");

var numberOfChangedProperties = await clientControl.SetSessionPropertiesAsync("$Latitude is '51.509865'", properties);
WriteLine($"Number of session properties changed: {numberOfChangedProperties}.");
Java and Android
// Change the session properties of set of sessions defined by a filter expression
final ClientControl clientControl = session.feature(ClientControl.class);

clientControl.setSessionProperties(
    "$Principal is 'client'",
    Collections.singletonMap("$Country", "CA")
);
// all sessions with the principal 'client' will have their properties set
C
static int on_session_properties_set_filter(
        const int number_of_matching_sessions,
        void *context)
{
        // ...
        return HANDLER_SUCCESS;
}


void set_session_properties_filter(SESSION_T *session, char *session_filter)
{
        HASH_T *properties = hash_new(1);
        hash_add(properties, strdup("foo"), strdup("bar"));

        DIFFUSION_SET_SESSION_PROPERTIES_FILTER_PARAMS_T params = {
                .filter = session_filter,
                .properties = properties,
                .on_session_properties_set = on_session_properties_set_filter
        };

        diffusion_set_session_properties_filter (session, params, NULL);
        hash_free(properties, free, free);
}
Apple
let properties = ["property": "value"]

session.clientControl.setSessionProperties(properties, usingFilter: filter) { (selected_sessions, error) in
    if (error != nil) {
        print("An error has occurred while setting the session properties using the filter '%@': %@",
              filter,
              error!.localizedDescription)
    }
    else {
        print("Session properties have been successfully set, affecting %lu sessions", selected_sessions)
    }
}