OLD | NEW |
1 --- | 1 --- |
2 layout: book | 2 layout: book |
3 title: "Chapter 5. Walkthrough: Dart Chat" | 3 title: "Chapter 5. Walkthrough: Dart Chat" |
4 description: "See a real app with both client-side and server-side Dart: Dart Ch
at." | 4 description: "See a real app with both client-side and server-side Dart: Dart Ch
at." |
5 has-permalinks: true | 5 has-permalinks: true |
6 --- | 6 --- |
7 <h1 id="ch05"> {{ page.title }} </h1> | 7 <h1 id="ch05"> {{ page.title }} </h1> |
8 | 8 |
9 <p>This chapter points out some of the useful and fun features of Dart | 9 <p>This chapter points out some of the useful and fun features of Dart |
10 that we used to build Dart Chat, a client-server app. If you’d like | 10 that we used to build Dart Chat, a client-server app. If you’d like |
11 step-by-step instructions on building Dart Chat, you might be interested in | 11 step-by-step instructions on building Dart Chat, you might be interested in |
12 our <a class="ulink" href="https://www.dartlang.org/slides/2012/06/io12/Bullse
ye-Your-first-Dart-app-Codelab-GoogleIO2012.pdf">code | 12 our <a class="ulink" href="https://www.dartlang.org/slides/2012/06/io12/Bullse
ye-Your-first-Dart-app-Codelab-GoogleIO2012.pdf">code |
13 lab</a>.</p><p><a class="xref" href="ch05.html#DartChat-screenshot" title="Fig
ure 5-1. Multiple chat clients can use the chat server to talk">Figure 5-1</a> s
hows the chat client executing | 13 lab</a>.</p><p><a class="xref" href="ch05.html#DartChat-screenshot" title="Fig
ure 5-1. Multiple chat clients can use the chat server to talk">Figure 5-1</a> s
hows the chat client executing |
14 in a Dartium window. Each copy of the chat client can send messages to the | 14 in a Dartium window. Each copy of the chat client can send messages to the |
15 chat server, which forwards those messages to the other chat clients.</p><div
class="figure"id="DartChat-screenshot"/><div class="figure-contents"><div class=
"mediaobject"><img src="figs/web/daur_0501.png" alt="Multiple chat clients can u
se the chat server to talk"/></div></div><p class="title">Figure 5-1. Multiple c
hat clients can use the chat server to talk</p></div><div class="sect1" title="H
ow to run Dart Chat"><div class="titlepage"><div><div><h1 class="title"id="ch05-
how-to-run"/>How to run Dart Chat</h1></div></div></div><p>The easiest way to ru
n the Dart Chat client and server apps is to | 15 chat server, which forwards those messages to the other chat clients.</p><div
class="figure"id="DartChat-screenshot"/><div class="figure-contents"><div class=
"mediaobject"><img src="figs/web/daur_0501.png" alt="Multiple chat clients can u
se the chat server to talk"/></div></div><p class="title">Figure 5-1. Multiple c
hat clients can use the chat server to talk</p></div><div class="sect1" title="H
ow to run Dart Chat"><div class="titlepage"><div><div><h2 class="title"id="ch05-
how-to-run"/>How to run Dart Chat</h2></div></div></div><p>The easiest way to ru
n the Dart Chat client and server apps is to |
16 open them in Dart Editor.</p><div class="orderedlist"><ol class="orderedlist
"><li class="listitem"><p>Download the Dart Chat source code from GitHub:</p><p> | 16 open them in Dart Editor.</p><div class="orderedlist"><ol class="orderedlist
"><li class="listitem"><p>Download the Dart Chat source code from GitHub:</p><p> |
17 <a class="ulink" href="https://github.com/dart-lang/io-2012-dart-code-
lab">https://github.com/dart-lang/io-2012-dart-code-lab</a> | 17 <a class="ulink" href="https://github.com/dart-lang/io-2012-dart-code-
lab">https://github.com/dart-lang/io-2012-dart-code-lab</a> |
18 </p></li><li class="listitem"><p>In Dart Editor, use <span class="bold">
<strong>File > Open | 18 </p></li><li class="listitem"><p>In Dart Editor, use <span class="bold">
<strong>File > Open |
19 Folder...</strong></span>, to open the <span class="bold"><strong>finish
ed</strong></span> directory of the Dart Chat source | 19 Folder...</strong></span>, to open the <span class="bold"><strong>finish
ed</strong></span> directory of the Dart Chat source |
20 code.</p></li><li class="listitem"><p>Select <code class="literal">chat-
server.dart</code>, and then click | 20 code.</p></li><li class="listitem"><p>Select <code class="literal">chat-
server.dart</code>, and then click |
21 the Run button <span class="inlinemediaobject"><img src="figs/incoming/r
un.png" alt=""/></span>.</p><p>A view named chat-server appears in Dart Editor,
displaying | 21 the Run button <span class="inlinemediaobject"><img src="figs/incoming/r
un.png" alt=""/></span>.</p><p>A view named chat-server appears in Dart Editor,
displaying |
22 debugging output for the server.</p></li><li class="listitem"><p>Select
<code class="literal">client/chat-client.dart</code>, and then | 22 debugging output for the server.</p></li><li class="listitem"><p>Select
<code class="literal">client/chat-client.dart</code>, and then |
23 click the Run button <span class="inlinemediaobject"><img src="figs/inco
ming/run.png" alt=""/></span>.</p><p>Dartium launches, if necessary, and display
s a Dart Chat | 23 click the Run button <span class="inlinemediaobject"><img src="figs/inco
ming/run.png" alt=""/></span>.</p><p>Dartium launches, if necessary, and display
s a Dart Chat |
24 tab.</p></li><li class="listitem"><p>To create another copy of the chat
client, go to the Dart | 24 tab.</p></li><li class="listitem"><p>To create another copy of the chat
client, go to the Dart |
25 Chat tab in Dartium. Right-click the tab, and choose <span class="bold">
<strong>Duplicate</strong></span>.</p></li></ol></div></div><div class="sect1" t
itle="How Dart Chat works"><div class="titlepage"><div><div><h1 class="title"id=
"ch05-how-it-works"/>How Dart Chat works</h1></div></div></div><p>The chat serve
r and client are simple. The chat server is an HTTP | 25 Chat tab in Dartium. Right-click the tab, and choose <span class="bold">
<strong>Duplicate</strong></span>.</p></li></ol></div></div><div class="sect1" t
itle="How Dart Chat works"><div class="titlepage"><div><div><h2 class="title"id=
"ch05-how-it-works"/>How Dart Chat works</h2></div></div></div><p>The chat serve
r and client are simple. The chat server is an HTTP |
26 server that provides a WebSocket. The chat client uses that WebSocket for | 26 server that provides a WebSocket. The chat client uses that WebSocket for |
27 a bi-directional communication channel with the server. The client sends | 27 a bi-directional communication channel with the server. The client sends |
28 chat messages to the sever over the WebSocket, and the server relays those | 28 chat messages to the sever over the WebSocket, and the server relays those |
29 messages to all other connected clients.</p><p>As <a class="xref" href="ch05
.html#web-socket-connections" title="Figure 5-2. Chat clients connect to a web s
ocket created by the chat server">Figure 5-2</a> shows, the server | 29 messages to all other connected clients.</p><p>As <a class="xref" href="ch05
.html#web-socket-connections" title="Figure 5-2. Chat clients connect to a web s
ocket created by the chat server">Figure 5-2</a> shows, the server |
30 starts things off by listening for requests to | 30 starts things off by listening for requests to |
31 <code class="literal">ws://127.0.0.1:1337/ws</code>. Chat clients then conne
ct to | 31 <code class="literal">ws://127.0.0.1:1337/ws</code>. Chat clients then conne
ct to |
32 that URL.</p><div class="figure"id="web-socket-connections"/><div class="fig
ure-contents"><div class="mediaobject"><img src="figs/web/daur_0502.png" alt="Ch
at clients connect to a web socket created by the chat server"/></div></div><p c
lass="title">Figure 5-2. Chat clients connect to a web socket created by the cha
t | 32 that URL.</p><div class="figure"id="web-socket-connections"/><div class="fig
ure-contents"><div class="mediaobject"><img src="figs/web/daur_0502.png" alt="Ch
at clients connect to a web socket created by the chat server"/></div></div><p c
lass="title">Figure 5-2. Chat clients connect to a web socket created by the cha
t |
33 server</p></div><p>The real communication between client and server happen
s when the | 33 server</p></div><p>The real communication between client and server happen
s when the |
34 user enters a message. As <a class="xref" href="ch05.html#web-socket-message
s" title="Figure 5-3. A chat client uses the server to send a message to other c
hat clients">Figure 5-3</a> shows, | 34 user enters a message. As <a class="xref" href="ch05.html#web-socket-message
s" title="Figure 5-3. A chat client uses the server to send a message to other c
hat clients">Figure 5-3</a> shows, |
35 the chat client sends a JSON-encoded version of the message to the server. | 35 the chat client sends a JSON-encoded version of the message to the server. |
36 The server then forwards the message to every client except the one that | 36 The server then forwards the message to every client except the one that |
37 sent it.</p><div class="figure"id="web-socket-messages"/><div class="figure-
contents"><div class="mediaobject"><img src="figs/web/daur_0503.png" alt="A chat
client uses the server to send a message to other chat clients"/></div></div><p
class="title">Figure 5-3. A chat client uses the server to send a message to ot
her chat | 37 sent it.</p><div class="figure"id="web-socket-messages"/><div class="figure-
contents"><div class="mediaobject"><img src="figs/web/daur_0503.png" alt="A chat
client uses the server to send a message to other chat clients"/></div></div><p
class="title">Figure 5-3. A chat client uses the server to send a message to ot
her chat |
38 clients</p></div><p>The chat server implements an HTTP server to listen fo
r WebSocket | 38 clients</p></div><p>The chat server implements an HTTP server to listen fo
r WebSocket |
39 requests. The HTTP server can also serve static files from the client | 39 requests. The HTTP server can also serve static files from the client |
40 directory—for example, http://127.0.0.1:1337/chat-log.txt shows the file | 40 directory—for example, http://127.0.0.1:1337/chat-log.txt shows the file |
41 that’s at client/chat-log.txt.</p><p>The client code is split between HTML (
page structure), CSS (page | 41 that’s at client/chat-log.txt.</p><p>The client code is split between HTML (
page structure), CSS (page |
42 look), and JavaScript (logic and behavior). That’s typical of web | 42 look), and JavaScript (logic and behavior). That’s typical of web |
43 clients.</p><p>The twist is that this client’s JavaScript code is produced f
rom | 43 clients.</p><p>The twist is that this client’s JavaScript code is produced f
rom |
44 Dart code, thanks to the dart2js compiler. Any modern browser can run this | 44 Dart code, thanks to the dart2js compiler. Any modern browser can run this |
45 JavaScript code. Dartium (and any other browsers that support Dart) can | 45 JavaScript code. Dartium (and any other browsers that support Dart) can |
46 run either the JavaScript code or the original Dart code.</p></div><div clas
s="sect1" title="The client’s HTML code"><div class="titlepage"><div><div><h1 cl
ass="title"id="ch05-client-html-code"/>The client’s HTML code</h1></div></div></
div><p>The main elements in the client UI are two text fields (with the IDs | 46 run either the JavaScript code or the original Dart code.</p></div><div clas
s="sect1" title="The client’s HTML code"><div class="titlepage"><div><div><h2 cl
ass="title"id="ch05-client-html-code"/>The client’s HTML code</h2></div></div></
div><p>The main elements in the client UI are two text fields (with the IDs |
47 “chat-username” and “chat-message”) and a status area (ID: | 47 “chat-username” and “chat-message”) and a status area (ID: |
48 “chat-display”).</p><pre class="programlisting"><!-- In client/index.html
: --> | 48 “chat-display”).</p><pre class="programlisting"><!-- In client/index.html
: --> |
49 <textarea id="chat-display" rows="10" disabled></textarea> | 49 <textarea id="chat-display" rows="10" disabled></textarea> |
50 ... | 50 ... |
51 <input id="chat-username" name="chat-username" type="text"> | 51 <input id="chat-username" name="chat-username" type="text"> |
52 ... | 52 ... |
53 <input id="chat-message" name="chat-message" type="text" disabled value="ente
r message..."></pre><p>Near the bottom of client/index.html, a couple of <
script> | 53 <input id="chat-message" name="chat-message" type="text" disabled value="ente
r message..."></pre><p>Near the bottom of client/index.html, a couple of <
script> |
54 tags tell the browser to execute the client’s Dart or JavaScript | 54 tags tell the browser to execute the client’s Dart or JavaScript |
55 code:</p><pre class="programlisting"><script type="application/dart" src=
"chat-client.dart"></script> | 55 code:</p><pre class="programlisting"><script type="application/dart" src=
"chat-client.dart"></script> |
56 <script src="dart.js"></script></pre><p>The first line works in brow
sers that have an embedded Dart VM and | 56 <script src="dart.js"></script></pre><p>The first line works in brow
sers that have an embedded Dart VM and |
57 so can execute Dart code; currently, only Dartium qualifies. The second | 57 so can execute Dart code; currently, only Dartium qualifies. The second |
58 line is important for every other browser. It executes dart.js, which is a | 58 line is important for every other browser. It executes dart.js, which is a |
59 standard script that converts all Dart <script> tags to use | 59 standard script that converts all Dart <script> tags to use |
60 foo.dart.js instead of foo.dart, with the assumption that foo.dart.js is a | 60 foo.dart.js instead of foo.dart, with the assumption that foo.dart.js is a |
61 JavaScript version of foo.dart. For non-Dartium browsers, dart.js changes | 61 JavaScript version of foo.dart. For non-Dartium browsers, dart.js changes |
62 the first <script> tag to the following:</p><pre class="programlisting
"><!-- Inserted by dart.js for non-Dartium browsers --> | 62 the first <script> tag to the following:</p><pre class="programlisting
"><!-- Inserted by dart.js for non-Dartium browsers --> |
63 <script src="chat-client.dart.js"></script></pre><p>The script conte
nts run when the browser has loaded the HTML and | 63 <script src="chat-client.dart.js"></script></pre><p>The script conte
nts run when the browser has loaded the HTML and |
64 constructed its DOM (document object model).</p><p>You can get <a class="uli
nk" href="http://dart.googlecode.com/svn/trunk/dart/client/dart.js">dart.js</a> | 64 constructed its DOM (document object model).</p><p>You can get <a class="uli
nk" href="http://dart.googlecode.com/svn/trunk/dart/client/dart.js">dart.js</a> |
65 from the Dart project. See <a class="xref" href="ch04.html#ch04-tools-dart2j
s" title="dart2js: The Dart-to-JavaScript compiler">dart2js: The Dart-to-JavaScr
ipt compiler</a> for more | 65 from the Dart project. See <a class="xref" href="ch04.html#ch04-tools-dart2j
s" title="dart2js: The Dart-to-JavaScript compiler">dart2js: The Dart-to-JavaScr
ipt compiler</a> for more |
66 information about compiling Dart code into its JavaScript | 66 information about compiling Dart code into its JavaScript |
67 equivalent.</p></div><div class="sect1" title="The client’s Dart code"><div
class="titlepage"><div><div><h1 class="title"id="ch05-client-dart-code"/>The cli
ent’s Dart code</h1></div></div></div><p>Dart code (client/chat-client.dart) pro
vides the client’s logic, | 67 equivalent.</p></div><div class="sect1" title="The client’s Dart code"><div
class="titlepage"><div><div><h2 class="title"id="ch05-client-dart-code"/>The cli
ent’s Dart code</h2></div></div></div><p>Dart code (client/chat-client.dart) pro
vides the client’s logic, |
68 using the DOM to interact with UI elements. For example, the client’s Dart | 68 using the DOM to interact with UI elements. For example, the client’s Dart |
69 code uses the DOM to find the text area where the client displays | 69 code uses the DOM to find the text area where the client displays |
70 messages.</p><div class="sect2" title="Finding DOM elements"><div class="tit
lepage"><div><div><h2 class="title"id="id641182"/>Finding DOM elements</h2></div
></div></div><p>The client app uses dart:html’s top-level query() method to get | 70 messages.</p><div class="sect2" title="Finding DOM elements"><div class="tit
lepage"><div><div><h3 class="title"id="id641182"/>Finding DOM elements</h3></div
></div></div><p>The client app uses dart:html’s top-level query() method to get |
71 the client’s UI elements from the DOM.</p><pre class="programlisting">// I
n client/chat-client.dart: | 71 the client’s UI elements from the DOM.</p><pre class="programlisting">// I
n client/chat-client.dart: |
72 import 'dart:html'; | 72 import 'dart:html'; |
73 //... | 73 //... |
74 TextAreaElement chatElem = query('#chat-display'); | 74 TextAreaElement chatElem = query('#chat-display'); |
75 InputElement usernameElem = query('#chat-username'); | 75 InputElement usernameElem = query('#chat-username'); |
76 InputElement messageElem = query('#chat-message');</pre><p>The query() method us
es a selector string that identifies an | 76 InputElement messageElem = query('#chat-message');</pre><p>The query() method us
es a selector string that identifies an |
77 element in the DOM. See <a class="xref" href="ch03.html#ch03-finding-eleme
nts" title="Finding elements">Finding elements</a> for | 77 element in the DOM. See <a class="xref" href="ch03.html#ch03-finding-eleme
nts" title="Finding elements">Finding elements</a> for |
78 more about selectors.</p></div><div class="sect2" title="Wrapping DOM elem
ents"><div class="titlepage"><div><div><h2 class="title"id="id641208"/>Wrapping
DOM elements</h2></div></div></div><p>Rather than always dealing with DOM APIs,
the chat client wraps | 78 more about selectors.</p></div><div class="sect2" title="Wrapping DOM elem
ents"><div class="titlepage"><div><div><h3 class="title"id="id641208"/>Wrapping
DOM elements</h3></div></div></div><p>Rather than always dealing with DOM APIs,
the chat client wraps |
79 the elements in Dart objects:</p><pre class="programlisting">chatWindow =
new ChatWindow(chatElem); | 79 the elements in Dart objects:</p><pre class="programlisting">chatWindow =
new ChatWindow(chatElem); |
80 usernameInput = new UsernameInput(usernameElem); | 80 usernameInput = new UsernameInput(usernameElem); |
81 messageInput = new MessageInput(messageElem);</pre><p>ChatWindow, UsernameInput,
and MessageInput are custom classes | 81 messageInput = new MessageInput(messageElem);</pre><p>ChatWindow, UsernameInput,
and MessageInput are custom classes |
82 that extend another custom class called View. These Views effectively | 82 that extend another custom class called View. These Views effectively |
83 separate the DOM manipulation from the application logic.</p><p>Because Da
rt has real classes and inheritance, it’s simple to | 83 separate the DOM manipulation from the application logic.</p><p>Because Da
rt has real classes and inheritance, it’s simple to |
84 express the relationship that ChatWindow is-a View. Here’s the complete | 84 express the relationship that ChatWindow is-a View. Here’s the complete |
85 code for UsernameInput:</p><pre class="programlisting">class UsernameInput
extends View<InputElement> { | 85 code for UsernameInput:</p><pre class="programlisting">class UsernameInput
extends View<InputElement> { |
86 UsernameInput(InputElement elem) : super(elem); | 86 UsernameInput(InputElement elem) : super(elem); |
87 | 87 |
88 bind() { // Called by the View constructor. | 88 bind() { // Called by the View constructor. |
(...skipping 11 matching lines...) Expand all Loading... |
100 String get username => elem.value; | 100 String get username => elem.value; |
101 }</pre><p>To get the string that’s in the chat-username field, the client | 101 }</pre><p>To get the string that’s in the chat-username field, the client |
102 app uses the <code class="literal">username</code> getter of a UsernameInp
ut | 102 app uses the <code class="literal">username</code> getter of a UsernameInp
ut |
103 object. For example:</p><pre class="programlisting">chatWindow.displayMess
age(message, usernameInput.username);</pre><p>Notice how the code uses generics
(View<InputElement>) to | 103 object. For example:</p><pre class="programlisting">chatWindow.displayMess
age(message, usernameInput.username);</pre><p>Notice how the code uses generics
(View<InputElement>) to |
104 specify what kind of element the View class can encapsulate. In the | 104 specify what kind of element the View class can encapsulate. In the |
105 preceding example, the UsernameInput wraps an <a class="ulink" href="http:
//api.dartlang.org/dart_html/InputElement.html">InputElement.</a> | 105 preceding example, the UsernameInput wraps an <a class="ulink" href="http:
//api.dartlang.org/dart_html/InputElement.html">InputElement.</a> |
106 Expressing this gives tools information that they can use to identify | 106 Expressing this gives tools information that they can use to identify |
107 bugs or improve code completion.</p><p>Wrapping elements is a technique yo
u can use as you develop a | 107 bugs or improve code completion.</p><p>Wrapping elements is a technique yo
u can use as you develop a |
108 simple app that might evolve into a larger app. As the app grows, you | 108 simple app that might evolve into a larger app. As the app grows, you |
109 might change it to use a real <a class="ulink" href="http://en.wikipedia.o
rg/wiki/Model-view-controller">model-view-controller | 109 might change it to use a real <a class="ulink" href="http://en.wikipedia.o
rg/wiki/Model-view-controller">model-view-controller |
110 (MVC) architecture.</a></p><div class="note" title="Note"><h3 class="title
">Note</h3><p>We expect the Dart project to provide an MVC-type framework for | 110 (MVC) architecture.</a></p><div class="note" title="Note"><h4 class="title
">Note</h4><p>We expect the Dart project to provide an MVC-type framework for |
111 clients.</p></div></div><div class="sect2" title="Updating DOM elements"
><div class="titlepage"><div><div><h2 class="title"id="id641289"/>Updating DOM e
lements</h2></div></div></div><p>The bind() method sets up the event handlers, w
hich bind events | 111 clients.</p></div></div><div class="sect2" title="Updating DOM elements"
><div class="titlepage"><div><div><h3 class="title"id="id641289"/>Updating DOM e
lements</h3></div></div></div><p>The bind() method sets up the event handlers, w
hich bind events |
112 from the DOM to logic in the Dart objects. For example, in | 112 from the DOM to logic in the Dart objects. For example, in |
113 UsernameInput, the _onUsernameChange() method is called any time the | 113 UsernameInput, the _onUsernameChange() method is called any time the |
114 text in the input element changes.</p><p>To display messages in the chat w
indow, the ChatWindow class adds | 114 text in the input element changes.</p><p>To display messages in the chat w
indow, the ChatWindow class adds |
115 the message to the text node of the text area.</p><pre class="programlisti
ng">class ChatWindow extends View<TextAreaElement> { | 115 the message to the text node of the text area.</p><pre class="programlisti
ng">class ChatWindow extends View<TextAreaElement> { |
116 ChatWindow(TextAreaElement elem) : super(elem); | 116 ChatWindow(TextAreaElement elem) : super(elem); |
117 | 117 |
118 displayMessage(String msg, String from) { | 118 displayMessage(String msg, String from) { |
119 _display('$from: $msg\n'); | 119 _display('$from: $msg\n'); |
120 } | 120 } |
121 | 121 |
122 displayNotice(String notice) { | 122 displayNotice(String notice) { |
123 _display('[system]: $notice\n'); | 123 _display('[system]: $notice\n'); |
124 } | 124 } |
125 | 125 |
126 _display(String str) { | 126 _display(String str) { |
127 elem.addText(str); | 127 elem.addText(str); |
128 } | 128 } |
129 }</pre><p>In both examples, the View objects expose an application-specific | 129 }</pre><p>In both examples, the View objects expose an application-specific |
130 API—for example, displayMessage() or _onUsernameChange()—and encapsulate | 130 API—for example, displayMessage() or _onUsernameChange()—and encapsulate |
131 the manipulation of DOM elements.</p></div><div class="sect2" title="Encod
ing and decoding messages"><div class="titlepage"><div><div><h2 class="title"id=
"ch05-dart-json"/>Encoding and decoding messages</h2></div></div></div><p>The da
rt:json library encodes and decodes JSON-formatted messages. | 131 the manipulation of DOM elements.</p></div><div class="sect2" title="Encod
ing and decoding messages"><div class="titlepage"><div><div><h3 class="title"id=
"ch05-dart-json"/>Encoding and decoding messages</h3></div></div></div><p>The da
rt:json library encodes and decodes JSON-formatted messages. |
132 JSON is an easy way to provide string message data to WebSockets. Using | 132 JSON is an easy way to provide string message data to WebSockets. Using |
133 JSON also gives a bit of structure to the messages and leaves the door | 133 JSON also gives a bit of structure to the messages and leaves the door |
134 open to creating more detailed messages in the future.</p><p>The stringify
() method converts a Dart object to a JSON encoded | 134 open to creating more detailed messages in the future.</p><p>The stringify
() method converts a Dart object to a JSON encoded |
135 string, and the parse() method converts a JSON string back into a Dart | 135 string, and the parse() method converts a JSON string back into a Dart |
136 object. Here’s the JSON-related code from the chat client:</p><pre class="
programlisting">import 'dart:json'; | 136 object. Here’s the JSON-related code from the chat client:</p><pre class="
programlisting">import 'dart:json'; |
137 | 137 |
138 var encoded = JSON.stringify({'f': from, 'm': message}); | 138 var encoded = JSON.stringify({'f': from, 'm': message}); |
139 Map message = JSON.parse(encodedMessage);</pre><p>See <a class="xref" href="ch03
.html#ch03-json" title="dart:json - Encoding and decoding objects">dart:json - E
ncoding and decoding objects</a> for more information.</p></div><div class="sect
2" title="Communicating with WebSockets"><div class="titlepage"><div><div><h2 cl
ass="title"id="id641357"/>Communicating with WebSockets</h2></div></div></div><p
>The custom class ChatConnection takes care of the chat client’s | 139 Map message = JSON.parse(encodedMessage);</pre><p>See <a class="xref" href="ch03
.html#ch03-json" title="dart:json - Encoding and decoding objects">dart:json - E
ncoding and decoding objects</a> for more information.</p></div><div class="sect
2" title="Communicating with WebSockets"><div class="titlepage"><div><div><h3 cl
ass="title"id="id641357"/>Communicating with WebSockets</h3></div></div></div><p
>The custom class ChatConnection takes care of the chat client’s |
140 WebSocket communication. First it connects to the WebSocket by calling | 140 WebSocket communication. First it connects to the WebSocket by calling |
141 the WebSocket constructor with the argument | 141 the WebSocket constructor with the argument |
142 <code class="literal">'ws://127.0.0.1:1337/ws'</code>. Then ChatConnection
adds | 142 <code class="literal">'ws://127.0.0.1:1337/ws'</code>. Then ChatConnection
adds |
143 event handlers for open, close, error, and message events, using the | 143 event handlers for open, close, error, and message events, using the |
144 WebSocketEvents object it gets from webSocket.on. For example, here’s | 144 WebSocketEvents object it gets from webSocket.on. For example, here’s |
145 the code that responds to message events:</p><pre class="programlisting">w
ebSocket.on.message.add((MessageEvent e) { | 145 the code that responds to message events:</p><pre class="programlisting">w
ebSocket.on.message.add((MessageEvent e) { |
146 print('received message ${e.data}'); | 146 print('received message ${e.data}'); |
147 _receivedEncodedMessage(e.data); | 147 _receivedEncodedMessage(e.data); |
148 });</pre><p>The _receivedEncodedMessage() method just parses the JSON data and | 148 });</pre><p>The _receivedEncodedMessage() method just parses the JSON data and |
149 displays it in the status area.</p><pre class="programlisting">_receivedEn
codedMessage(String encodedMessage) { | 149 displays it in the status area.</p><pre class="programlisting">_receivedEn
codedMessage(String encodedMessage) { |
(...skipping 29 matching lines...) Expand all Loading... |
179 if (!encounteredError) { | 179 if (!encounteredError) { |
180 window.setTimeout(() => _init(retrySeconds*2), 1000*retrySeconds); | 180 window.setTimeout(() => _init(retrySeconds*2), 1000*retrySeconds); |
181 } | 181 } |
182 encounteredError = true; | 182 encounteredError = true; |
183 } | 183 } |
184 | 184 |
185 //... | 185 //... |
186 | 186 |
187 webSocket.on.close.add((e) => scheduleReconnect()); | 187 webSocket.on.close.add((e) => scheduleReconnect()); |
188 webSocket.on.error.add((e) => scheduleReconnect());</pre><p>The reconnect l
ogic uses setTimeout() to schedule a retry using an | 188 webSocket.on.error.add((e) => scheduleReconnect());</pre><p>The reconnect l
ogic uses setTimeout() to schedule a retry using an |
189 exponential backoff algorithm.</p></div></div><div class="sect1" title="Th
e server’s code"><div class="titlepage"><div><div><h1 class="title"id="ch05-serv
er"/>The server’s code</h1></div></div></div><p>The chat-server.dart file contai
ns most of the code used in the chat | 189 exponential backoff algorithm.</p></div></div><div class="sect1" title="Th
e server’s code"><div class="titlepage"><div><div><h2 class="title"id="ch05-serv
er"/>The server’s code</h2></div></div></div><p>The chat-server.dart file contai
ns most of the code used in the chat |
190 server. It is responsible for serving static files and managing WebSocket | 190 server. It is responsible for serving static files and managing WebSocket |
191 connections. The chat server also logs the chat messages to a file.</p><div
class="sect2" title="Serving static files"><div class="titlepage"><div><div><h2
class="title"id="id641449"/>Serving static files</h2></div></div></div><p>The ch
at server uses dart:io’s HttpServer to implement a web | 191 connections. The chat server also logs the chat messages to a file.</p><div
class="sect2" title="Serving static files"><div class="titlepage"><div><div><h3
class="title"id="id641449"/>Serving static files</h3></div></div></div><p>The ch
at server uses dart:io’s HttpServer to implement a web |
192 server. The default request handler is configured to serve static files | 192 server. The default request handler is configured to serve static files |
193 from a specific directory on the file system.</p><pre class="programlistin
g">runServer(String basePath, int port) { | 193 from a specific directory on the file system.</p><pre class="programlistin
g">runServer(String basePath, int port) { |
194 HttpServer server = new HttpServer(); | 194 HttpServer server = new HttpServer(); |
195 server.defaultRequestHandler = new StaticFileHandler(basePath).onRequest; | 195 server.defaultRequestHandler = new StaticFileHandler(basePath).onRequest; |
196 //... | 196 //... |
197 server.onError = (error) => print(error); | 197 server.onError = (error) => print(error); |
198 server.listen('127.0.0.1', 1337); | 198 server.listen('127.0.0.1', 1337); |
199 print('listening for connections on $port'); | 199 print('listening for connections on $port'); |
200 } | 200 } |
201 | 201 |
(...skipping 13 matching lines...) Expand all Loading... |
215 onRequest(HttpRequest request, HttpResponse response) { | 215 onRequest(HttpRequest request, HttpResponse response) { |
216 //... | 216 //... |
217 file.exists().then((found) { | 217 file.exists().then((found) { |
218 if (found) { | 218 if (found) { |
219 // ...Respond with the file’s contents... | 219 // ...Respond with the file’s contents... |
220 } else { | 220 } else { |
221 // ...Send a 404 response... | 221 // ...Send a 404 response... |
222 } | 222 } |
223 });</pre><p>See <a class="xref" href="ch03.html#ch03-asynchronous-programming"
title="Asynchronous programming">Asynchronous programming</a> for more | 223 });</pre><p>See <a class="xref" href="ch03.html#ch03-asynchronous-programming"
title="Asynchronous programming">Asynchronous programming</a> for more |
224 information about using Future, and <a class="xref" href="ch03.html#ch03-f
iles-and-directories" title="Files and directories">Files and directories</a> fo
r details on file and | 224 information about using Future, and <a class="xref" href="ch03.html#ch03-f
iles-and-directories" title="Files and directories">Files and directories</a> fo
r details on file and |
225 directory I/O.</p></div><div class="sect2" title="Managing WebSocket conne
ctions"><div class="titlepage"><div><div><h2 class="title"id="id641516"/>Managin
g WebSocket connections</h2></div></div></div><p>In addition to serving static f
iles, the chat server manages | 225 directory I/O.</p></div><div class="sect2" title="Managing WebSocket conne
ctions"><div class="titlepage"><div><div><h3 class="title"id="id641516"/>Managin
g WebSocket connections</h3></div></div></div><p>In addition to serving static f
iles, the chat server manages |
226 WebSocket connections, routing chat messages between clients. The | 226 WebSocket connections, routing chat messages between clients. The |
227 dart:io WebSocketHandler class accepts HTTP connections, converts them | 227 dart:io WebSocketHandler class accepts HTTP connections, converts them |
228 into WebSocket connections, and then passes them to ChatHandler.</p><pre c
lass="programlisting">runServer(String basePath, int port) { | 228 into WebSocket connections, and then passes them to ChatHandler.</p><pre c
lass="programlisting">runServer(String basePath, int port) { |
229 //... | 229 //... |
230 WebSocketHandler wsHandler = new WebSocketHandler(); | 230 WebSocketHandler wsHandler = new WebSocketHandler(); |
231 wsHandler.onOpen = new ChatHandler(basePath).onOpen; | 231 wsHandler.onOpen = new ChatHandler(basePath).onOpen; |
232 }</pre><p>ChatHandler is a custom class that takes care of all WebSocket | 232 }</pre><p>ChatHandler is a custom class that takes care of all WebSocket |
233 communication for the chat server. Here is its implementation.</p><pre cla
ss="programlisting">class ChatHandler { | 233 communication for the chat server. Here is its implementation.</p><pre cla
ss="programlisting">class ChatHandler { |
234 Set<WebSocketConnection> connections; | 234 Set<WebSocketConnection> connections; |
235 //... | 235 //... |
(...skipping 14 matching lines...) Expand all Loading... |
250 }; | 250 }; |
251 | 251 |
252 conn.onError = (e) { | 252 conn.onError = (e) { |
253 connections.remove(conn); | 253 connections.remove(conn); |
254 }; | 254 }; |
255 } | 255 } |
256 }</pre><p>When a client connects, the server adds the client’s WebSocket | 256 }</pre><p>When a client connects, the server adds the client’s WebSocket |
257 connection to a collection. When the client disconnects (either through | 257 connection to a collection. When the client disconnects (either through |
258 an error or on purpose), the server removes that client’s connection | 258 an error or on purpose), the server removes that client’s connection |
259 from the collection. When a new message arrives, the server sends the | 259 from the collection. When a new message arrives, the server sends the |
260 message to all connected clients except the original source.</p></div><div
class="sect2" title="Logging messages to a file"><div class="titlepage"><div><d
iv><h2 class="title"id="id641560"/>Logging messages to a file</h2></div></div></
div><p>The chat server logs data to a file, client/chat-log.txt, using a | 260 message to all connected clients except the original source.</p></div><div
class="sect2" title="Logging messages to a file"><div class="titlepage"><div><d
iv><h3 class="title"id="id641560"/>Logging messages to a file</h3></div></div></
div><p>The chat server logs data to a file, client/chat-log.txt, using a |
261 custom library implemented in file-logger.dart. This library uses an | 261 custom library implemented in file-logger.dart. This library uses an |
262 isolate to handle file I/O without tying up the root isolate. Here’s the | 262 isolate to handle file I/O without tying up the root isolate. Here’s the |
263 code that creates and starts this isolate:</p><pre class="programlisting">
SendPort _loggingPort = spawnFunction(startLogging);</pre><p>The value returned
by dart:isolate’s spawnFunction() is a SendPort | 263 code that creates and starts this isolate:</p><pre class="programlisting">
SendPort _loggingPort = spawnFunction(startLogging);</pre><p>The value returned
by dart:isolate’s spawnFunction() is a SendPort |
264 object. Because isolates share no data, messages sent to ports are the | 264 object. Because isolates share no data, messages sent to ports are the |
265 only way for the root isolate to communicate with the spawned | 265 only way for the root isolate to communicate with the spawned |
266 isolate.</p><p>The argument to spawnFunction() points to the startLogging(
) | 266 isolate.</p><p>The argument to spawnFunction() points to the startLogging(
) |
267 function, which implements the logging isolate. The logic for the | 267 function, which implements the logging isolate. The logic for the |
268 logging isolate is simple: the first message specifies the log file | 268 logging isolate is simple: the first message specifies the log file |
269 location, and subsequent messages provide data to write to the log | 269 location, and subsequent messages provide data to write to the log |
270 file.</p><pre class="programlisting">startLogging() { | 270 file.</p><pre class="programlisting">startLogging() { |
(...skipping 14 matching lines...) Expand all Loading... |
285 }</pre><p>In the preceding code, the port property used by startLogging() | 285 }</pre><p>In the preceding code, the port property used by startLogging() |
286 refers to a ReceivePort provided by dart:isolate. The port is how this | 286 refers to a ReceivePort provided by dart:isolate. The port is how this |
287 isolate gets data from the root isolate. If this isolate needed to send | 287 isolate gets data from the root isolate. If this isolate needed to send |
288 messages back to the root isolate, it could use the replyTo argument (a | 288 messages back to the root isolate, it could use the replyTo argument (a |
289 SendPort) to do so.</p><p>Recall that in the root isolate, the _loggingPor
t variable holds a | 289 SendPort) to do so.</p><p>Recall that in the root isolate, the _loggingPor
t variable holds a |
290 SendPort that the root isolate uses to send messages to the logging | 290 SendPort that the root isolate uses to send messages to the logging |
291 isolate. Every time the chat server calls the log() method, the root | 291 isolate. Every time the chat server calls the log() method, the root |
292 isolate sends the log data:</p><pre class="programlisting">void log(String
message) { | 292 isolate sends the log data:</p><pre class="programlisting">void log(String
message) { |
293 _loggingPort.send(message); | 293 _loggingPort.send(message); |
294 }</pre><p>See <a class="xref" href="ch03.html#ch03-dartisolate---concurrency-wit
h-isolates" title="dart:isolate - Concurrency with isolates">dart:isolate - Conc
urrency with isolates</a> for more | 294 }</pre><p>See <a class="xref" href="ch03.html#ch03-dartisolate---concurrency-wit
h-isolates" title="dart:isolate - Concurrency with isolates">dart:isolate - Conc
urrency with isolates</a> for more |
295 information about using isolates.</p></div></div><div class="sect1" title=
"What next?"><div class="titlepage"><div><div><h1 class="title"id="ch05-what-nex
t"/>What next?</h1></div></div></div><p>You’ve seen how the Dart Chat sample use
s both server-side and | 295 information about using isolates.</p></div></div><div class="sect1" title=
"What next?"><div class="titlepage"><div><div><h2 class="title"id="ch05-what-nex
t"/>What next?</h2></div></div></div><p>You’ve seen how the Dart Chat sample use
s both server-side and |
296 client-side Dart code to implement a web app. Here are some other samples | 296 client-side Dart code to implement a web app. Here are some other samples |
297 you might want to look at:</p><div class="itemizedlist"><ul class="itemizedl
ist"><li class="listitem"><p><a class="ulink" href="https://code.google.com/p/da
rt/source/browse/#svn%2Ftrunk%2Fdart%2Fsamples%2Fsolar"> | 297 you might want to look at:</p><div class="itemizedlist"><ul class="itemizedl
ist"><li class="listitem"><p><a class="ulink" href="https://code.google.com/p/da
rt/source/browse/#svn%2Ftrunk%2Fdart%2Fsamples%2Fsolar"> |
298 Solar,</a> which simulates the solar system with animations in a | 298 Solar,</a> which simulates the solar system with animations in a |
299 canvas, using requestAnimationFrame().</p></li><li class="listitem"><p><
a class="ulink" href="https://code.google.com/p/dart/source/browse/#svn%2Ftrunk%
2Fdart%2Fsamples%2Fspirodraw"> | 299 canvas, using requestAnimationFrame().</p></li><li class="listitem"><p><
a class="ulink" href="https://code.google.com/p/dart/source/browse/#svn%2Ftrunk%
2Fdart%2Fsamples%2Fspirodraw"> |
300 Spirodraw,</a> a fun, interactive tool to build colorful works of | 300 Spirodraw,</a> a fun, interactive tool to build colorful works of |
301 art.</p></li></ul></div><p>Finally, please visit our website and join th
e discussion. We look | 301 art.</p></li></ul></div><p>Finally, please visit our website and join th
e discussion. We look |
302 forward to hearing from you!</p><div class="itemizedlist"><ul class="itemize
dlist"><li class="listitem"><p> | 302 forward to hearing from you!</p><div class="itemizedlist"><ul class="itemize
dlist"><li class="listitem"><p> |
303 <a class="ulink" href="http://www.dartlang.org">Dart | 303 <a class="ulink" href="http://www.dartlang.org">Dart |
304 website</a> | 304 website</a> |
305 </p></li><li class="listitem"><p> | 305 </p></li><li class="listitem"><p> |
306 <a class="ulink" href="http://www.dartlang.org/mailing-list"> Dart | 306 <a class="ulink" href="http://www.dartlang.org/mailing-list"> Dart |
307 discussion group</a> | 307 discussion group</a> |
308 </p></li><li class="listitem"><p> | 308 </p></li><li class="listitem"><p> |
309 <a class="ulink" href="http://stackoverflow.com/tags/dart"> Dart | 309 <a class="ulink" href="http://stackoverflow.com/tags/dart"> Dart |
310 questions on Stack Overflow</a> | 310 questions on Stack Overflow</a> |
311 </p></li></ul> | 311 </p></li></ul> |
OLD | NEW |