- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / doc / devguide / coding / message-system.rst
1 .. _message-system:
2
3 ################
4 Messaging System
5 ################
6
7 .. contents::
8   :local:
9   :backlinks: none
10   :depth: 2
11
12 This chapter describes the messaging system used to communicate between the
13 JavaScript code and the Native Client module's C or C++ code in a
14 Native Client application. It introduces the concept of asynchronous
15 programming and the basic steps required to set up a Native Client module
16 that sends messages to and receive messages from JavaScript. This chapter
17 assumes you are familiar with the material presented in the
18 :doc:`Application Structure <application-structure>` chapter.
19
20 .. Note::
21   :class: note
22
23   The "Hello, World" example for getting started with NaCl is used here to
24   illustrate basic programming techniques. You can find this code in
25   the ``/getting_started/part2`` directory in the Native Client SDK download.
26
27 Reference information
28 =====================
29
30 For reference information related to the Pepper messaging API, see the
31 following documentation:
32
33 * `pp::Instance class <https://developers.google.com/native-client/peppercpp/classpp_1_1_instance>`_ HandleMessage(), PostMessage())
34 * `pp::Module class <https://developers.google.com/native-client/peppercpp/classpp_1_1_module>`_
35 * `pp::Var class <https://developers.google.com/native-client/peppercpp/classpp_1_1_var>`_
36
37 Introduction to the messaging system
38 ====================================
39
40 Native Client modules and JavaScript communicate by sending messages
41 to each other. The most basic form of a message is a string.  Messages
42 support many JavaScript types, including ints, arrays, array buffers,
43 and dictionaries (see `pp::Var
44 <https://developers.google.com/native-client/peppercpp/classpp_1_1_var>`_,
45 `pp:VarArrayBuffer
46 <https://developers.google.com/native-client/peppercpp/classpp_1_1_var_array_buffer>`_,
47 and the general `messaging system documentation
48 <https://developers.google.com/native-client/pepperc/struct_p_p_b___messaging__1__0>`_).
49 It's up to you to decide on the type of message and define how to
50 process the messages on both the JavaScript and Native Client
51 side. For the "Hello, World" example, we will work with string-typed
52 messages only.
53
54 When JavaScript posts a message to the Native Client module, the
55 Pepper ``HandleMessage()`` function is invoked on the module
56 side. Similarly, the Native Client module can post a message to
57 JavaScript, and this message triggers a JavaScript event listener for
58 ``message`` events in the DOM. (See the W3C specification on
59 `Document Object Model Events
60 <http://www.w3.org/TR/DOM-Level-2-Events/events.html>`_ for more
61 information.) In the "Hello, World" example, the JavaScript functions for
62 posting and handling messages are named ``postMessage()`` and
63 ``handleMessage()`` (but any names could be used). On the Native Client
64 C++ side, the Pepper Library functions for posting and handling
65 messages are:
66
67 * ``void pp::Instance::PostMessage(const Var &message)``
68 * ``virtual void pp::Instance::HandleMessage(const Var &message)``
69
70 If you want to receive messages from JavaScript, you need to implement the
71 ``pp::Instance::HandleMessage()`` function in your Native Client module.
72
73 Design of the messaging system
74 ------------------------------
75
76 The Native Client messaging system is analogous to the system used by
77 the browser to allow web workers to communicate (see the `W3 web
78 worker specification <http://www.w3.org/TR/workers>`_).  The Native
79 Client messaging system is designed to keep the web page responsive while the
80 Native Client module is performing potentially heavy processing in the
81 background. When JavaScript sends a message to the Native Client
82 module, the ``postMessage()`` call returns as soon as it sends its message
83 to the Native Client module. The JavaScript does not wait for a reply
84 from Native Client, thus avoiding bogging down the main JavaScript
85 thread. On the JavaScript side, you set up an event listener to
86 respond to the message sent by the Native Client module when it has
87 finished the requested processing and returns a message.
88
89 This asynchronous processing model keeps the main thread free while
90 avoiding the following problems:
91
92 * The JavaScript engine hangs while waiting for a synchronous call to return.
93 * The browser pops up a dialog when a JavaScript entry point takes longer
94   than a few moments.
95 * The application hangs while waiting for an unresponsive Native Client module.
96
97 Communication tasks in the "Hello, World" example
98 =================================================
99
100 The following sections describe how the "Hello, World" example posts
101 and handles messages on both the JavaScript side and the Native Client
102 side of the application.
103
104 JavaScript code
105 ---------------
106
107 The JavaScript code and HTML in the "Hello, World" example can be
108 found in the ``example.js``, ``common.js``, and ``index.html`` files.
109 The important steps are:
110
111 #. Sets up an event listener to listen for ``message`` events from the
112    Native Client module.
113 #. Implements an event handler that the event listener invokes to handle
114    incoming ``message`` events.
115 #. Calls ``postMessage()`` to communicate with the NaCl module,
116    after the page loads.
117
118 Step 1: From common.js
119 ^^^^^^^^^^^^^^^^^^^^^^
120
121 .. naclcode::
122
123   function attachDefaultListeners() {
124     // The NaCl module embed is created within the listenerDiv
125     var listenerDiv = document.getElementById('listener');
126     // ...
127
128     // register the handleMessage function as the message event handler.
129     listenerDiv.addEventListener('message', handleMessage, true);
130     // ...
131   }
132
133
134 Step 2: From example.js
135 ^^^^^^^^^^^^^^^^^^^^^^^
136
137 .. naclcode::
138
139   // This function is called by common.js when a message is received from the
140   // NaCl module.
141   function handleMessage(message) {
142     // In the example, we simply log the data that's received in the message.
143     var logEl = document.getElementById('log');
144     logEl.textContent += message.data;
145   }
146
147   // In the index.html we have set up the appropriate divs:
148   <body {attrs}>
149     <!-- ... -->
150     <div id="listener"></div>
151     <div id="log"></div>
152   </body>
153
154
155 Step 3: From example.js
156 ^^^^^^^^^^^^^^^^^^^^^^^
157
158 .. naclcode::
159
160   // From example.js, Step 3:
161   function moduleDidLoad() {
162     // After the NaCl module has loaded, common.naclModule is a reference to the
163     // NaCl module's <embed> element.
164     //
165     // postMessage sends a message to it.
166     common.naclModule.postMessage('hello');
167   }
168
169
170 Native Client module
171 --------------------
172
173 The C++ code in the Native Client module of the "Hello, World" example:
174
175 #. Implements ``pp::Instance::HandleMessage()`` to handle messages sent
176    by the JavaScript.
177 #. Processes incoming messages. This example simply checks that JavaScript
178    has sent a "hello" message and not some other message.
179 #. Calls ``PostMessage()`` to send an acknowledgement back to the
180    JavaScript code.  The acknowledgement is a string in the form of a ``Var``
181    that the JavaScript code can process.  In general, a ``pp::Var`` can be
182    several JavaScript types, see the
183    `messaging system documentation
184    <https://developers.google.com/native-client/pepperc/struct_p_p_b___messaging__1__0>`_.
185
186
187 .. naclcode::
188
189   class HelloTutorialInstance : public pp::Instance {
190    public:
191     // ...
192
193     // === Step 1: Implement the HandleMessage function. ===
194     virtual void HandleMessage(const pp::Var& var_message) {
195
196       // === Step 2: Process the incoming message. ===
197       // Ignore the message if it is not a string.
198       if (!var_message.is_string())
199         return;
200
201       // Get the string message and compare it to "hello".
202       std::string message = var_message.AsString();
203       if (message == kHelloString) {
204         // === Step 3: Send the reply. ===
205         // If it matches, send our response back to JavaScript.
206         pp::Var var_reply(kReplyString);
207         PostMessage(var_reply);
208       }
209     }
210   };
211
212
213 Messaging in JavaScript code: More details.
214 ===========================================
215
216 This section describes in more detail the messaging system code in the
217 JavaScript portion of the "Hello, World" example.
218
219 Setting up an event listener and handler
220 ----------------------------------------
221
222 The following JavaScript code sets up an event listener for messages
223 posted by the Native Client module. It then defines a message handler
224 that simply logs the content of messages received from the module.
225
226 Setting up the 'message' handler on load
227 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
228
229 .. naclcode::
230
231   // From common.js
232
233   // Listen for the DOM content to be loaded. This event is fired when
234   // parsing of the page's document has finished.
235   document.addEventListener('DOMContentLoaded', function() {
236     var body = document.body;
237     // ...
238     var loadFunction = common.domContentLoaded;
239     // ... set up parameters ...
240     loadFunction(...);
241   }
242
243   // This function is exported as common.domContentLoaded.
244   function domContentLoaded(...) {
245     // ...
246     if (common.naclModule == null) {
247       // ...
248       attachDefaultListeners();
249       // initialize common.naclModule ...
250     } else {
251       // ...
252     }
253   }
254
255   function attachDefaultListeners() {
256     var listenerDiv = document.getElementById('listener');
257     // ...
258     listenerDiv.addEventListener('message', handleMessage, true);
259     // ...
260   }
261
262
263 Implementing the handler
264 ^^^^^^^^^^^^^^^^^^^^^^^^
265
266 .. naclcode::
267
268   // From example.js
269   function handleMessage(message) {
270     var logEl = document.getElementById('log');
271     logEl.textContent += message.data;
272   }
273
274
275 Note that the ``handleMessage()`` function is handed a message_event
276 containing ``data`` that you can display or manipulate in JavaScript. The
277 "Hello, World" application simply logs this data to the ``log`` div.
278
279
280 Messaging in the Native Client module: More details.
281 ====================================================
282
283 This section describes in more detail the messaging system code in
284 the Native Client module portion of the "Hello, World" example.  
285
286 Implementing HandleMessage()
287 ----------------------------
288
289 If you want the Native Client module to receive and handle messages
290 from JavaScript, you need to implement a ``HandleMessage()`` function
291 for your module's ``pp::Instance`` class. The
292 ``HelloWorldInstance::HandleMessage()`` function examines the message
293 posted from JavaScript. First it examines that the type of the
294 ``pp::Var`` is indeed a string (not a double, etc.). It then
295 interprets the data as a string with ``var_message.AsString()``, and
296 checks that the string matches ``kHelloString``. After examining the
297 message received from JavaScript, the code calls ``PostMessage()`` to
298 send a reply message back to the JavaScript side.
299
300 .. naclcode::
301
302   namespace {
303
304   // The expected string sent by the JavaScript.
305   const char* const kHelloString = "hello";
306   // The string sent back to the JavaScript code upon receipt of a message
307   // containing "hello".
308   const char* const kReplyString = "hello from NaCl";
309
310   }  // namespace
311
312   class HelloTutorialInstance : public pp::Instance {
313    public:
314     // ...
315     virtual void HandleMessage(const pp::Var& var_message) {
316       // Ignore the message if it is not a string.
317       if (!var_message.is_string())
318         return;
319
320       // Get the string message and compare it to "hello".
321       std::string message = var_message.AsString();
322       if (message == kHelloString) {
323         // If it matches, send our response back to JavaScript.
324         pp::Var var_reply(kReplyString);
325         PostMessage(var_reply);
326       }
327     }
328   };
329
330
331 Implementing application-specific functions
332 -------------------------------------------
333
334 While the "Hello, World" example is very simple, your Native Client
335 module will likely include application-specific functions to perform
336 custom tasks in response to messages. For example the application
337 could be a compression and decompression service (two functions
338 exported).  The application could set up an application-specific
339 convention that messages coming from JavaScript are colon-separated
340 pairs of the form ``<command>:<data>``.  The Native Client module
341 message handler can then split the incoming string along the ``:``
342 character to determine which command to execute.  If the command is
343 "compress", then data to process is an uncompressed string.  If the
344 command is "uncompress", then data to process is an already-compressed
345 string. After processing the data asynchronously, the application then
346 returns the result to JavaScript.
347
348
349 Sending messages back to the JavaScript code
350 --------------------------------------------
351
352 The Native Client module sends messages back to the JavaScript code
353 using ``PostMessage()``. The Native Client module always returns
354 its values in the form of a ``pp::Var`` that can be processed by the
355 browser's JavaScript. In this example, the message is posted at the
356 end of the Native Client module's ``HandleMessage()`` function:
357
358 .. naclcode::
359
360   PostMessage(var_reply);
361
362
363 Sending and receiving other ``pp::Var`` types
364 ---------------------------------------------
365
366 Besides strings, ``pp::Var`` can represent other types of JavaScript
367 objects. For example, messages can be JavaScript objects. These
368 richer types can make it easier to implement an application's
369 messaging protocol.
370
371 To send a dictionary from the NaCl module to JavaScript simply create
372 a ``pp::VarDictionary`` and then call ``PostMessage`` with the
373 dictionary.
374
375 .. naclcode::
376
377   pp::VarDictionary dictionary;
378   dictionary.Set(pp::Var("command"), pp::Var(next_command));
379   dictionary.Set(pp::Var("param_int"), pp::Var(123));
380   pp::VarArray an_array;
381   an_array.Set(0, pp::Var("string0"));
382   an_array.Set(1, pp::Var("string1"))
383   dictionary.Set(pp::Var("param_array"), an_array);
384   PostMessage(dictionary);
385
386
387 Here is how to create a similar object in JavaScript and send it to
388 the NaCl module:
389
390 .. naclcode::
391
392   var dictionary = {
393     command: next_command,
394     param_int: 123,
395     param_array: ['string0', 'string1']
396   }
397   nacl_module.postMessage(dictionary);
398
399
400 To receive a dictionary-typed message in the NaCl module, test that
401 the message is truly a dictionary type, then convert the message
402 with the ``pp::VarDictionary`` class.
403
404 .. naclcode::
405
406   virtual void HandleMessage(const pp::Var& var) {
407     if (var.is_dictionary()) {
408       pp::VarDictionary dictionary(var);
409       // Use the dictionary
410       pp::VarArray keys = dictionary.GetKeys();
411       // ...
412     } else {
413       // ...
414     }
415   }