Transporters

November 3, 2016 ยท View on GitHub

About

In the IOTDB "worldview", Things are modelled as a collection of JSON dictionaries, called Bands. If you have all the Bands of a Thing, you have a complete representation of the Thing.

Typical Bands are:

  • model the semantic model that explains the istate and ostate Bands
  • istate the input state, that is the current state of a Thing
  • ostate the output state, the state we want a Thing to transition to
  • meta the Thing's metadata, e.g. its name, its manufacturer
  • connection the Thing's connection status

A Transporter is a collection of all the Band data for some group of Things. Note that though transporters don't use these Thing objects, it's really easy to create Things from transporters using all or one.

Why?

Transporters are designed to plug together like Legos, to move data around.

The most important Transporter is the IOTDB Transporter, which wraps up all the data from an IOTDB installation, e.g. all the Things on reachable from a computer.

Here's something things you can do:

  • tell a MQTT Transporter to monitor a IOTDB Transporter, so that all changes to the IOTDB Transporter go to the MQTT transporter, and all requests sent to the MQTT Transporter update the IOTDB Transporter
  • create an Express Transporter that takes an IOTDB Transporter as argument to create an API.

Our intention is to develop more Transporters for popular data stores.

API

These APIs use Reactive Extensions.

Standard Methods

For these Standard Methods, all Transporters guarantee that every time onNext is called, the payload will be a new shallow clone of the argument d, with new / requested data layered on top.

So it's safe to pass in data using your own keys, and it's safe to modify the results you get out (within the bounds of shallow clones).

list(d)

Returns observable that will onNext every thing.id, then onCompleted.

added(d)

Returns observable that will onNext every time a new thing.id is found. onCompleted is normally never called.

updated(d)

Returns observable that will onNext every time a change is seen. thing.id and thing.band are delivered, thing.value may not be. onCompleted is normally never called.

The results can be restricted by using d.id; or d.id and d.band

put(d)

Update a Thing's band. d.id, d.band and d.value are all required.

After a successful update, onNext is called with a updated value, then onCompleted.

If the update fails, onError will be called with an appropriate error code.

get(d)

Get a Thing's band's value. d.id, d.band are required. thing.id, thing.band and thing.value are delivered.

remove(d)

Remove a Thing's band's value. d.id, d.band are required.

bands(d)

Get the bands for a Thing. d.id

Helper Methods

all(d)

Will iterate through each Thing with all its bands in one dictionary.

one(d)

Similar to all but will only return the Thing matching d.id

Binding Methods

monitor(source_transport, d)

All changes to the source\_transport will be put to this transport (the destination).

If a put reports an errors.Timestamp, this will put the change to the source\_transport. This can be used to keep the two transporters in sync.

Two useful subparameters are:

  • d.check_source
  • d.check_destination

If either of them return an error, the put operation will not happen. This allows selective or controlled data updates. There is an example of this homestar-persist.

copy(source_transport, d)

Copy all the data in the source\_transport to this transport (the destination).
This returns a Promise so you know when the operations are all complete.

This could probably use d.check_source and d.check_destination like monitor.

Access Transporter

This Transport can be to control what items can be read fro or written to.

Note that at this time there's no support for controlling what can be seen in the value. It's all or nothing.

Here's an example that will deny access to ThingB. In the case of list, updated and added it will be as if the Thing never existed. get and bands will observe the error.

const base = require("iotdb-transport");
const errors = require("iotdb-errors");
const access_transporter = base.access.make({
    check_read: d => {
        if (d.id === "ThingB") {
            return new errors.AccessDenied()
        }
    }
}, wrapped_transporter);

You can use check_write to control access to put.

There is an example of this the sample code for iotdb-transport-memory.

Transporters

Every transporter has documentation and samples showing how it is to be used.

In Progress

These need some (or a lot!) of work