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

Side by Side Diff: sdk/lib/io/directory_impl.dart

Issue 16813006: Make Directory.list pull-based, making it possible to pause, resume and cancel directory listing. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Review update. Created 7 years, 6 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 | « runtime/bin/directory_win.cc ('k') | tests/standalone/io/directory_list_pause_test.dart » ('j') | no next file with comments »
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 part of dart.io; 5 part of dart.io;
6 6
7 class _Directory implements Directory { 7 class _Directory implements Directory {
8 static const CREATE_REQUEST = 0; 8 static const CREATE_REQUEST = 0;
9 static const DELETE_REQUEST = 1; 9 static const DELETE_REQUEST = 1;
10 static const EXISTS_REQUEST = 2; 10 static const EXISTS_REQUEST = 2;
11 static const CREATE_TEMP_REQUEST = 3; 11 static const CREATE_TEMP_REQUEST = 3;
12 static const LIST_REQUEST = 4; 12 static const LIST_START_REQUEST = 4;
13 static const RENAME_REQUEST = 5; 13 static const LIST_NEXT_REQUEST = 5;
14 static const LIST_STOP_REQUEST = 6;
15 static const RENAME_REQUEST = 7;
14 16
15 _Directory(String this._path); 17 _Directory(String this._path);
16 _Directory.fromPath(Path path) : this(path.toNativePath()); 18 _Directory.fromPath(Path path) : this(path.toNativePath());
17 19
18 external static String _current(); 20 external static String _current();
19 external static _setCurrent(path); 21 external static _setCurrent(path);
20 external static _createTemp(String template); 22 external static _createTemp(String template);
21 external static int _exists(String path); 23 external static int _exists(String path);
22 external static _create(String path); 24 external static _create(String path);
23 external static _delete(String path, bool recursive); 25 external static _delete(String path, bool recursive);
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 } 181 }
180 var result = _createTemp(path); 182 var result = _createTemp(path);
181 if (result is OSError) { 183 if (result is OSError) {
182 throw new DirectoryException("Creation of temporary directory failed", 184 throw new DirectoryException("Creation of temporary directory failed",
183 _path, 185 _path,
184 result); 186 result);
185 } 187 }
186 return new Directory(result); 188 return new Directory(result);
187 } 189 }
188 190
189 Future<Directory> _deleteHelper(bool recursive, String errorMsg) {
190 }
191
192 Future<Directory> delete({recursive: false}) { 191 Future<Directory> delete({recursive: false}) {
193 _ensureDirectoryService(); 192 _ensureDirectoryService();
194 List request = new List(3); 193 List request = new List(3);
195 request[0] = DELETE_REQUEST; 194 request[0] = DELETE_REQUEST;
196 request[1] = _path; 195 request[1] = _path;
197 request[2] = recursive; 196 request[2] = recursive;
198 return _directoryService.call(request).then((response) { 197 return _directoryService.call(request).then((response) {
199 if (_isErrorResponse(response)) { 198 if (_isErrorResponse(response)) {
200 throw _exceptionOrErrorFromResponse(response, "Deletion failed"); 199 throw _exceptionOrErrorFromResponse(response, "Deletion failed");
201 } 200 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 } 232 }
234 var result = _rename(_path, newPath); 233 var result = _rename(_path, newPath);
235 if (result is OSError) { 234 if (result is OSError) {
236 throw new DirectoryException("Rename failed", _path, result); 235 throw new DirectoryException("Rename failed", _path, result);
237 } 236 }
238 return new Directory(newPath); 237 return new Directory(newPath);
239 } 238 }
240 239
241 Stream<FileSystemEntity> list({bool recursive: false, 240 Stream<FileSystemEntity> list({bool recursive: false,
242 bool followLinks: true}) { 241 bool followLinks: true}) {
243 const int LIST_FILE = 0; 242 return new _AsyncDirectoryLister(path, recursive, followLinks).stream;
244 const int LIST_DIRECTORY = 1;
245 const int LIST_LINK = 2;
246 const int LIST_ERROR = 3;
247 const int LIST_DONE = 4;
248
249 const int RESPONSE_TYPE = 0;
250 const int RESPONSE_PATH = 1;
251 const int RESPONSE_COMPLETE = 1;
252 const int RESPONSE_ERROR = 2;
253
254 var controller = new StreamController<FileSystemEntity>(sync: true);
255
256 List request = [ _Directory.LIST_REQUEST, path, recursive, followLinks ];
257 ReceivePort responsePort = new ReceivePort();
258 // Use a separate directory service port for each listing as
259 // listing operations on the same directory can run in parallel.
260 _Directory._newServicePort().send(request, responsePort.toSendPort());
261 responsePort.receive((message, replyTo) {
262 if (message is !List || message[RESPONSE_TYPE] is !int) {
263 responsePort.close();
264 controller.addError(new DirectoryException("Internal error"));
265 return;
266 }
267 switch (message[RESPONSE_TYPE]) {
268 case LIST_FILE:
269 controller.add(new File(message[RESPONSE_PATH]));
270 break;
271 case LIST_DIRECTORY:
272 controller.add(new Directory(message[RESPONSE_PATH]));
273 break;
274 case LIST_LINK:
275 controller.add(new Link(message[RESPONSE_PATH]));
276 break;
277 case LIST_ERROR:
278 var errorType =
279 message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
280 if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
281 controller.addError(new ArgumentError());
282 } else if (errorType == _OSERROR_RESPONSE) {
283 var responseError = message[RESPONSE_ERROR];
284 var err = new OSError(
285 responseError[_OSERROR_RESPONSE_MESSAGE],
286 responseError[_OSERROR_RESPONSE_ERROR_CODE]);
287 var errorPath = message[RESPONSE_PATH];
288 if (errorPath == null) errorPath = path;
289 controller.addError(
290 new DirectoryException("Directory listing failed",
291 errorPath,
292 err));
293 } else {
294 controller.addError(new DirectoryException("Internal error"));
295 }
296 break;
297 case LIST_DONE:
298 responsePort.close();
299 controller.close();
300 break;
301 }
302 });
303
304 return controller.stream;
305 } 243 }
306 244
307 List listSync({bool recursive: false, bool followLinks: true}) { 245 List listSync({bool recursive: false, bool followLinks: true}) {
308 if (_path is! String || recursive is! bool) { 246 if (_path is! String || recursive is! bool) {
309 throw new ArgumentError(); 247 throw new ArgumentError();
310 } 248 }
311 return _list(_path, recursive, followLinks); 249 return _list(_path, recursive, followLinks);
312 } 250 }
313 251
314 String get path => _path; 252 String get path => _path;
(...skipping 20 matching lines...) Expand all
335 273
336 void _ensureDirectoryService() { 274 void _ensureDirectoryService() {
337 if (_directoryService == null) { 275 if (_directoryService == null) {
338 _directoryService = _newServicePort(); 276 _directoryService = _newServicePort();
339 } 277 }
340 } 278 }
341 279
342 final String _path; 280 final String _path;
343 SendPort _directoryService; 281 SendPort _directoryService;
344 } 282 }
283
284 class _AsyncDirectoryLister {
285 const int LIST_FILE = 0;
286 const int LIST_DIRECTORY = 1;
287 const int LIST_LINK = 2;
288 const int LIST_ERROR = 3;
289 const int LIST_DONE = 4;
290
291 const int RESPONSE_TYPE = 0;
292 const int RESPONSE_PATH = 1;
293 const int RESPONSE_COMPLETE = 1;
294 const int RESPONSE_ERROR = 2;
295
296 final String path;
297 final bool recursive;
298 final bool followLinks;
299
300 StreamController controller;
301 int id;
302 bool canceled = false;
303 bool nextRunning = false;
304 bool closed = false;
305
306 _AsyncDirectoryLister(String this.path,
307 bool this.recursive,
308 bool this.followLinks) {
309 controller = new StreamController(onListen: onListen,
310 onResume: onResume,
311 onCancel: onCancel);
312 }
313
314 Stream get stream => controller.stream;
315
316 void onListen() {
317 var request = [_Directory.LIST_START_REQUEST, path, recursive, followLinks];
318 _Directory._newServicePort().call(request)
319 .then((response) {
320 if (response is int) {
321 id = response;
322 next();
323 } else {
324 error(response);
325 controller.close();
326 }
327 });
328 }
329
330 void onResume() {
331 if (!nextRunning) next();
332 }
333
334 void onCancel() {
335 canceled = true;
336 // If we are active, but not requesting, close.
337 if (!nextRunning) {
338 close();
339 }
340 }
341
342 void next() {
343 if (canceled) {
344 close();
345 return;
346 }
347 if (id == null) return;
348 if (controller.isPaused) return;
349 assert(!nextRunning);
350 nextRunning = true;
351 _Directory._newServicePort().call([_Directory.LIST_NEXT_REQUEST, id])
352 .then((result) {
353 if (result is List) {
354 assert(result.length % 2 == 0);
355 for (int i = 0; i < result.length; i++) {
356 assert(i % 2 == 0);
357 switch (result[i++]) {
358 case LIST_FILE:
359 controller.add(new File(result[i]));
360 break;
361 case LIST_DIRECTORY:
362 controller.add(new Directory(result[i]));
363 break;
364 case LIST_LINK:
365 controller.add(new Link(result[i]));
366 break;
367 case LIST_ERROR:
368 error(result[i]);
369 break;
370 case LIST_DONE:
371 close();
372 return;
373 }
374 }
375 } else {
376 controller.addError(new DirectoryException("Internal error"));
377 }
378 nextRunning = false;
379 next();
380 });
381 }
382
383 void close() {
384 if (closed) return;
385 if (id == null) return;
386 closed = true;
387 _Directory._newServicePort().call([_Directory.LIST_STOP_REQUEST, id])
388 .then((_) {
389 controller.close();
390 });
391 }
392
393 void error(message) {
394 var errorType =
395 message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
396 if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
397 controller.addError(new ArgumentError());
398 } else if (errorType == _OSERROR_RESPONSE) {
399 var responseError = message[RESPONSE_ERROR];
400 var err = new OSError(
401 responseError[_OSERROR_RESPONSE_MESSAGE],
402 responseError[_OSERROR_RESPONSE_ERROR_CODE]);
403 var errorPath = message[RESPONSE_PATH];
404 if (errorPath == null) errorPath = path;
405 controller.addError(
406 new DirectoryException("Directory listing failed",
407 errorPath,
408 err));
409 } else {
410 controller.addError(
411 new DirectoryException("Internal error"));
412 }
413 }
414 }
OLDNEW
« no previous file with comments | « runtime/bin/directory_win.cc ('k') | tests/standalone/io/directory_list_pause_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698