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 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 ClientControl clientControl = session.feature(ClientControl.class);

clientControl.setSessionPropertiesListener(new ClientControl.SessionPropertiesStream() {
    @Override
    public void onSessionOpen(SessionId sessionId,
        Map<String, String> properties) {
        // The action to take on a client session open notification
    }

    @Override
    public void onSessionEvent(SessionId sessionId,
        EventType eventType, Map<String, String> properties,
        Map<String, String> previousValues) {
        // The action to take on a client session update notification
    }

    @Override
    public void onSessionClose(SessionId sessionId,
        Map<String, String> properties,
        ClientControl.CloseReason closeReason) {
        // The action to take on a client session close notification
    }

    @Override
    public void onError(ErrorReason errorReason) { }

    @Override
    public void onClose() { }
},
    // The session properties to receive
    "$Country", "$Department");
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")
    }
}

When registering this listener, specify which session properties to receive for each client session:

JavaScript
// Receive all fixed properties
await session.clients.setSessionPropertiesListener(diffusion.clients.PropertyKeys.ALL_FIXED_PROPERTIES, listener);
// OR
// Receive all user-defined properties
await session.clients.setSessionPropertiesListener(diffusion.clients.PropertyKeys.ALL_USER_PROPERTIES, listener);
// OR
// Receive all properties
await session.clients.setSessionPropertiesListener([
    ...diffusion.clients.PropertyKeys.ALL_FIXED_PROPERTIES,
    ...diffusion.clients.PropertyKeys.ALL_USER_PROPERTIES
], listener);
.NET
var requiredProperties = new List<string> { "$Country", "Department", SessionProperty.ALL_FIXED_PROPERTIES, SessionProperty.ALL_USER_PROPERTIES };

clientControl.SetSessionPropertiesListener(new SessionPropertiesListener(), requiredProperties.ToArray());


...


/// <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 ClientControl clientControl = session.feature(ClientControl.class);

clientControl.setSessionPropertiesListener(
    new ClientControl.SessionPropertiesStream.Default() {
        // Define callbacks
    },
    "$Country", "$Department");
// OR
// Receive all fixed properties
clientControl.setSessionPropertiesListener(
    new ClientControl.SessionPropertiesStream.Default() {
        // Define callbacks
    },
    Session.ALL_FIXED_PROPERTIES);
// OR
// Receive all user-defined properties
clientControl.setSessionPropertiesListener(
    new ClientControl.SessionPropertiesStream.Default() {
        // Define callbacks
    },
    Session.ALL_USER_PROPERTIES);
C
// Receive all fixed properties
SET_T *all_fixed_properties = set_new_string(5);
set_add(all_fixed_properties, PROPERTIES_SELECTOR_ALL_FIXED_PROPERTIES);

GET_SESSION_PROPERTIES_PARAMS_T all_fixed_params = {
        // ...
        .session_id = session_id,
        .required_properties = all_fixed_properties
};
get_session_properties(session, all_fixed_params);

// OR
// Receive all user-defined properties
SET_T *used_defined_properties = set_new_string(5);
set_add(used_defined_properties, PROPERTIES_SELECTOR_ALL_USER_PROPERTIES);

GET_SESSION_PROPERTIES_PARAMS_T user_defined_params = {
        // ...
        .session_id = session_id,
        .required_properties = used_defined_properties
};
get_session_properties(session, user_defined_params);

// OR
// Receive all properties
SET_T *all_properties = set_new_string(5);
set_add(all_properties, PROPERTIES_SELECTOR_ALL_FIXED_PROPERTIES);
set_add(all_properties, PROPERTIES_SELECTOR_ALL_USER_PROPERTIES);

GET_SESSION_PROPERTIES_PARAMS_T all_properties_params = {
        // ...
        .session_id = session_id,
        .required_properties = all_properties
};
get_session_properties(session, all_properties_params);
Apple
// Receive all fixed properties
let all_fixed_properties = [PTDiffusionSession.allFixedProperties()]

session.clientControl.addSessionPropertiesListener(handler,
                                                   forProperties: all_fixed_properties) { (registration, error) in
    //...
}
// OR
// Receive all user-defined properties
let all_user_defined_properties = [PTDiffusionSession.allUserProperties()]

session.clientControl.addSessionPropertiesListener(handler,
                                                   forProperties: all_user_defined_properties) { (registration, error) in
    //...
}
// OR
// Receive all properties
let all_properties = [PTDiffusionSession.allFixedProperties(), PTDiffusionSession.allUserProperties()]

session.clientControl.addSessionPropertiesListener(handler,
                                                   forProperties: all_properties) { (registration, error) in
    //...
}

When the listening client first registers a listener, it receives a notification for every client session that is currently open. When subsequent client sessions open, the listening client receives a notification for those clients.

When the listening client is notified of a session event, it receives the requested session properties as a map of keys and values.

When the listening client is notified of a session closing, it also receives the reason that the session was closed. If the client session becomes disconnected from the Diffusion™ server , the listener might not receive notification of session close immediately. If reconnection is configured for the client, when the client disconnects, its session goes into reconnecting state for the configured time (the default is 60 seconds) before going into a closed state.

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 the Diffusion server , 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.

If you have a cluster of Diffusion servers, requests specifying a session ID can be routed to the server within the cluster which hosts that session.

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.

If you have a cluster of Diffusion servers, the change of session properties will be applied to sessions which match the filter on all servers within the cluster.

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)
    }
}