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