Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(249)

Side by Side Diff: pkg/dart2js_incremental/lib/server.dart

Issue 2667793003: Remove dart2js_incremental. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library dart2js_incremental.server;
6
7 import 'dart:io';
8
9 import 'dart:async' show
10 Completer,
11 Future,
12 Stream,
13 StreamController,
14 StreamSubscription;
15
16 import 'dart:convert' show
17 HtmlEscape,
18 JSON,
19 UTF8;
20
21 import 'src/options.dart';
22
23 import 'compiler.dart' show
24 CompilerEvent,
25 IncrementalKind,
26 compile;
27
28 class Conversation {
29 HttpRequest request;
30 HttpResponse response;
31
32 static const String PACKAGES_PATH = '/packages';
33
34 static const String CONTENT_TYPE = HttpHeaders.CONTENT_TYPE;
35
36 static Uri documentRoot = Uri.base;
37
38 static Uri packageRoot = Uri.base.resolve('packages/');
39
40 static Map<Uri, Future<String>> generatedFiles =
41 new Map<Uri, Future<String>>();
42
43 static Map<Uri, StreamController<String>> updateControllers =
44 new Map<Uri, StreamController<String>>();
45
46 Conversation(this.request, this.response);
47
48 onClosed(_) {
49 if (response.statusCode == HttpStatus.OK) return;
50 print('Request for ${request.uri} ${response.statusCode}');
51 }
52
53 Future notFound(Uri uri) {
54 response
55 ..headers.set(CONTENT_TYPE, 'text/html')
56 ..statusCode = HttpStatus.NOT_FOUND
57 ..write(htmlInfo("Not Found", "The file '$uri' could not be found."));
58 return response.close();
59 }
60
61 Future badRequest(String problem) {
62 response
63 ..headers.set(CONTENT_TYPE, 'text/html')
64 ..statusCode = HttpStatus.BAD_REQUEST
65 ..write(
66 htmlInfo("Bad request", "Bad request '${request.uri}': $problem"));
67 return response.close();
68 }
69
70 Future handleSocket() async {
71 StreamController<String> controller = updateControllers[request.uri];
72 if (controller != null) {
73 WebSocket socket = await WebSocketTransformer.upgrade(request);
74 print(
75 "Patches to ${request.uri} will be pushed to "
76 "${request.connectionInfo.remoteAddress.host}:"
77 "${request.connectionInfo.remotePort}.");
78 controller.stream.pipe(socket);
79 } else {
80 response.done
81 .then(onClosed)
82 .catchError(onError);
83 return await notFound(request.uri);
84 }
85 }
86
87 Future handle() {
88 response.done
89 .then(onClosed)
90 .catchError(onError);
91
92 Uri uri = request.uri;
93 if (uri.path.endsWith('/')) {
94 uri = uri.resolve('index.html');
95 }
96 if (uri.path.contains('..') || uri.path.contains('%')) {
97 return notFound(uri);
98 }
99 String path = uri.path;
100 Uri root = documentRoot;
101 if (path.startsWith('${PACKAGES_PATH}/')) {
102 root = packageRoot;
103 path = path.substring(PACKAGES_PATH.length);
104 }
105
106 Uri resolvedRequest = root.resolve('.$path');
107 switch (request.method) {
108 case 'GET':
109 return handleGet(resolvedRequest);
110 default:
111 String method = const HtmlEscape().convert(request.method);
112 return badRequest("Unsupported method: '$method'");
113 }
114 }
115
116 Future handleGet(Uri uri) async {
117 String path = uri.path;
118 var f = new File.fromUri(uri);
119 if (!await f.exists()) {
120 return await handleNonExistingFile(uri);
121 } else {
122 setContentType(path);
123 }
124 return await f.openRead().pipe(response);
125 }
126
127 void setContentType(String path) {
128 if (path.endsWith('.html')) {
129 response.headers.set(CONTENT_TYPE, 'text/html');
130 } else if (path.endsWith('.dart')) {
131 response.headers.set(CONTENT_TYPE, 'application/dart');
132 } else if (path.endsWith('.js')) {
133 response.headers.set(CONTENT_TYPE, 'application/javascript');
134 } else if (path.endsWith('.ico')) {
135 response.headers.set(CONTENT_TYPE, 'image/x-icon');
136 } else if (path.endsWith('.appcache')) {
137 response.headers.set(CONTENT_TYPE, 'text/cache-manifest');
138 } else if (path.endsWith('.css')) {
139 response.headers.set(CONTENT_TYPE, 'text/css');
140 } else if (path.endsWith('.png')) {
141 response.headers.set(CONTENT_TYPE, 'image/png');
142 }
143 }
144
145 Future handleNonExistingFile(Uri uri) async {
146 String path = uri.path;
147 String generated = await generatedFiles[request.uri];
148 if (generated != null) {
149 print("Serving ${request.uri} from memory.");
150 setContentType(path);
151 response.write(generated);
152 return await response.close();
153 }
154 if (path.endsWith('.dart.js')) {
155 Uri dartScript = uri.resolve(path.substring(0, path.length - 3));
156 if (await new File.fromUri(dartScript).exists()) {
157 return await compileToJavaScript(dartScript);
158 }
159 }
160 return await notFound(request.uri);
161 }
162
163 compileToJavaScript(Uri dartScript) {
164 Uri outputUri = request.uri;
165 Completer<String> completer = new Completer<String>();
166 generatedFiles[outputUri] = completer.future;
167 StreamController controller = updateControllers[outputUri];
168 if (controller != null) {
169 controller.close();
170 }
171 updateControllers[outputUri] = new StreamController<String>.broadcast();
172 print("Compiling $dartScript to $outputUri.");
173 StreamSubscription<CompilerEvent> subscription;
174 subscription = compile(dartScript).listen((CompilerEvent event) {
175 subscription.onData(
176 (CompilerEvent event) => onCompilerEvent(completer, event));
177 if (event.kind != IncrementalKind.FULL) {
178 notFound(request.uri);
179 // TODO(ahe): Do something about this situation.
180 } else {
181 print("Done compiling $dartScript to $outputUri.");
182 completer.complete(event['.js']);
183 setContentType(outputUri.path);
184 response.write(event['.js']);
185 response.close();
186 }
187 });
188 }
189
190 onCompilerEvent(Completer completer, CompilerEvent event) {
191 Uri outputUri = request.uri;
192 print("Got ${event.kind} for $outputUri");
193
194 switch (event.kind) {
195 case IncrementalKind.FULL:
196 generatedFiles[outputUri] = new Future.value(event['.js']);
197 break;
198
199 case IncrementalKind.INCREMENTAL:
200 generatedFiles[outputUri] = completer.future.then(
201 (String full) => '$full\n\n${event.compiler.allUpdates()}');
202 pushUpdates(event.updates);
203 break;
204
205 case IncrementalKind.ERROR:
206 generatedFiles.removeKey(outputUri);
207 break;
208 }
209 }
210
211 void pushUpdates(String updates) {
212 if (updates == null) return;
213 StreamController<String> controller = updateControllers[request.uri];
214 if (controller == null) return;
215 print("Adding updates to controller");
216 controller.add(updates);
217 }
218
219 Future dispatch() async {
220 try {
221 return await WebSocketTransformer.isUpgradeRequest(request)
222 ? handleSocket()
223 : handle();
224 } catch (e, s) {
225 onError(e, s);
226 }
227 }
228
229 static Future onRequest(HttpRequest request) async {
230 HttpResponse response = request.response;
231 try {
232 return await new Conversation(request, response).dispatch();
233 } catch (e, s) {
234 try {
235 onStaticError(e, s);
236 return await response.close();
237 } catch (e, s) {
238 onStaticError(e, s);
239 }
240 }
241 }
242
243 Future onError(error, [stack]) async {
244 try {
245 onStaticError(error, stack);
246 return await response.close();
247 } catch (e, s) {
248 onStaticError(e, s);
249 }
250 }
251
252 static void onStaticError(error, [stack]) {
253 if (error is HttpException) {
254 print('Error: ${error.message}');
255 } else {
256 print('Error: ${error}');
257 }
258 if (stack != null) {
259 print(stack);
260 }
261 }
262
263 String htmlInfo(String title, String text) {
264 // No script injection, please.
265 title = const HtmlEscape().convert(title);
266 text = const HtmlEscape().convert(text);
267 return """
268 <!DOCTYPE html>
269 <html lang='en'>
270 <head>
271 <title>$title</title>
272 </head>
273 <body>
274 <h1>$title</h1>
275 <p style='white-space:pre'>$text</p>
276 </body>
277 </html>
278 """;
279 }
280 }
281
282 main(List<String> arguments) async {
283 Options options = Options.parse(arguments);
284 if (options == null) {
285 exit(1);
286 }
287 if (!options.arguments.isEmpty) {
288 Conversation.documentRoot = Uri.base.resolve(options.arguments.single);
289 }
290 Conversation.packageRoot = options.packageRoot;
291 String host = options.host;
292 int port = options.port;
293 try {
294 HttpServer server = await HttpServer.bind(host, port);
295 print('HTTP server started on http://$host:${server.port}/');
296 server.listen(Conversation.onRequest, onError: Conversation.onStaticError);
297 } catch (e) {
298 print("HttpServer.bind error: $e");
299 exit(1);
300 };
301 }
OLDNEW
« no previous file with comments | « pkg/dart2js_incremental/lib/library_updater.dart ('k') | pkg/dart2js_incremental/lib/src/options.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698