Skip to content
This repository was archived by the owner on May 25, 2022. It is now read-only.

Commit b8751b4

Browse files
authored
Merge pull request #35 from davidmorgan/add-chat-example
Add chat example.
2 parents 07f3486 + 6d23c52 commit b8751b4

31 files changed

+1933
-1
lines changed

.travis.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,9 @@ script:
66
- pub run test
77
- cd ../example
88
- pub get
9-
- pub run tool/build.dart
9+
- dart tool/build.dart
10+
- pub run test
11+
- cd ../chat_example
12+
- pub get
13+
- dart tool/build.dart
1014
- pub run test

chat_example/.analysis_options

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
analyzer:
2+
strong-mode: true

chat_example/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# built_json chat example
2+
3+
A simple chat client (dart2js) and server (Dart VM).
4+
5+
Launch the server:
6+
7+
`dart bin/main.dart`
8+
9+
This will immediately work in Dartium, connect to `localhost:26199`. To build for js, run:
10+
11+
`pub build`
12+
13+
When developing, run
14+
15+
`dart tool/watch.dart`
16+
17+
to continuously update generated source.

chat_example/bin/main.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
import 'package:chat_example/server/http_server_connection.dart';
6+
import 'package:chat_example/server/resource_server.dart';
7+
import 'package:chat_example/server/server.dart';
8+
9+
void main() {
10+
final server = new Server();
11+
new ResourceServer().start(
12+
(webSocket) => server.addConnection(new HttpServerConnection(webSocket)));
13+
}

chat_example/lib/client/client.dart

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
import 'dart:convert';
7+
8+
import 'package:chat_example/client/client_connection.dart';
9+
import 'package:chat_example/client/display.dart';
10+
import 'package:chat_example/data_model/data_model.dart';
11+
import 'package:chat_example/data_model/serializers.dart';
12+
13+
typedef CommandRunner(String command);
14+
15+
/// Client-side logic for built_json chat example.
16+
class Client {
17+
final Stream<String> _keyboardInput;
18+
final Display _display;
19+
final ClientConnection _connection;
20+
21+
/// A chat client needs a keyboard, a display and a connection.
22+
Client(this._keyboardInput, this._display, this._connection) {
23+
_keyboardInput.listen(_runLocalCommand);
24+
_connection.dataFromServer.listen(_handleServerData);
25+
}
26+
27+
void _handleServerData(String data) {
28+
final response = serializers.deserialize(JSON.decode(data));
29+
30+
if (response is Response) {
31+
_display.add(response.render());
32+
} else {
33+
throw new StateError('Invalid data from server: $response');
34+
}
35+
}
36+
37+
void _runLocalCommand(String command) {
38+
final handlers = <String, CommandRunner>{
39+
'/away': _runAway,
40+
'/help': _runHelp,
41+
'/list': _runList,
42+
'/login': _runLogin,
43+
'/quit': _runQuit,
44+
'/status': _runStatus,
45+
'/tell': _runTell,
46+
};
47+
48+
var found = false;
49+
handlers.forEach((prefix, commandRunner) {
50+
if (command.startsWith(prefix)) {
51+
commandRunner(command);
52+
found = true;
53+
}
54+
});
55+
if (found) return;
56+
57+
if (command.startsWith('/')) {
58+
_display.addLocal(command);
59+
_display.add('Unknown command.');
60+
return;
61+
}
62+
63+
_send(new Chat((b) => b..text = command));
64+
}
65+
66+
void _runAway(String command) {
67+
_send(new Status((b) => b
68+
..message = command.substring('/away '.length)
69+
..type = StatusType.away));
70+
}
71+
72+
void _runHelp(String command) {
73+
_display.add('''Commands:
74+
75+
/away <message> -- sets away message
76+
/help -- for help
77+
/list -- list online users
78+
/login <username> <password> -- log in or create new user
79+
/quit <message> -- quits with message
80+
/status <message> -- sets status message
81+
/tell <username> <message> -- private message
82+
''');
83+
}
84+
85+
void _runList(String command) {
86+
_display.addLocal(command);
87+
_send(new ListUsers(
88+
(b) => b..statusTypes.replace([StatusType.online, StatusType.away])));
89+
}
90+
91+
void _runLogin(String command) {
92+
final words = command.split(' ');
93+
_display.addLocal('/login ${words[1]} ********');
94+
_send(new Login((b) => b
95+
..username = words[1]
96+
..password = words[2]));
97+
}
98+
99+
void _runQuit(String command) {
100+
_display.addLocal(command);
101+
_send(new Status((b) => b
102+
..message = command.substring('/quit '.length)
103+
..type = StatusType.offline));
104+
}
105+
106+
void _runStatus(String command) {
107+
_display.addLocal(command);
108+
_display.addLocal(command);
109+
_send(new Status((b) => b
110+
..message = command.substring('/status '.length)
111+
..type = StatusType.online));
112+
}
113+
114+
void _runTell(String command) {
115+
_display.addLocal(command);
116+
final words = command.split(' ');
117+
final targets = words[1].split(',');
118+
_send(new Chat((b) => b
119+
..text = words.sublist(2).join(' ')
120+
..targets.replace(targets)));
121+
}
122+
123+
void _send(Command command) {
124+
_connection.sendToServer(JSON.encode(serializers.serialize(command)));
125+
}
126+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
/// Two-way connection between client and server; the client.
8+
abstract class ClientConnection {
9+
Stream<String> get dataFromServer;
10+
11+
void sendToServer(String string);
12+
}

chat_example/lib/client/display.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
/// Chat window main text display.
6+
abstract class Display {
7+
/// Adds [text] to the display, coloured to indicate a local command.
8+
void addLocal(String text);
9+
10+
/// Adds [text] to the display.
11+
void add(String text);
12+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
import 'dart:html';
7+
8+
import 'package:chat_example/client/display.dart';
9+
10+
/// [Display] using `dart:html`.
11+
class HtmlDisplay implements Display {
12+
final Element _element;
13+
final HtmlEscape _htmlEscape = const HtmlEscape();
14+
15+
factory HtmlDisplay() {
16+
return new HtmlDisplay._(querySelector('#text'));
17+
}
18+
19+
HtmlDisplay._(this._element) {
20+
add('Welcome to the built_json chat example. For help, type /help.');
21+
}
22+
23+
void addLocal(String text) {
24+
_element.innerHtml +=
25+
'<div class="local">${_htmlEscape.convert(text)}</div>';
26+
window.scrollTo(0, document.body.scrollHeight);
27+
}
28+
29+
void add(String text) {
30+
_element.innerHtml +=
31+
'${_htmlEscape.convert(text).replaceAll('\n', '<br>')}<br>';
32+
window.scrollTo(0, document.body.scrollHeight);
33+
}
34+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
import 'dart:html';
7+
8+
import 'package:chat_example/client/client_connection.dart';
9+
10+
/// [ClientConnection] using a web socket.
11+
class HttpClientConnection implements ClientConnection {
12+
final WebSocket _websocket;
13+
final StreamController<String> _streamController =
14+
new StreamController<String>();
15+
16+
factory HttpClientConnection() {
17+
return new HttpClientConnection._(
18+
new WebSocket('ws://${window.location.host}/ws'));
19+
}
20+
21+
HttpClientConnection._(this._websocket) {
22+
_websocket.onMessage.listen((message) {
23+
_streamController.add(message.data as String);
24+
});
25+
}
26+
27+
Stream<String> get dataFromServer => _streamController.stream;
28+
29+
void sendToServer(String data) {
30+
_websocket.send(data);
31+
}
32+
}

chat_example/lib/client/input.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
import 'dart:html';
7+
8+
/// An input box using `dart:html`.
9+
class Input {
10+
final StreamController<String> _streamController =
11+
new StreamController<String>();
12+
13+
Input() {
14+
final input = querySelector('#input') as InputElement;
15+
16+
input.onKeyPress.listen((keyEvent) {
17+
if (keyEvent.keyCode == KeyCode.ENTER) {
18+
_streamController.add(input.value);
19+
input.value = '';
20+
}
21+
});
22+
}
23+
24+
Stream<String> get keyboardInput => _streamController.stream;
25+
}

chat_example/lib/client/layout.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.
2+
// All rights reserved. Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
import 'dart:html';
6+
7+
/// Forces focus to the input box.
8+
class Layout {
9+
Layout() {
10+
final screen = querySelector('#screen');
11+
final text = querySelector('#text');
12+
final input = querySelector('#input');
13+
14+
input.focus();
15+
16+
for (final element in [screen, text]) {
17+
element.onClick.listen((e) {
18+
input.focus();
19+
});
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)