6. Reading Data (Input)

6.1. Getting the input

To read/take samples, first get a reference to the Input():

input = connector.getInput('MySubscriber::MySquareReader')

Connector.getInput() returns an Input() object. This example, obtains the Input defined by the data_reader named MySquareReader within the <subscriber> named MySubscriber:

<subscriber name="MySubscriber">
  <data_reader name="MySquareReader" topic_ref="Square" />
</subscriber>

This <subscriber> is defined inside the <domain_participant> selected to create this connector (see Creating a new Connector).

6.2. Reading or taking the data

Call Input.take() to access and remove the samples:

input.take()

or Input.read() to access the samples but leave them available for a future read() or take():

input.read()

The method Input.wait() can be used to identify when there is new data available on a specific Input(). It returns a Promise that will be resolved when new data is available, or rejected if the supplied timeout expires.

You can wait for the Promise using await in an async function:

await input.wait()
input.take()

Or using the then method:

input.wait()
  .then(() => {
    input.take()
  })

The method Connector.wait() has the same behavior as Input.wait(), but the returned promise will be resolved when data is available on any of the Input() objects within the Connector():

await connector.wait()

You can also install a listener in a Connector(). Connector() inherits from EventEmitter. If a listener for the on_data_available event is attached to a Connector(), this event will be emitted whenever new data is available on any Input defined within the :class:`Connector().

// Store all the inputs in an array
const inputs = [
  connector.getInput('MySubscriber::MySquareReader'),
  connector.getInput('MySubscriber::MyCircleReader'),
  connector.getInput('MySubscriber::MyTriangleReader')
]

// Install the listener
connector.on('on_data_available', () => {
  // One or more inputs have data
  inputs.forEach(input => {
    input.take()
    for (const sample of input.samples.validDataIter) {
      // Access the data
    }
  }
})

For more information on how to use the event-based notification, refer to the documentation of the events module.

The web_socket example shows how to use this event.

Warning

There are additional threading concerns to take into account when using the on_data_available event. Refer to Additional considerations when using event-based functionality for more information.

Note

When using the event-based methods to be notified of available data, errors are propagated using the error event. See Error Handling for more information.

6.3. Accessing the data samples

After calling Input.read() or Input.take(), Input.samples contains the data samples:

for (const sample of input.samples) {
   if (sample.validData) {
      console.log(JSON.stringify(sample.getJson()))
   }
}

SampleIterator.getJson() retrieves all the fields of a sample.

If you don’t need to access the meta-data (see Accessing sample meta-data), the simplest way to access the data is to use Samples.validDataIter to skip samples with invalid data:

for (const sample of input.samples.validDataIter) {
   // It is not necessary to check the sample.validData field
   console.log(JSON.stringify(sample.getJson()))
}

It is also possible to access an individual sample:

// Obtain the first sample in the Input's queue
const theSample = input.samples.get(0)
if (theSample.validData) {
   console.log(JSON.stringify(theSample.getJson()))
}

Both of the iterables shown above also provide iterator implementations, allowing them to be incremented outside of a for loop:

const iterator = input.samples.validDataIter.iterator()
let sample = iterator.next()
// sample.value contains contains the current sample and sample.done is a
// boolean value which will become true when we have iterated over all of
// the available samples
console.log(JSON.stringify(sample.value.getJson()))

Warning

All the methods described in this section return generators. Calling read/take again invalidates all generators currently in use.

Samples.getJson() can receive a fieldName to only return the fields of a complex member. In addition to getJson, you can get the values of specific primitive fields using SampleIterator.getNumber(), SampleIterator.getBoolean() and SampleIterator.getString(), for example:

for (const sample of input.samples.validDataIter) {
   const x = sample.getNumber('x')
   const y = sample.getNumber('y')
   const size = sample.getNumber('shapesize')
   const color = sample.getString('color')
}

See more information and examples in Accessing the data.

6.4. Accessing sample meta-data

Every sample contains an associated SampleInfo with meta-information about the sample:

for (const sample of input.samples) {
   const sourceTimestamp = sample.info.get('source_timestamp')
}

See SampleIterator.info for the list of available meta-data fields.

Connext DDS can produce samples with invalid data, which contain meta-data only. For more information about this, see Valid Data Flag in the RTI Connext DDS Core Libraries User’s Manual. These samples indicate a change in the instance state. Samples with invalid data still provide the following information:

  • The SampleInfo()

  • When an instance is disposed (sample.info.get('instance_state') is 'NOT_ALIVE_DISPOSED'), the sample data contains the value of the key that has been disposed. You can access the key fields only. See Accessing key values of disposed samples.

6.5. Matching with a publication

The method Input.waitForPublications() can be used to detect when a compatible DDS publication is matched or unmatched. It returns a promise that resolves to the change in the number of matched publications since the last time it was called:

// From within an async function. Otherwise, use the .then() syntax
let changeInMatches = await input.waitForPublications()

For example, if 1 new compatible publication is discovered within the specified timeout, the promise will resolve to 1; if a previously matching publication no longer matches, it resolves to -1.

You can obtain information about the existing matched publications through the Input.matchedPublications property:

input.matchedPublications.forEach((match) => {
   pubName = match.name
}

6.6. Class reference: Input, Samples, SampleIterator

6.6.1. Input class

class Input(connector, name)

Allows reading data for a DDS Topic.

This class is used to subscribe to a specific DDS Topic.

To get an Input object, use Connector.getInput().

Attributes:
  • connector (Connector()) - The Connector creates this Input.

  • name (string) - The name of the Input (the name used in Connector.getInput()).

  • native (pointer) - A native handle that allows accessing additional Connext DDS APIs in C.

  • matchedPublications (JSON) - A JSON object containing information about all the publications currently matched with this Input.

Input.matchedPublications

type: JSON

Returns information about matched publications.

This property returns a JSON array, with each element of the array containing information about a matched publication.

Currently the only information contained in this JSON object is the publication name of the matched publication. If the matched publication doesn’t have a name, the name for that specific publication will be null.

Note that Connector() Outputs are automatically assigned a name from the data_writer name element in the XML configuration.

Input.samples

type: Samples

Allows iterating over the samples returned by this input.

This container provides iterators to access the data samples retrieved by the most-recent call to Input.take() and Input.read().

Input.read()

Accesses the samples received by this Input.

This operation performs the same operation as Input.take() but the samples remain accessible (in the internal queue) after the operation has been called.

Input.take()

Accesses the samples receieved by this Input.

After calling this method, the samples are accessible using Input.samples().

Input.wait(timeout)

Wait for this Input to receive data.

Note

This operation is asynchronous.

Arguments:
  • timeout (number) – The maximum time to wait, in milliseconds. By default, infinite.

Throws:

TimeoutErrorTimeoutError() will be thrown if the timeout expires before data is received.

Returns:

Promise – A Promise which will be resolved once data is available, or rejected if the timeout expires.

Input.waitForPublications(timeout)

Waits for this Input to match or unmatch a compatible DDS Subscription.

Note

This operation is asynchronous.

This method waits for the specified timeout (or if no timeout is specified, it waits forever), for a match (or unmatch) to occur.

Arguments:
  • timeout (number) – The maximum time to wait, in milliseconds. By default, infinite.

Throws:

TimeoutErrorTimeoutError() will be thrown if the timeout expires before any publications are matched.

Returns:

Promise – Promise object resolving with the change in the current number of matched outputs. If this is a positive number, the input has matched with new publishers. If it is negative, the input has unmatched from an output. It is possible for multiple matches and/or unmatches to be returned (e.g., 0 could be returned, indicating that the input matched the same number of outputs as it unmatched).

6.6.2. Samples class

class Samples(input)

Provides access to the data samples read by an Input().

This class provides access to data samples read by an Input() (using either the Input.read() or Input.take() methods).

This class implements a [Symbol.iterator]() method, making it an iterable. This allows it to be used in for... of loops, to iterate through available samples:

for (const sample of input.samples) {
   console.log(JSON.stringify(sample.getJson()))
}

The method Samples.get() returns a SampleIterator() which can also be used to access available samples:

const sample = input.samples.get(0)
console.log(JSON.stringify(sample.getJson()))

The samples returned by these methods may only contain meta-data (see SampleIterator.info). The Samples.validDataIter iterable only iterates over samples that contain valid data (a ValidSampleIterator()).

Samples() and ValidSampleIterator() both also provide generators to the samples, allowing applications to define their own iterables (see Samples.iterator() and ValidSampleIterator.iterator()).

Samples is the type of the property Input.samples().

For more information and examples, see Accessing the data samples.

Attributes:
  • length (number) - The number of samples available since the last time Input.read() or Input.take() was called.

  • validDataIter (ValidSampleIterator()) - The class used to iterate through the available samples that have valid data.

Samples.length

The number of samples available.

Samples.validDataIter

Returns an iterator to the data samples that contain valid data.

The iterator provides access to all the data samples retrieved by the most recent call to Input.read() or Input.take(), and skips samples with invalid data (meta-data only).

By using this iterator, it is not necessary to check if each sample contains valid data.

Samples.get(index)

Returns an iterator to the data samples, starting at the index specified.

The iterator provides access to all the data samples retrieved by the most recent call to Input.read() or Input.take().

This iterator may return samples with invalid data (samples that only contain meta-data). Use Samples.validDataIter to avoid having to check SampleIterator.validData.

Arguments:
  • index (number) – The index of the sample from which the iteration should begin. By default, the iterator begins with the first sample.

Returns:

SampleIterator() - An iterator to the samples (which implements both iterable and iterator logic).

Samples.getBoolean(index, fieldName)

Obtains the value of a boolean field within this sample.

See Accessing the data samples.

Arguments:
  • index (number) – The index of the sample.

  • fieldName (string) – The name of the field.

Returns:

number – The obtained value.

Samples.getJson(index, memberName)

Gets a JSON object with the values of all the fields of this sample.

Arguments:
  • index (number) – The index of the sample.

  • memberName (string) – The name of the complex member. The type of the member with name memberName must be an array, sequence, struct, value or union.

Returns:

JSON – The obtained JSON object. See Accessing the data samples.

Samples.getNative(index)

Obtains a native handle to the sample, which can be used to access additional Connext DDS APIs in C.

Arguments:
  • index (number) – The index of the sample for which to obtain the native pointer.

Returns:

pointer – A native pointer to the sample.

Samples.getNumber(index, fieldName)

Obtains the value of a numeric field within this sample.

See Accessing the data samples.

Arguments:
  • index (number) – The index of the sample.

  • fieldName (string) – The name of the field.

Returns:

number – The obtained value.

Samples.getString(index, fieldName)

Obtains the value of a string field within this sample.

See Accessing the data samples.

Arguments:
  • index (number) – The index of the sample.

  • fieldName (string) – The name of the field.

Returns:

string – The obtained value.

Samples.getValue(fieldName)

Gets the value of a field within this sample.

See Accessing the data samples.

This API can be used to obtain strings, numbers, booleans and the JSON representation of complex members.

Arguments:
  • fieldName (string) – The name of the field.

Returns:

number|string|boolean|JSON – The value of the field.

Samples.iterator()

The iterator generator (used by the iterable).

This method returns a generator, which must be incremented manually by the application (using the iterator.next() method).

Once incremented, the data can be accessed via the .value attribute. Once no more samples are available, the .done attribute will be true.

Using this method, it is possible to create your own iterable:

const iterator = input.samples.iterator()
const singleSample = iterator.next().value

6.6.3. SampleIterator class

class SampleIterator(input, index)

Iterates and provides access to a data sample.

A SampleIterator provides access to the data receieved by an Input().

The Input.samples attribute implements a SampleIterator(), meaning it can be iterated over. An individual sample can be accessed using Input.samples.get().

See ValidSampleIterator().

This class provides both an iterator and iterable, and is used internally by the Samples() class. The following options to iterate over the samples exist:

// option 1 - The iterable can be used in for...of loops
for (const sample of input.samples)
// option 2 - Returns an individual sample at the given index
const individualSample = input.samples.get(0)
// option 3 - Returns a generator which must be incremented by the application
const iterator = input.samples.iterator()
Arguments:
  • validData (boolean) – Whether or not the current sample contains valid data.

  • infos (SampleInfo) – The meta-data associated with the current sample.

  • native (pointer) – A native handle that allows accessing additional Connext DDS APIs in C.

SampleIterator.info

Provides access to this sample’s meta-data.

The info property expects one of the SampleInfo() field names:

const value = sample.info.get('field')

The supported field names are:

  • 'source_timestamp' returns an integer representing nanoseconds

  • 'reception_timestamp' returns an integer representing nanoseconds

  • 'sample_identity' or 'identity' returns a JSON object (see Output.write())

  • 'related_sample_identity' returns a JSON object (see Output.write())

  • 'valid_data' returns a boolean (equivalent to SampleIterator.validData)

  • 'view_state', returns a string (either “NEW” or “NOT_NEW”)

  • 'instance_state', returns a string (one of “ALIVE”, “NOT_ALIVE_DISPOSED” or “NOT_ALIVE_NO_WRITERS”)

  • 'sample_state', returns a string (either “READ” or “NOT_READ”)

These fields are documented in The SampleInfo Structure section in the RTI Connext DDS Core Libraries User’s Manual.

See SampleInfo().

SampleIterator.validData

type: boolean

Whether or not this sample contains valid data.

If false, the methods to obtain values of the samples (e.g., SampleIterator.getNumber(), SampleIterator.getBoolean(), SampleIterator.getJson(), SampleIterator.getString()) should not be called. To avoid this restraint, use a ValidSampleIterator().

SampleIterator.get(fieldName)

Gets the value of a field within this sample.

This API can be used to obtain strings, numbers, booleans and the JSON representation of complex members.

Arguments:
  • fieldName (string) – The name of the field.

Returns:

number|string|boolean|JSON – The value of the field.

SampleIterator.getBoolean(fieldName)

Gets the value of a boolean field in this sample.

Arguments:
  • fieldName (string) – The name of the field.

Returns:

boolean – The boolean value of the field.

SampleIterator.getJson(memberName)

Returns a JSON object with the values of all the fields of this sample.

See Accessing the data samples.

Arguments:
  • memberName (string) – The name of the complex member or field to obtain.

Returns:

JSON – The obtained JSON object.

SampleIterator.getNumber(fieldName)

Gets the value of a numeric field in this sample.

Note

This operation should not be used with values with an aboslute value larger than Number.MAX_SAFE_INTEGER. See Accessing 64-bit integers for more information.

Arguments:
  • fieldName (string) – The name of the field.

Returns:

number – The numeric value of the field.

SampleIterator.getString(fieldName)

Gets the value of a string field in this sample.

Arguments:
  • fieldName (string) – The name of the field.

Returns:

string – The string value of the field.

6.6.4. ValidSampleIterator class

class ValidSampleIterator()

Iterates and provides access to data samples with valid data.

This iterator provides the same methods as SampleIterator(). It can be obtained using Input.samples.validDataIter.

ValidSampleIterator.iterator()

The iterator generator (used by the iterable).

Using this method, it is possible to create your own iterable:

const iterator = input.samples.validDataIter.iterator()
const singleSample = iterator.next().value

6.6.5. SampleInfo class

class SampleInfo(input, index)

The type returned by the property SampleIterator.info().

This class provides a way to access the SampleInfo of a received data sample.

SampleInfo.get(fieldName)

Type-independent function to obtain any value from the SampleInfo structure.

The supported fieldNames are:

  • 'source_timestamp' returns an integer representing nanoseconds

  • 'reception_timestamp' returns an integer representing nanoseconds

  • 'sample_identity' or 'identity' returns a JSON object (see Output.write())

  • 'related_sample_identity' returns a JSON object (see Output.write())

  • 'valid_data' returns a boolean (equivalent to SampleIterator.validData)

These fields are documented in The SampleInfo Structure section in the RTI Connext DDS Core Libraries User’s Manual.

Arguments:
  • fieldName (string) – The name of the SampleInfo field to obtain

Returns:

The obtained value from the SampleInfo structure

Examples:

const source_timestamp = input.samples.get(0).info.get('source_timestamp')