Index: sdk/lib/io/directory_impl.dart |
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart |
index cdb6df479a6914240df87f22c7736de07ca9bb02..39f8b2ca16377d7edb2dff45fa6322f6240736fa 100644 |
--- a/sdk/lib/io/directory_impl.dart |
+++ b/sdk/lib/io/directory_impl.dart |
@@ -9,8 +9,10 @@ class _Directory implements Directory { |
static const DELETE_REQUEST = 1; |
static const EXISTS_REQUEST = 2; |
static const CREATE_TEMP_REQUEST = 3; |
- static const LIST_REQUEST = 4; |
- static const RENAME_REQUEST = 5; |
+ static const LIST_START_REQUEST = 4; |
+ static const LIST_NEXT_REQUEST = 5; |
+ static const LIST_STOP_REQUEST = 6; |
+ static const RENAME_REQUEST = 7; |
_Directory(String this._path); |
_Directory.fromPath(Path path) : this(path.toNativePath()); |
@@ -186,9 +188,6 @@ class _Directory implements Directory { |
return new Directory(result); |
} |
- Future<Directory> _deleteHelper(bool recursive, String errorMsg) { |
- } |
- |
Future<Directory> delete({recursive: false}) { |
_ensureDirectoryService(); |
List request = new List(3); |
@@ -240,68 +239,7 @@ class _Directory implements Directory { |
Stream<FileSystemEntity> list({bool recursive: false, |
bool followLinks: true}) { |
- const int LIST_FILE = 0; |
- const int LIST_DIRECTORY = 1; |
- const int LIST_LINK = 2; |
- const int LIST_ERROR = 3; |
- const int LIST_DONE = 4; |
- |
- const int RESPONSE_TYPE = 0; |
- const int RESPONSE_PATH = 1; |
- const int RESPONSE_COMPLETE = 1; |
- const int RESPONSE_ERROR = 2; |
- |
- var controller = new StreamController<FileSystemEntity>(sync: true); |
- |
- List request = [ _Directory.LIST_REQUEST, path, recursive, followLinks ]; |
- ReceivePort responsePort = new ReceivePort(); |
- // Use a separate directory service port for each listing as |
- // listing operations on the same directory can run in parallel. |
- _Directory._newServicePort().send(request, responsePort.toSendPort()); |
- responsePort.receive((message, replyTo) { |
- if (message is !List || message[RESPONSE_TYPE] is !int) { |
- responsePort.close(); |
- controller.addError(new DirectoryException("Internal error")); |
- return; |
- } |
- switch (message[RESPONSE_TYPE]) { |
- case LIST_FILE: |
- controller.add(new File(message[RESPONSE_PATH])); |
- break; |
- case LIST_DIRECTORY: |
- controller.add(new Directory(message[RESPONSE_PATH])); |
- break; |
- case LIST_LINK: |
- controller.add(new Link(message[RESPONSE_PATH])); |
- break; |
- case LIST_ERROR: |
- var errorType = |
- message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE]; |
- if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) { |
- controller.addError(new ArgumentError()); |
- } else if (errorType == _OSERROR_RESPONSE) { |
- var responseError = message[RESPONSE_ERROR]; |
- var err = new OSError( |
- responseError[_OSERROR_RESPONSE_MESSAGE], |
- responseError[_OSERROR_RESPONSE_ERROR_CODE]); |
- var errorPath = message[RESPONSE_PATH]; |
- if (errorPath == null) errorPath = path; |
- controller.addError( |
- new DirectoryException("Directory listing failed", |
- errorPath, |
- err)); |
- } else { |
- controller.addError(new DirectoryException("Internal error")); |
- } |
- break; |
- case LIST_DONE: |
- responsePort.close(); |
- controller.close(); |
- break; |
- } |
- }); |
- |
- return controller.stream; |
+ return new _AsyncDirectoryLister(path, recursive, followLinks).stream; |
} |
List listSync({bool recursive: false, bool followLinks: true}) { |
@@ -342,3 +280,135 @@ class _Directory implements Directory { |
final String _path; |
SendPort _directoryService; |
} |
+ |
+class _AsyncDirectoryLister { |
+ const int LIST_FILE = 0; |
+ const int LIST_DIRECTORY = 1; |
+ const int LIST_LINK = 2; |
+ const int LIST_ERROR = 3; |
+ const int LIST_DONE = 4; |
+ |
+ const int RESPONSE_TYPE = 0; |
+ const int RESPONSE_PATH = 1; |
+ const int RESPONSE_COMPLETE = 1; |
+ const int RESPONSE_ERROR = 2; |
+ |
+ final String path; |
+ final bool recursive; |
+ final bool followLinks; |
+ |
+ StreamController controller; |
+ int id; |
+ bool canceled = false; |
+ bool nextRunning = false; |
+ bool closed = false; |
+ |
+ _AsyncDirectoryLister(String this.path, |
+ bool this.recursive, |
+ bool this.followLinks) { |
+ controller = new StreamController(onListen: onListen, |
+ onResume: onResume, |
+ onCancel: onCancel); |
+ } |
+ |
+ Stream get stream => controller.stream; |
+ |
+ void onListen() { |
+ var request = [_Directory.LIST_START_REQUEST, path, recursive, followLinks]; |
+ _Directory._newServicePort().call(request) |
+ .then((response) { |
+ if (response is int) { |
+ id = response; |
+ next(); |
+ } else { |
+ error(response); |
+ controller.close(); |
+ } |
+ }); |
+ } |
+ |
+ void onResume() { |
+ if (!nextRunning) next(); |
+ } |
+ |
+ void onCancel() { |
+ canceled = true; |
+ // If we are active, but not requesting, close. |
+ if (!nextRunning) { |
+ close(); |
+ } |
+ } |
+ |
+ void next() { |
+ if (canceled) { |
+ close(); |
+ return; |
+ } |
+ if (id == null) return; |
+ if (controller.isPaused) return; |
+ assert(!nextRunning); |
+ nextRunning = true; |
+ _Directory._newServicePort().call([_Directory.LIST_NEXT_REQUEST, id]) |
+ .then((result) { |
+ if (result is List) { |
+ assert(result.length % 2 == 0); |
+ for (int i = 0; i < result.length; i++) { |
+ assert(i % 2 == 0); |
+ switch (result[i++]) { |
+ case LIST_FILE: |
+ controller.add(new File(result[i])); |
+ break; |
+ case LIST_DIRECTORY: |
+ controller.add(new Directory(result[i])); |
+ break; |
+ case LIST_LINK: |
+ controller.add(new Link(result[i])); |
+ break; |
+ case LIST_ERROR: |
+ error(result[i]); |
+ break; |
+ case LIST_DONE: |
+ close(); |
+ return; |
+ } |
+ } |
+ } else { |
+ controller.addError(new DirectoryException("Internal error")); |
+ } |
+ nextRunning = false; |
+ next(); |
+ }); |
+ } |
+ |
+ void close() { |
+ if (closed) return; |
+ if (id == null) return; |
+ closed = true; |
+ _Directory._newServicePort().call([_Directory.LIST_STOP_REQUEST, id]) |
+ .then((_) { |
+ controller.close(); |
+ }); |
+ } |
+ |
+ void error(message) { |
+ var errorType = |
+ message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE]; |
+ if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) { |
+ controller.addError(new ArgumentError()); |
+ } else if (errorType == _OSERROR_RESPONSE) { |
+ var responseError = message[RESPONSE_ERROR]; |
+ var err = new OSError( |
+ responseError[_OSERROR_RESPONSE_MESSAGE], |
+ responseError[_OSERROR_RESPONSE_ERROR_CODE]); |
+ var errorPath = message[RESPONSE_PATH]; |
+ if (errorPath == null) errorPath = path; |
+ controller.addError( |
+ new DirectoryException("Directory listing failed", |
+ errorPath, |
+ err)); |
+ } else { |
+ controller.addError( |
+ new DirectoryException("Internal error")); |
+ } |
+ } |
+} |