| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js_incremental.server; | 5 library dart2js_incremental.server; |
| 6 | 6 |
| 7 import 'dart:io'; | 7 import 'dart:io'; |
| 8 | 8 |
| 9 import 'dart:async' show | 9 import 'dart:async' show |
| 10 Completer, |
| 10 Future, | 11 Future, |
| 11 Stream; | 12 Stream, |
| 13 StreamSubscription; |
| 12 | 14 |
| 13 import 'dart:convert' show | 15 import 'dart:convert' show |
| 14 HtmlEscape, | 16 HtmlEscape, |
| 15 JSON, | 17 JSON, |
| 16 UTF8; | 18 UTF8; |
| 17 | 19 |
| 18 import 'src/options.dart'; | 20 import 'src/options.dart'; |
| 19 | 21 |
| 22 import 'compiler.dart' show |
| 23 CompilerEvent, |
| 24 IncrementalKind, |
| 25 compile; |
| 26 |
| 20 class Conversation { | 27 class Conversation { |
| 21 HttpRequest request; | 28 HttpRequest request; |
| 22 HttpResponse response; | 29 HttpResponse response; |
| 23 | 30 |
| 24 static const String PACKAGES_PATH = '/packages'; | 31 static const String PACKAGES_PATH = '/packages'; |
| 25 | 32 |
| 26 static const String CONTENT_TYPE = HttpHeaders.CONTENT_TYPE; | 33 static const String CONTENT_TYPE = HttpHeaders.CONTENT_TYPE; |
| 27 | 34 |
| 28 static Uri documentRoot = Uri.base; | 35 static Uri documentRoot = Uri.base; |
| 29 | 36 |
| 30 static Uri packageRoot = Uri.base.resolve('packages/'); | 37 static Uri packageRoot = Uri.base.resolve('packages/'); |
| 31 | 38 |
| 39 static Map<Uri, Future<String>> generatedFiles = |
| 40 new Map<Uri, Future<String>>(); |
| 41 |
| 32 Conversation(this.request, this.response); | 42 Conversation(this.request, this.response); |
| 33 | 43 |
| 34 onClosed(_) { | 44 onClosed(_) { |
| 35 if (response.statusCode == HttpStatus.OK) return; | 45 if (response.statusCode == HttpStatus.OK) return; |
| 36 print('Request for ${request.uri} ${response.statusCode}'); | 46 print('Request for ${request.uri} ${response.statusCode}'); |
| 37 } | 47 } |
| 38 | 48 |
| 39 Future notFound(Uri uri) { | 49 Future notFound(Uri uri) { |
| 40 response | 50 response |
| 41 ..headers.set(CONTENT_TYPE, 'text/html') | 51 ..headers.set(CONTENT_TYPE, 'text/html') |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 default: | 105 default: |
| 96 String method = const HtmlEscape().convert(request.method); | 106 String method = const HtmlEscape().convert(request.method); |
| 97 return badRequest("Unsupported method: '$method'"); | 107 return badRequest("Unsupported method: '$method'"); |
| 98 } | 108 } |
| 99 } | 109 } |
| 100 | 110 |
| 101 Future handleGet(Uri uri) async { | 111 Future handleGet(Uri uri) async { |
| 102 String path = uri.path; | 112 String path = uri.path; |
| 103 var f = new File.fromUri(uri); | 113 var f = new File.fromUri(uri); |
| 104 if (!await f.exists()) { | 114 if (!await f.exists()) { |
| 105 if (path.endsWith('.dart.js')) { | 115 return await handleNonExistingFile(uri); |
| 106 Uri dartScript = uri.resolve(path.substring(0, path.length - 3)); | 116 } else { |
| 107 if (await new File.fromUri(dartScript).exists()) { | 117 setContentType(path); |
| 108 return await compileToJavaScript(dartScript); | 118 } |
| 109 } | 119 return await f.openRead().pipe(response); |
| 110 } | 120 } |
| 111 return await notFound(request.uri); | 121 |
| 112 } else if (path.endsWith('.html')) { | 122 void setContentType(String path) { |
| 123 if (path.endsWith('.html')) { |
| 113 response.headers.set(CONTENT_TYPE, 'text/html'); | 124 response.headers.set(CONTENT_TYPE, 'text/html'); |
| 114 } else if (path.endsWith('.dart')) { | 125 } else if (path.endsWith('.dart')) { |
| 115 response.headers.set(CONTENT_TYPE, 'application/dart'); | 126 response.headers.set(CONTENT_TYPE, 'application/dart'); |
| 116 } else if (path.endsWith('.js')) { | 127 } else if (path.endsWith('.js')) { |
| 117 response.headers.set(CONTENT_TYPE, 'application/javascript'); | 128 response.headers.set(CONTENT_TYPE, 'application/javascript'); |
| 118 } else if (path.endsWith('.ico')) { | 129 } else if (path.endsWith('.ico')) { |
| 119 response.headers.set(CONTENT_TYPE, 'image/x-icon'); | 130 response.headers.set(CONTENT_TYPE, 'image/x-icon'); |
| 120 } else if (path.endsWith('.appcache')) { | 131 } else if (path.endsWith('.appcache')) { |
| 121 response.headers.set(CONTENT_TYPE, 'text/cache-manifest'); | 132 response.headers.set(CONTENT_TYPE, 'text/cache-manifest'); |
| 122 } | 133 } |
| 123 return await f.openRead().pipe(response); | |
| 124 } | 134 } |
| 125 | 135 |
| 126 Future compileToJavaScript(Uri dartScript) { | 136 Future handleNonExistingFile(Uri uri) async { |
| 137 String path = uri.path; |
| 138 String generated = await generatedFiles[request.uri]; |
| 139 if (generated != null) { |
| 140 print("Serving ${request.uri} from memory."); |
| 141 setContentType(path); |
| 142 response.write(generated); |
| 143 return await response.close(); |
| 144 } |
| 145 if (path.endsWith('.dart.js')) { |
| 146 Uri dartScript = uri.resolve(path.substring(0, path.length - 3)); |
| 147 if (await new File.fromUri(dartScript).exists()) { |
| 148 return await compileToJavaScript(dartScript); |
| 149 } |
| 150 } |
| 151 return await notFound(request.uri); |
| 152 } |
| 153 |
| 154 compileToJavaScript(Uri dartScript) { |
| 127 Uri outputUri = request.uri; | 155 Uri outputUri = request.uri; |
| 156 Completer<String> completer = new Completer<String>(); |
| 157 generatedFiles[outputUri] = completer.future; |
| 128 print("Compiling $dartScript to $outputUri"); | 158 print("Compiling $dartScript to $outputUri"); |
| 129 // TODO(ahe): Implement this. | 159 StreamSubscription<CompilerEvent> subscription; |
| 130 throw new UnimplementedError("compileToJavaScript"); | 160 subscription = compile(dartScript).listen((CompilerEvent event) { |
| 131 return notFound(request.uri); | 161 subscription.onData( |
| 162 (CompilerEvent event) => onCompilerEvent(completer, event)); |
| 163 if (event.kind != IncrementalKind.FULL) { |
| 164 notFound(request.uri); |
| 165 // TODO(ahe): Do something about this situation. |
| 166 } else { |
| 167 completer.complete(event['.js']); |
| 168 setContentType(outputUri.path); |
| 169 response.write(event['.js']); |
| 170 response.close(); |
| 171 } |
| 172 }); |
| 173 } |
| 174 |
| 175 onCompilerEvent(Completer completer, CompilerEvent event) { |
| 176 Uri outputUri = request.uri; |
| 177 print("Got ${event.kind} for $outputUri"); |
| 178 |
| 179 switch (event.kind) { |
| 180 case IncrementalKind.FULL: |
| 181 generatedFiles[outputUri] = new Future.value(event['.js']); |
| 182 break; |
| 183 |
| 184 case IncrementalKind.INCREMENTAL: |
| 185 generatedFiles[outputUri] = completer.future.then( |
| 186 (String full) => '$full\n\n${event.compiler.allUpdates()}'); |
| 187 break; |
| 188 |
| 189 case IncrementalKind.ERROR: |
| 190 generatedFiles.removeKey(outputUri); |
| 191 break; |
| 192 } |
| 132 } | 193 } |
| 133 | 194 |
| 134 Future dispatch() async { | 195 Future dispatch() async { |
| 135 try { | 196 try { |
| 136 return await WebSocketTransformer.isUpgradeRequest(request) | 197 return await WebSocketTransformer.isUpgradeRequest(request) |
| 137 ? handleSocket() | 198 ? handleSocket() |
| 138 : handle(); | 199 : handle(); |
| 139 } catch (e, s) { | 200 } catch (e, s) { |
| 140 onError(e, s); | 201 onError(e, s); |
| 141 } | 202 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 int port = options.port; | 268 int port = options.port; |
| 208 try { | 269 try { |
| 209 HttpServer server = await HttpServer.bind(host, port); | 270 HttpServer server = await HttpServer.bind(host, port); |
| 210 print('HTTP server started on http://$host:${server.port}/'); | 271 print('HTTP server started on http://$host:${server.port}/'); |
| 211 server.listen(Conversation.onRequest, onError: Conversation.onStaticError); | 272 server.listen(Conversation.onRequest, onError: Conversation.onStaticError); |
| 212 } catch (e) { | 273 } catch (e) { |
| 213 print("HttpServer.bind error: $e"); | 274 print("HttpServer.bind error: $e"); |
| 214 exit(1); | 275 exit(1); |
| 215 }; | 276 }; |
| 216 } | 277 } |
| OLD | NEW |