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

Side by Side Diff: dart/sdk/lib/_internal/compiler/samples/leap_server/leap_server.dart

Issue 197923002: Mock up code completion. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Too many changes to summarize in one line. Created 6 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | dart/site/try/build_try.gyp » ('j') | dart/site/try/index.html » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 leap_server; 5 library leap_server;
6 6
7 import 'dart:io'; 7 import 'dart:io';
8 8
9 import 'dart:convert' show JSON, HtmlEscape;
10
11 class ProjectCommand {
kasperl 2014/03/24 10:32:51 Maybe add a short comment for these classes to giv
ahe 2014/03/24 15:20:23 Done.
12 final String name;
13 final Map<String, String> rules;
14 final Function handle;
15
16 const ProjectCommand(this.name, this.rules, this.handle);
17 }
18
9 class Conversation { 19 class Conversation {
10 HttpRequest request; 20 HttpRequest request;
11 HttpResponse response; 21 HttpResponse response;
12 22
23 static const String PROJECT_PATH = '/project';
24
25 static const String PACKAGES_PATH = '/packages';
26
13 static const String CONTENT_TYPE = HttpHeaders.CONTENT_TYPE; 27 static const String CONTENT_TYPE = HttpHeaders.CONTENT_TYPE;
14 28
15 static const String LEAP_LANDING_PAGE = 29 static Uri documentRoot = Uri.base;
16 'sdk/lib/_internal/compiler/samples/leap/index.html';
17 30
18 static String landingPage = LEAP_LANDING_PAGE; 31 static Uri projectRoot = Uri.base.resolve('site/try/src/');
32
33 static Uri packageRoot = Uri.base.resolve('sdk/lib/_internal/');
34
35 static const List<ProjectCommand> COMMANDS = const <ProjectCommand>[
36 const ProjectCommand('list', const {'list': null}, handleProjectList),
37 ];
kasperl 2014/03/24 10:32:51 Less indentation?
ahe 2014/03/24 15:20:23 Done.
19 38
20 Conversation(this.request, this.response); 39 Conversation(this.request, this.response);
21 40
22 onClosed(_) { 41 onClosed(_) {
23 if (response.statusCode == HttpStatus.OK) return; 42 if (response.statusCode == HttpStatus.OK) return;
24 print('Request for ${request.uri} ${response.statusCode}'); 43 print('Request for ${request.uri} ${response.statusCode}');
25 } 44 }
26 45
27 notFound(path) { 46 notFound(path) {
28 response.statusCode = HttpStatus.NOT_FOUND; 47 response.statusCode = HttpStatus.NOT_FOUND;
29 response.write(htmlInfo('Not Found', 48 response.write(htmlInfo('Not Found',
30 'The file "$path" could not be found.')); 49 'The file "$path" could not be found.'));
31 response.close(); 50 response.close();
32 } 51 }
33 52
34 redirect(String location) { 53 redirect(String location) {
35 response.statusCode = HttpStatus.FOUND; 54 response.statusCode = HttpStatus.FOUND;
36 response.headers.add(HttpHeaders.LOCATION, location); 55 response.headers.add(HttpHeaders.LOCATION, location);
37 response.close(); 56 response.close();
38 } 57 }
39 58
59 badRequest(String problem) {
60 response.statusCode = HttpStatus.BAD_REQUEST;
61 response.write(htmlInfo("Bad request",
62 "Bad request '${request.uri}': $problem"));
63 response.close();
64 }
65
66 bool validate(Map<String, String> parameters, Map<String, String> rules) {
67 String problem;
68 rules.forEach((String name, String desc) {
69 if (problem != null) return;
kasperl 2014/03/24 10:32:51 This seems hacky. How about something like this:
ahe 2014/03/24 15:20:23 Done.
70 if (!parameters.containsKey(name)) {
71 return problem = "Missing parameter: '$name'.";
72 }
73 });
74 if (problem == null) {
75 Set extra = new Set.from(parameters.keys)..removeAll(rules.keys);
76 if (!extra.isEmpty) {
77 String extraString = (extra.toList()..sort()).join("', '");
78 problem = "Extra parameters: '$extraString'.";
79 }
80 }
81 if (problem != null) {
82 badRequest(problem);
83 return false;
84 }
85 return true;
86 }
87
88 static handleProjectList(Conversation self) {
89 String nativeDir = projectRoot.toFilePath();
90 Directory dir = new Directory(nativeDir);
91 var future = dir.list(recursive: true, followLinks: false).toList();
92 future.then((List<FileSystemEntity> entries) {
93 List<String> files = <String>[];
94 for (FileSystemEntity entry in entries) {
kasperl 2014/03/24 10:32:51 List<String> files = entries .map((e) => e.pat
ahe 2014/03/24 15:20:23 Done.
95 String nativePath = entry.path;
96 if (nativePath.endsWith("~")) continue;
97 if (!nativePath.startsWith(nativeDir)) continue;
98 nativePath = nativePath.substring(nativeDir.length);
99 files.add(new Uri.file(nativePath).path);
100 }
101 self.response
102 ..write(JSON.encode(files))
103 ..close();
104 });
105 }
106
107 handleProjectRequest() {
108 Map<String, String> parameters = request.uri.queryParameters;
109 for (ProjectCommand command in COMMANDS) {
110 if (parameters.containsKey(command.name)) {
111 if (validate(parameters, command.rules)) {
112 (command.handle)(this);
113 }
114 return;
115 }
116 }
117 String commands = COMMANDS.map((c) => c.name).join("', '");
118 badRequest("Valid commands are: '$commands'");
119 }
120
40 handle() { 121 handle() {
41 response.done 122 response.done
42 .then(onClosed) 123 .then(onClosed)
43 .catchError(onError); 124 .catchError(onError);
44 125
45 String path = request.uri.path; 126 Uri uri = request.uri;
46 if (path == '/') return redirect('/$landingPage'); 127 if (uri.path == PROJECT_PATH) {
47 if (path == '/favicon.ico') { 128 return handleProjectRequest();
48 path = '/sdk/lib/_internal/dartdoc/static/favicon.ico';
49 } 129 }
50 if (path.contains('..') || path.contains('%')) return notFound(path); 130 if (uri.path.endsWith('/')) {
51 var f = new File("./$path"); 131 uri = uri.resolve('index.html');
132 }
133 if (uri.path == '/css/fonts/fontawesome-webfont.woff') {
134 uri = uri.resolve('/fontawesome-webfont.woff');
135 }
136 if (uri.path.contains('..') || uri.path.contains('%')) {
137 return notFound(uri.path);
138 }
139 String path = uri.path;
140 Uri root = documentRoot;
141 String dartType = 'application/dart';
142 if (path.startsWith('/project/packages/')) {
143 root = packageRoot;
144 path = path.substring('/project/packages'.length);
145 } else if (path.startsWith('${PROJECT_PATH}/')) {
146 root = projectRoot;
147 path = path.substring(PROJECT_PATH.length);
148 dartType = 'text/plain';
149 } else if (path.startsWith('${PACKAGES_PATH}/')) {
150 root = packageRoot;
151 path = path.substring(PACKAGES_PATH.length);
152 }
153 var f = new File(root.resolve('.$path').toFilePath());
52 f.exists().then((bool exists) { 154 f.exists().then((bool exists) {
53 if (!exists) return notFound(path); 155 if (!exists) return notFound(path);
54 if (path.endsWith('.html')) { 156 if (path.endsWith('.html')) {
55 response.headers.set(CONTENT_TYPE, 'text/html'); 157 response.headers.set(CONTENT_TYPE, 'text/html');
56 } else if (path.endsWith('.dart')) { 158 } else if (path.endsWith('.dart')) {
57 response.headers.set(CONTENT_TYPE, 'application/dart'); 159 response.headers.set(CONTENT_TYPE, dartType);
58 } else if (path.endsWith('.js')) { 160 } else if (path.endsWith('.js')) {
59 response.headers.set(CONTENT_TYPE, 'application/javascript'); 161 response.headers.set(CONTENT_TYPE, 'application/javascript');
60 } else if (path.endsWith('.ico')) { 162 } else if (path.endsWith('.ico')) {
61 response.headers.set(CONTENT_TYPE, 'image/x-icon'); 163 response.headers.set(CONTENT_TYPE, 'image/x-icon');
62 } else if (path.endsWith('.appcache')) { 164 } else if (path.endsWith('.appcache')) {
63 response.headers.set(CONTENT_TYPE, 'text/cache-manifest'); 165 response.headers.set(CONTENT_TYPE, 'text/cache-manifest');
64 } 166 }
65 f.openRead().pipe(response).catchError(onError); 167 f.openRead().pipe(response).catchError(onError);
66 }); 168 });
67 } 169 }
68 170
69 static onRequest(HttpRequest request) { 171 static onRequest(HttpRequest request) {
70 new Conversation(request, request.response).handle(); 172 new Conversation(request, request.response).handle();
71 } 173 }
72 174
73 static onError(error) { 175 static onError(error) {
74 if (error is HttpException) { 176 if (error is HttpException) {
75 print('Error: ${error.message}'); 177 print('Error: ${error.message}');
76 } else { 178 } else {
77 print('Error: ${error}'); 179 print('Error: ${error}');
78 } 180 }
79 } 181 }
80 182
81 String htmlInfo(String title, String text) { 183 String htmlInfo(String title, String text) {
184 // No script injection, please.
185 title = const HtmlEscape().convert(title);
186 text = const HtmlEscape().convert(text);
82 return """ 187 return """
83 <!DOCTYPE html> 188 <!DOCTYPE html>
84 <html lang='en'> 189 <html lang='en'>
85 <head> 190 <head>
86 <title>$title</title> 191 <title>$title</title>
87 </head> 192 </head>
88 <body> 193 <body>
89 <h1>$title</h1> 194 <h1>$title</h1>
90 <p>$text</p> 195 <p>$text</p>
91 </body> 196 </body>
92 </html> 197 </html>
93 """; 198 """;
94 } 199 }
95 } 200 }
96 201
97 main(List<String> arguments) { 202 main(List<String> arguments) {
98 if (arguments.length > 0) { 203 if (arguments.length > 0) {
99 Conversation.landingPage = arguments[0]; 204 Conversation.documentRoot = Uri.base.resolve(arguments[0]);
100 } 205 }
101 var host = '127.0.0.1'; 206 var host = '127.0.0.1';
102 if (arguments.length > 1) { 207 if (arguments.length > 1) {
103 host = arguments[1]; 208 host = arguments[1];
104 } 209 }
105 int port = 0; 210 int port = 0;
106 if (arguments.length > 2) { 211 if (arguments.length > 2) {
107 port = int.parse(arguments[2]); 212 port = int.parse(arguments[2]);
108 } 213 }
214 if (arguments.length > 3) {
215 Conversation.projectRoot = Uri.base.resolve(arguments[3]);
216 }
217 if (arguments.length > 4) {
218 Conversation.packageRoot = Uri.base.resolve(arguments[4]);
219 }
109 HttpServer.bind(host, port).then((HttpServer server) { 220 HttpServer.bind(host, port).then((HttpServer server) {
110 print('HTTP server started on http://$host:${server.port}/'); 221 print('HTTP server started on http://$host:${server.port}/');
111 server.listen(Conversation.onRequest, onError: Conversation.onError); 222 server.listen(Conversation.onRequest, onError: Conversation.onError);
112 }).catchError((e) { 223 }).catchError((e) {
113 print("HttpServer.bind error: $e"); 224 print("HttpServer.bind error: $e");
114 exit(1); 225 exit(1);
115 }); 226 });
116 } 227 }
OLDNEW
« no previous file with comments | « no previous file | dart/site/try/build_try.gyp » ('j') | dart/site/try/index.html » ('J')

Powered by Google App Engine
This is Rietveld 408576698