COTONIC

Cotonic is a Javascript library which makes it possible to split the javascript code of your page into truly isolated components. By doing this a crash in one component can never affect another component.

Cotonic provides tools to make it possible for these components to cooperate by providing an MQTT publish/subscribe bus. This makes it possible for components to communicate via topics.

Workers

Cotonic uses Web Workers which all run in separate calling context. This means that they will not block the main user interface thread. They are also truly isolated from each other. This means that a crash or another kind of problem in worker A can crash worker B.

You can run whatever code you like in workers, with some exceptions. You can't access the DOM, and a lot of things from the window object. This also makes them more secure because you don't have to worry that worker code from an external resource can steal the a credit-card number entered somewhere in the DOM tree.

Cotonic adds a MQTT like publish subscribe mechanism to the standard javascript web worker api. This makes it easy for web workers to communicate with each other.

// worker-a
"use strict";

self.subscribe("some/topic", function(message) {
    self.publish("model/ui/update", "<p>Worker A got message</p>")
});

self.publish("model/ui/insert", "<p>Worker A started</p>");
// worker-b
"use strict";

self.subscribe("some/topic", function(message) {
    self.publish("model/ui/update", "<p>Worker B got message</p>")
});

self.publish("model/ui/insert", "<p>Worker B started</p>");
let worker_a = cotonic.spawn("worker-a.js");
let worker_a = cotonic.spawn("worker-b.js");

cotonic.broker.publish("some/topic", "hello workers!");

Functions

Cotonics main functions are available in the cotonic namespace. The functions are mostly used to control and allow messaging between workers.

spawn cotonic.spawn(worker_src_url, [args])
Spawn a new worker. Returns the worker-id of the process.

let worker_id1 = cotonic.spawn("/js/example-worker.js");
let worker_id2 = cotonic.spawn("/js/another-worker.js", ["Arg1", 1]);

spawn_named cotonic.spawn_named(name, worker_src_url, [base], [args])
Spawn a new named worker. Named workers are unique. Use "" or undefined for a nameless worker. Return the worker_id of the newly spawned worker. If the worker was already running, the existing worker_id is returned.

cotonic.spawn_named("example", "example-worker.js");

exit cotonic.exit(nameOrwid)
Exit stops a worker which was previously spawned.

const wid = cotonic.spawn("example.worker.js");
cotonic.exit(wid);
=> Worker wid is no longer running.

send cotonic.send(worker_id, message)
Send a message to a worker.

cotonic.send(worker_id1, "hello");

receive cotonic.receive(handler)
Receive messages from workers. The handler should be a function which takes two parameters, the message, and the worker_id.

cotonic.receive(function(message, worker_id) {
    console.log("Received", message, "from worker", worker_id);
});

set_worker_base_src cotonic.set_worker_base_src(baseUrl)
Set the base url to load additional importable cotonic modules from. This is used to locate the base worker script which is needed to communicate with the other workers.
By default the location is /lib/cotonic/cotonic-worker-bundle.js . It is also possible to configure this via the script via which cotonic itself is loaded on the page. Note: When this is not setup correctly, it will not be possible to spawn workers.

cotonic.set_worker_base_src("/lib/js/cotonic-worker.js");
=> Cotonic will now use the '/lib/js/cotonic-worker.js' when workers are spawned.
<script data-worker-base-src="/lib/cotonic-worker.js" src="/lib/cotonic.js"></script>
=> Cotonic will use '/lib/cotonic-worker.js' when new workers are spawned.

Broker

The broker module handles all local publish subscribe connections. The subscriptions are stored in a trie datastructure allowing quick action. They are available in the cotonic.broker namespace.

find_subscriptions_below cotonic.broker.find_subscriptions_below(topic)
Find all subscribers below a certain topic. Used by the bridge to collect all subscriptions after a session restart.

cotonic.broker.find_subscriptions_below("/my/topic/#");

match cotonic.broker.match(topic)
Collect all subscribers which match the topic.

cotonic.broker.subscribe("/a/test"
    function(msg) {
        console.log("test topic a");
    })
cotonic.broker.subscribe("/b/test"
    function(msg) {
        console.log("test topic b");
    })
cotonic.broker.match("+/test");

publish cotonic.broker.publish(topic, payload, [options])
Publish the message <payload on a topic. The possible options are:

qos
Quality of service. Can be 0, 1, or 2. 0 means at most once, 1 at least once, and 2 exactly once.
retain
When retain is true, the last message sent will be stored, and delivered immediately when a new client subscribes to the topic.
properties
Extra properties which can be attached to the message

cotonic.broker.publish("truck/001/temperature", 88);
=> All subscribers receive the message 88 on the topic.
cotonic.broker.publish("truck/001/speed", 74, {retain: true});
=> All subscribers receive the message 74. New subscribers will immediately receive 74.
            

subscribe cotonic.broker.subscribe(topics, callback, [options])
Subscribe to the topics. The callback will be called when a message which matches one of the topics is published.

// [TODO]
cotonic.broker.subscribe();

unsubscribe cotonic.broker.unsubscribe(topics, [options])
Unsubscribe from the topics.

// [TODO]
cotonic.broker.unsubscribe();

call cotonic.broker.call(topic, payload, [options])
Call a topic, returns a promise for the response.

// [TODO]
cotonic.broker.call();

MQTT

matches cotonic.mqtt.matches(pattern, topic)

// [TODO]
cotonic.mqtt.matches();

extract cotonic.mqtt.extract(pattern, topic)

// [TODO]
cotonic.mqtt.extract();

exec cotonic.mqtt.exec(pattern, topic)

// [TODO]
cotonic.mqtt.exec();

fill cotonic.mqtt.fill(pattern, params)

// [TODO]
cotonic.mqtt.fill();

fill cotonic.mqtt.remove_named_wildcards(pattern)

// [TODO]
cotonic.mqtt.remove_named_wildcards();

ui

insert cotonic.ui.insert(targetId, isInner, initialHTML, [priority])
Insert a new html snippet into the user interface composer. The snippet will be stored under the given targetId. The element will not be placed in the dom-tree immediately. This will happen when one of the render functions is called. The isInner boolean flag indicates if only innerHTML of the target element must be updated, or the outerHTML. The optional priority parameter indicates the render order of the elements. Elements with a high priority are rendedered before lower priorities. This makes it possible to nest elements.

cotonic.ui.insert("root", false, "<p>Hello World!</p>");
cotonic.ui.render();

get cotonic.ui.get(id)
Retrieve the current html snippet registered at id.

let currentHTML = cotonic.ui.get("root");

remove cotonic.ui.remove(id)
Remove the html snippet registered at id. Note that this will not remove the element from the dom-tree, it will only remove it from the user interface composer. When the element must be removed it should first be updated and set to a blank string and a render operation should be done.

cotonic.ui.remove("root");

update cotonic.ui.update(id, htmlOrTokens)
Update the registered snippet for the registered element with the given id. The new snippet will be visible after a render operation.

cotonic.ui.update("root", "<p>Hello Everybody!</p>");

render cotonic.ui.render()
Render all registered elements.

cotonic.ui.render();

renderId cotonic.ui.renderId(id)
Just render the element with the given id.

cotonic.ui.renderId("root");

updateStateData cotonic.ui.updateStateData(model, states)

// [TODO]
cotonic.ui.updateStateData();

updateStateClass cotonic.ui.updateStateClass(model, classes)

// [TODO]
cotonic.ui.updateStateClass();

on cotonic.ui.on(topic, msg, event, [options])

// [TODO]
cotonic.ui.on();

Models

Document

"model/document/get/+key"

key = "all"

            
            screen_width
            screen_height
            inner_width
            inner_height
            is_touch
            timezone
            language

key = "intl"

            timezone
            language

Location

"model/location/get/+what"

"model/location/event" ping, search (q), pathname, hash

User Interface Composer

Service Worker

Local Storage

Session Storage