Skip to content

freedom.js structure: Consumer Interface

willscott edited this page Nov 12, 2014 · 2 revisions

This document discusses conventions for consuming freedom.js APIs. For conventions around exporting an API from your freedom module, see Provider Interface documentation

The client interface for freedom.js is referred to in code as a Consumer. The consumer takes an API definition from the API Registry, or as defined in a module manifest, and instantiates an object accessible to module code matching that template. The proxy interface does impose a set of conventions and semantics which are not obvious from the template. This page attempts to document those conventions.

The Null Interface

For simplicity, and to reflect the interface exposed across javascript namespaces by browsers, freedom.js provides a default message passing interface if no template is specified. The null interface provides the following behavior.

// Send a message.
consumer.emit('tag', 'json object');

// Listen for a message.
consumer.on('tag', function(msg) {
  // Do Something
});

// Stop listening.
consumer.off('tag', func);

// Listen for a single message.
consumer.once('tag', function(msg) {
  // Convenience method that automatically deregisters itself.
});

Methods

Methods, as specified in an interface, are necessarily asynchronous, and are implemented using javascript promises. A method specified in json as

'myMethod': {
    'type': 'method',
    'value': ['string', 'number'],  // The types and number of arguments.
    'ret': 'string' // The type of the return value.
}

Can subsequently be invoked as

consumer.myMethod('myString', 12).then(function(str) {
  // Do something
});

Events

Many interfaces encode the concept that an alert will be raised by the Provider, rather than the consumer. Such events are encoded in freedom.js consumers by reusing the on/emit interface provided by the Null interface. In order to promote reusability of interfaces, events must be explicitly defined, as in the following example:

'myEvent': {
    'type': 'event',
    'value': 'string'  // The data sent in the event.
}

The consumer exposes remotely generated events as in the null interface, for example to consume raised 'myEvent's:

consumer.on('myEvent', function(str) {
  // Do something
});

Consumer Lifetime

While in many cases modules can assume that consumers will exist for the lifetime of the module, such as when a single instance is created, there are also use cases where the lifetime of freedom.js modules must be considered. To support this, the interface exposed by freedom.js allows modules to explicitly close an instance of a consumer, and register for notification if the consumer is closed either by the remote side or due to a communication failure. Access to these lifetime properties is exposed not on a proxy itself, in order not to conflict with methods defined by the interface. Instead, lifetime methods are exposed on the user exposed object from which consumers are instantiated.

Closing

Closing can be accomplished through the close method. Any subsequent methods on the instance will result in errors that it is not connected.

var instance = freedom.social();
// Deallocate the consumer.
freedom.social.close(instance);

Alternatively, if you will no longer use the interface, and want to tell freedom.js that it is okay to fully stop the module providing that interface, you can do so through a close call with no arguments. This is the explicit user action needed to deallocate the web worker or module context of the provider, assuming that it has no consumers left.

// Close the entire interface, and remote provider context.
freedom.social.close();

Listening for Lifetime Events

In order to determine if the remote side of the interface has closed a consumer, you can either reactively handle errors on subsequent methods, or proactively register a handler to alert you when the consumer has been deallocated.

freedom.social.onClose(instance, function() {
  // Handle closure of a consumer instance.
});

You can likewise determine if the remote module has closed of its own accord by registering a generic onClose handler.

freedom.social.onClose(function() {
  // Handle closure of the entire interface.
});

While closure events will be raised when access to the remote consumer is disrupted, if you want to specifically be notified when there are errors resulting in the issue - either communication problems, syntax errors in the handler, or other abnormal conditions other than an explicit close() call which has resulted in the consumer failing, you can also register an onError handler:

freedom.social.onError(function() {
  // Handle Errors associated with the interface.
});