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

Unified Diff: sdk/lib/io/file_system_entity.dart

Issue 19263003: Add FileSystemWatcher class to dart:io. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Simplify watching by removing FileSystemWatcher and adding FileSystemEntity.watch. Created 7 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/io/file_system_entity.dart
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index b764f04be7ca151d28701ae498155411f4b86f5f..168a57b37b6b9deddabe5b74340b8cd0348dac9b 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -317,6 +317,12 @@ abstract class FileSystemEntity {
FileStat statSync();
+
+ Stream<FileSystemEvent> watch({int events: FileSystemEvent.ALL_EVENTS,
+ bool recursive: false})
+ => new _FileSystemWatcher(path, events, recursive).stream;
+
+
/**
* Finds the type of file system object that a path points to. Returns
* a [:Future<FileSystemEntityType>:] that completes with the result.
@@ -390,11 +396,204 @@ abstract class FileSystemEntity {
(_getTypeSync(path, true) == FileSystemEntityType.DIRECTORY._type);
- static _throwIfError(Object result, String msg) {
+ static _throwIfError(Object result, String msg, [String path]) {
if (result is OSError) {
- throw new FileException(msg, result);
+ throw new FileException(msg, result, path);
} else if (result is ArgumentError) {
throw result;
}
}
}
+
+
+/**
+ * Base event class emitted by FileSystemWatcher.
+ */
+class FileSystemEvent {
+ static const int CREATE_EVENT = 1 << 0;
Søren Gjesse 2013/08/26 07:51:55 How about removing the _EVENT prefix?
Anders Johnsen 2013/09/03 11:36:23 Done.
+ static const int MODIFY_EVENT = 1 << 1;
+ static const int DELETE_EVENT = 1 << 2;
+ static const int MOVE_EVENT = 1 << 3;
Søren Gjesse 2013/08/26 07:51:55 Two spaces after =.
Anders Johnsen 2013/09/03 11:36:23 Done.
+ static const int ALL_EVENTS =
+ CREATE_EVENT | MODIFY_EVENT | DELETE_EVENT | MOVE_EVENT;
+
+ static const int _MODIFY_ATTRIBUTES_EVENT = 1 << 4;
Søren Gjesse 2013/08/26 07:51:55 Add empty line.
Anders Johnsen 2013/09/03 11:36:23 Done.
+ /**
+ * The type of event. See [FileSystemEvent] for a list of events.
+ */
+ final int type;
+
+ /**
+ * The path that triggered the event.
Søren Gjesse 2013/08/26 07:51:55 Some doc on whether this is absolute or maybe ŕela
Anders Johnsen 2013/09/03 11:36:23 Done.
+ */
+ final String path;
+
+ FileSystemEvent._(this.type, this.path);
+}
+
+
+/**
+ * File system event for newly created file system objects.
+ */
+class FileSystemCreateEvent extends FileSystemEvent {
+ FileSystemCreateEvent._(path)
+ : super._(FileSystemEvent.CREATE_EVENT, path);
+
+ String toString() => "FileSystemCreateEvent('$path')";
+}
+
+
+/**
+ * File system event for modifications of file system objects.
+ */
+class FileSystemModifyEvent extends FileSystemEvent {
+ /**
+ * If the content was changed and not only the attributes, [contentChanged]
+ * is `true`.
+ */
+ final bool contentChanged;
+
+ FileSystemModifyEvent._(path, this.contentChanged)
+ : super._(FileSystemEvent.MODIFY_EVENT, path);
+
+ String toString() =>
+ "FileSystemModifyEvent('$path', contentChanged=$contentChanged)";
+}
+
+
+/**
+ * File system event for deletion of file system objects.
+ */
+class FileSystemDeleteEvent extends FileSystemEvent {
+ FileSystemDeleteEvent._(path)
+ : super._(FileSystemEvent.DELETE_EVENT, path);
+
+ String toString() => "FileSystemDeleteEvent('$path')";
+}
+
+
+/**
+ * File system event for moving of file system objects.
+ */
+class FileSystemMoveEvent extends FileSystemEvent {
+ /**
+ * If the underlaying implementation is able to identify the destination of
+ * the moved file, [destination] will be set. Otherwise, it will be `null`.
+ */
+ final String destination;
+
+ FileSystemMoveEvent._(path, this.destination)
+ : super._(FileSystemEvent.MOVE_EVENT, path);
+
+ String toString() {
+ var buffer = new StringBuffer();
+ buffer.write("FileSystemMoveEvent('$path'");
+ if (destination != null) buffer.write(", '$destination'");
+ buffer.write(')');
+ return buffer.toString();
+ }
+}
+
+
+class _FileSystemWatcher {
+ final String _path;
+ final int _events;
+
+ StreamController _controller;
+ int _id;
+ _RawSocket _socket;
+
+ _FileSystemWatcher(this._path, this._events, bool recursive) {
+
+ _controller = new StreamController(
+ onListen: () {
+ print("in listen");
Søren Gjesse 2013/08/26 07:51:55 Debug print.
Anders Johnsen 2013/09/03 11:36:23 Done.
+ _id = _watchPath(_path, _events, recursive);
+ FileSystemEntity._throwIfError(_id, "Failed to watch path", _path);
+ _listen();
+ },
+ onCancel: () {
+ if (_socket != null) {
+ _socket.close();
+ }
+ });
+ }
+
+ void _stop() {
+ _controller.close();
+ _unwatchPath(_id);
+ }
+
+ void _listen() {
Søren Gjesse 2013/08/26 07:51:55 I think we should do _NativeSocket setup the same
Anders Johnsen 2013/09/03 11:36:23 I've tried to simplify as much as possible.
+ int socketId = _getSocketId(_id);
+ var native = new _NativeSocket.normal();
+ native.isClosedWrite = true;
+ native.setSocketId(socketId);
+ _socket = new _RawSocket(native);
+ print(socketId);
Søren Gjesse 2013/08/26 07:51:55 Debug print.
Anders Johnsen 2013/09/03 11:36:23 Done.
+ _socket.expand((event) {
+ print(event);
+ var events = [];
+ var pair = {};
+ if (event == RawSocketEvent.READ) {
+ String getPath(event) {
+ var path = _path;
+ if (event[2] != null) {
+ path += Platform.pathSeparator;
+ path += event[2];
+ }
+ return path;
+ }
+ while (_socket.available() > 0) {
+ for (var event in _readEvents(_id)) {
+ print(event);
Søren Gjesse 2013/08/26 07:51:55 Debug print.
Anders Johnsen 2013/09/03 11:36:23 Done.
+ var path = getPath(event);
+ if ((event[0] & FileSystemEvent.CREATE_EVENT) != 0) {
+ events.add(new FileSystemCreateEvent._(path));
+ }
+ if ((event[0] & FileSystemEvent.MODIFY_EVENT) != 0) {
+ events.add(new FileSystemModifyEvent._(path, true));
+ }
+ if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES_EVENT) != 0) {
+ events.add(new FileSystemModifyEvent._(path, false));
+ }
+ if ((event[0] & FileSystemEvent.MOVE_EVENT) != 0) {
+ int link = event[3];
+ if (link > 0) {
+ if (pair.containsKey(link)) {
+ events.add(
+ new FileSystemMoveEvent._(getPath(pair[link]), path));
+ pair.remove(link);
+ } else {
+ pair[link] = event;
+ }
+ } else {
+ events.add(new FileSystemMoveEvent._(path, null));
+ }
+ }
+ if ((event[0] & FileSystemEvent.DELETE_EVENT) != 0) {
+ events.add(new FileSystemDeleteEvent._(path));
+ }
+ }
+ }
+ for (var event in pair.values) {
+ events.add(new FileSystemMoveEvent._(getPath(event), null));
+ }
+ } else if (event == RawSocketEvent.CLOSED) {
+ _stop();
+ } else if (event == RawSocketEvent.READ_CLOSED) {
+ } else {
+ assert(false);
+ }
+ print(events);
+ return events;
+ }).where((event) => (event.type & _events) != 0).listen(_controller.add);
+ }
+
+ Stream<FileSystemEvent> get stream => _controller.stream;
+
+ external _watchPath(String path, int events, bool recursive);
+ external void _unwatchPath(int id);
+ external int _getSocketId(int id);
+ external List _readEvents(int id);
+}

Powered by Google App Engine
This is Rietveld 408576698