This section covers the following topics:

Writing and Removing State Data

In order to publish data on a state Topic, you need a state writer. Creating a state writer is done using the qeo_factory_create_state_writer() function. This function takes four arguments:

  1. The previously created Qeo factory to be used for creating the writer;

  2. The description of the type for which to create a writer.
  3. The listener to be used for policy update notifications (see C).
  4. An optional user data argument.  The user data will be passed back to the application in all listener callback invocations.
Icon

Creation of a State Writer for a type that does not contain key fields will fail and return NULL because states are required to have key fields.

The Qeo C API offers two functions for publishing data on a state Topic:

  • qeo_state_writer_write() writes a new value for an instance on the Topic. This amounts to either instance creation (you are writing the first sample for this instance) or an update of the instance (the sample you're writing is not the first sample for this instance).

  • qeo_state_writer_remove() removes an instance from the Topic. In this case, only the key fields of the sample are relevant, all other fields are ignored.

Writing and Removing: an Example

The code snippet below shows you how to:

  • Create a state writer for the Topic org_qeo_sample_simplechat_ChatParticipant_t;
  • Actually publish your data samples;
  • Remove the previously published state instances.
#include <qeo/api.h>

#include "QSimpleChat_ChatParticipant.h"

int main(int argc, const char **argv)
{
    qeo_factory_t *qeo;
    qeo_state_writer_t *state_writer;

    /* user's state used for sending */
    org_qeo_sample_simplechat_ChatParticipant_t john = { .name = "John", .state = ORG_QEO_SAMPLE_SIMPLECHAT_CHATSTATE_AWAY };

    /* initialize */
    qeo = qeo_factory_create();
    state_writer = qeo_factory_create_state_writer(qeo, org_qeo_sample_simplechat_ChatParticipant_type,
                                                   NULL, 0);
    /* write John's state */
    qeo_state_writer_write(state_writer, &john);

    while (!done) {
        ...
    }
    /* signal John's departure */
    qeo_state_writer_remove(state_writer, &john);
    /* clean up */
    qeo_state_writer_close(state_writer);
    qeo_factory_close(qeo);
    return 0;
} 

 

Receiving State Data

In order to subscribe to a state Topic, you need a State Reader. There are two flavors of State Readers: iterating and evented.  Both are described below. For more information, refer to the Qeo System Description.

Iterating State Reader

Description

A StateReader allows you to iterate over all instances on a state Topic. For each instance, you will see the most recently published sample. Consider our example type org_qeo_sample_simplechat_ChatParticipant. Let's suppose we have several chat applications running and we want to have a list of available participants. This can simply be done using a StateReader. StateReaders are created by the qeo_factory_create_state_reader() function. This function takes four arguments:

  1. The previously created Qeo factory to be used for creating the reader.

  2. The description of the type for which to create a reader (this should be the same as for the corresponding state writer).

  3. The listener to be used for data sample reception and policy update notifications (see C).

  4. An optional user data argument. The user data will be passed back to the application in all listener callback invocations.

The listener structure, if provided, contains one callback function for data sample reception:

  • the on_update() callback function will be invoked whenever instances are created, updated or removed on the Topic. The on_update() callback does not tell you what changed on the Topic. It is a simple notification that something changed on the Topic, leaving it up to the application developer to iterate over the Topic to find out what changed.
Code Sample

The sample below shows how to use a StateReader for instances of type org_qeo_sample_simplechat_ChatParticipant_t.

 

#include <qeo/api.h>

#include "QSimpleChat_ChatParticipant.h"

static qeo_state_reader_t *_state_reader;

/* This callback will be called when iterating for each chat participant instance. */
static qeo_iterate_action_t print_participant(const void *data,
                                              uintptr_t userdata)
{
    org_qeo_sample_simplechat_ChatParticipant_t *p = (org_qeo_sample_simplechat_ChatParticipant_t *)data;
    char state_name[16];

    /* convert the enumeration value to its string representation */
    qeo_enum_value_to_string(org_qeo_sample_simplechat_ChatParticipant_type, p->state, state_name, sizeof(state_name));
    printf("%s is %s\n", p->name, state_name);
    return QEO_ITERATE_CONTINUE; /* continue with next chatter (if any) */
}

/* This callback will be called whenever a chat participant instance gets updated. */
static void on_data(const qeo_state_reader_t *reader,
                    uintptr_t userdata)
{
    /* We can now start iterating again */
	qeo_state_reader_foreach(_state_reader, print_participant, 0);
}

static qeo_state_reader_listener_t _listener = { .on_update = on_data };

int main(int argc, const char **argv)
{
    qeo_factory_t *qeo;
    int done = 0;

    /* initialize */
    qeo = qeo_factory_create();
    _state_reader = qeo_factory_create_state_reader(qeo, org_qeo_sample_simplechat_ChatParticipant_type,
                                                    &_listener, 0);

    /* start receiving messages */
    while (!done) {
        sleep(60);
    }

    /* clean up */
    qeo_state_reader_close(_state_reader);
    qeo_factory_close(qeo);
    return 0;
}

 

Evented state reader

Description

The evented state reader (in Qeo terms: a StateChangeReader) can be used if you want to be notified of the received samples of the state instances. Consider our example type org_qeo_sample_simplechat_ChatParticipant_t. Let's suppose we have several chat applications running and we want to be notified when a participant's state changes. This can simply be done using an evented state reader. StateChangeReaders are created by the qeo_factory_create_state_change_reader() function. This function takes four arguments:

  1. The previously created Qeo factory to be used for creating the reader.

  2. The description of the type for which to create a reader (this should be the same as for the corresponding state writer).

  3. The listener to be used for data sample reception and policy update notifications (see C).

  4. An optional user data argument. The user data will be passed back to the application in all listener callback invocations.

The listener structure contains three callback functions for data sample reception:

  • (conditionally required) the on_data() callback function that will be called whenever there is new data available (in our example of the type org_qeo_sample_simplechat_ChatParticipant_t);

  • (conditionally required) the on_remove() callback function that will be called whenever an instance has been removed by the state writer;

  • (optional) the on_no_more_data() callback function that will be called if all received data has been notified to the application and there is no more data at this moment.

Note that either the on_data() callback or the on_remove() callback is required.  Both are allowed, but at least one of them has to be provided.

Code Sample

The sample below shows how to use a state reader for instances of the type org_qeo_sample_simplechat_ChatParticipant_t:

 

#include <qeo/api.h>

#include "QSimpleChat_ChatParticipant.h"

/* This callback will be called whenever a chat participant instance gets updated. */
static void on_state_data(const qeo_state_change_reader_t *reader,
                          const void *data,
                          uintptr_t userdata)
{
    org_qeo_sample_simplechat_ChatParticipant_t *p = (org_qeo_sample_simplechat_ChatParticipant_t *)data;

    if (0 == strcmp(p->name, "MyBestFriend") {
        char state_name[16];

        /* convert the enumeration value to its string representation */
        qeo_enum_value_to_string(org_qeo_sample_simplechat_ChatParticipant_type, p->state, state_name, sizeof(state_name));
        printf("New state of best friend: %s\n", state_name);
    }
}

/* This callback will be called whenever a chat state instance gets removed. */
static void on_state_remove(const qeo_state_change_reader_t *reader,
                            const void *data,
                            uintptr_t userdata)
{
    org_qeo_sample_simplechat_ChatParticipant_t *p = (org_qeo_sample_simplechat_ChatParticipant_t *)data;

	if (0 == strcmp(p->name, "MyBestFriend") {
        printf("Time to go to sleep, nobody to talk to anymore.\n");
    }
}

static qeo_state_change_reader_listener_t _listener = {
    .on_data = on_state_data,
    .on_remove = on_state_remove,
};

int main(int argc, const char **argv)
{
    qeo_factory_t *qeo;
    qeo_state_change_reader_t *state_reader;
    int done = 0;

    /* initialize */
    qeo = qeo_factory_create();
    state_reader = qeo_factory_create_state_change_reader(qeo, org_qeo_sample_simplechat_ChatParticipant_type,
                                                          &_listener, 0);

    /* start receiving messages */
    while (!done) {
        sleep(60);
    }

    /* clean up */
    qeo_state_change_reader_close(state_reader);
    qeo_factory_close(qeo);
    return 0;
}

Cleaning up Resources - Closing readers and Writers

Whenever you are done with a reader or a writer you must close it by explicitly calling the qeo_event_reader_close() or qeo_event_writer_close() function respectively. This will release any resources associated with it. Readers and Writers must be closed before the Qeo Factory is closed. Failing to do so can lead to crashes and other problems. Make sure to close all Readers and Writers at all times.