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