.. _dev-ref-crosstalk:

=================
lucid.crosstalk
=================

.. module:: lucid.crosstalk
    :synopsis: Communicate between two instances of an app, regardless of user

Lucid's crosstalk system is similar to D-Bus; it provides a simple way for two application instances to communicate with one another. Lucid's adaptation adds the ability to send and recieve messages between two different users as well. The api is influenced from Dojo's ``dojo.subscribe`` and ``dojo.publish`` methods.

Lifecycle of a message
======================
The way messages are sent depend on the destination, but the API acts the same either way. Each message sent can have a user, application, and instance as it's destination. Both routes have a message dispacher that takes messages from a message queue and routes them to the other application. If the message only specifies an application, and the application is not running, then the dispacher will start the application and pass the message to it. If the message specifies a specific application instance, and that instance is not listening for messages, then the message is dropped.

Between two application instances
---------------------------------
.. image:: _images/crosstalk-one-user.png
   :alt: Diagram of message flow between two applications

When done locally, the message is pushed into a message queue by the API to be processed by the dispacher.

Between two users
-----------------
.. image:: _images/crosstalk-two-users.png
   :alt: Diagram of message flow between two applications running under different users

In the event that the message specifies a different user then the current, the message is sent to the server. When the other person starts the desktop, and the message checker polls the server, then the message checker pushes the message into it's message queue to be handled by the dispacher. The dispacher then sends the message to the application.

Topics and subscriptions
========================

Topics
------
Messages are separated into topics that can be subscribed to. For example, if you were writing a multiplayer checkers game, you could have a "movements" topic and a "chat" topic. 

Subscribing
-----------
When subscribing to topics, you provide a handler function. This function will handle any messages recieved by the dispacher.

It's important that you subscribe to topics inside of the ``init`` method of your app, since the dispacher may launch your app to send it a message. If it does not find any subscriptions after the ``init`` method is called, then it will kill the app. Applications launched by the dispacher are passed a ``crosstalk`` argument, which is set to ``true``.

Subscribing to topics is pretty simple:

.. code-block:: javascript

    this.myTopicSubscription = lucid.crosstalk.subscribe("myTopic", dojo.hitch(this, "myTopicHandler"), this.sysname);

The dispacher will pass a single argument to the handler function, that will contain the message. Messages are always objects, their keys being specified by the application that sent it.

.. code-block:: javascript

    myTopicHandler: function(msg){
        lucid.dialog.notify(msg.someKey);
    },

Messages also have a ``_crosstalk`` property, that has information about where the message came from:

``topic``
    The topic that the sender specified

``instance``
    the instance that the sender specified

``appsysname``
    the application's sysname that was specified by the sender

``sender``
    the userID (not username) that the message originated from. This is ``null`` if it was sent locally.

Unsubscribing
-------------
Unsubscribing from a topic will tell the dispacher to stop sending messages to the handler function:

.. code-block:: javascript

   lucid.crosstalk.unsubscribe(this.myTopicSubscription);

Publishing messages to topics
=============================
To publish a message, use the ``publish`` method.

Publishing messages between two users
-------------------------------------
To publish messages to a specific user, all you need to do is speicfy the userid and the app's system name, as well as the topic and message.

.. code-block:: javascript

    var message = {
        someKey: "Some Value",
        foo: "bar"
    };
    var userid = 5;
    lucid.crosstalk.publish("myTopic", message, userid, this.sysname);

Publishing messages between two instances
-----------------------------------------
To publish a message between two instances of an app being run by the same user, you need to pass ``null`` as the userid, and provide a system name and app instance.

.. code-block:: javascript

   var message = {
       someKey: "Some Value",
       foo: "bar"
   };
   var instance = 2;
   lucid.crosstalk.publish("myTopic", message, null, this.sysname, instance);

Checking if a message is on the database
----------------------------------------
This feature is handy if you want to check if the message has been sent to the user or not. If it has been sent, it will not exist on the database. You need to pass a event ID and a callback. The callback will be called with 'true' (it exists, not sent) or 'false' (it doesn't exist, sent).

.. code-block:: javascript

   var message = {
       someKey: "Some Value",
       foo: "bar"
   };
   var instance = 2;
   lucid.crosstalk.publish("myTopic", message, null, this.sysname, instance, dojo.hitch(this, function(id) {
	setTimeout(dojo.hitch(this, function() {
		lucid.crosstalk.exists(id, dojo.hitch(this, function(exists) {
			if(exists) alert('event exists! message not yet sent');
			else alert('event doesn't exist! message sent!');
		}));
	}), (lucid.config.crosstalkPing * 2));
   }));

Cancelling an event
-------------------
This is handy if you want an event sent to the user, but if the user isn't logged in or responding to crosstalk, it might as well be cancelled.

.. code-block:: javascript

   var message = {
       someKey: "Some Value",
       foo: "bar"
   };
   var instance = 2;
   lucid.crosstalk.publish("myTopic", message, null, this.sysname, instance, dojo.hitch(this, function(id) {
	setTimeout(dojo.hitch(this, function() {
		lucid.crosstalk.exists(id, dojo.hitch(this, function(exists) {
			if(exists){
				lucid.crosstalk.cancel(id);
			}
			else alert('event doesn't exist! message sent!');
		}));
	}), (lucid.config.crosstalkPing * 2));
   }));



