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

Side by Side Diff: runtime/bin/file_impl.dart

Issue 10392023: Change dart:io to use Future for one-shot operations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Minor cleanup Created 8 years, 7 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
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 class _FileInputStream extends _BaseDataInputStream implements InputStream { 5 class _FileInputStream extends _BaseDataInputStream implements InputStream {
6 _FileInputStream(String name) { 6 _FileInputStream(String name) {
7 var file = new File(name); 7 var file = new File(name);
8 _data = []; 8 _data = [];
9 _position = 0; 9 _position = 0;
10 file.onError = _reportError; 10 var chained = file.open(FileMode.READ).chain((openedFile) {
11 file.open(FileMode.READ, (openedFile) { 11 return _readDataFromFile(openedFile);
12 _readDataFromFile(openedFile); 12 });
13 chained.handleException((e) {
14 _reportError(e);
15 return true;
13 }); 16 });
14 } 17 }
15 18
16 _FileInputStream.fromStdio(int fd) { 19 _FileInputStream.fromStdio(int fd) {
17 assert(fd == 0); 20 assert(fd == 0);
18 var file = _File._openStdioSync(fd); 21 var file = _File._openStdioSync(fd);
19 _data = []; 22 _data = [];
20 _position = 0; 23 _position = 0;
21 _readDataFromFile(file); 24 _readDataFromFile(file).handleException((e) {
25 _reportError(e);
26 return true;
27 });
22 } 28 }
23 29
24 void _readDataFromFile(RandomAccessFile openedFile) { 30 Future<RandomAccessFile> _closeAfterRead(RandomAccessFile openedFile) {
25 openedFile.onError = _reportError; 31 return openedFile.close().transform((ignore) {
26 openedFile.length((length) { 32 _streamMarkedClosed = true;
33 _checkScheduleCallbacks();
34 return openedFile;
35 });
36 }
37
38 Future<RandomAccessFile> _readDataFromFile(RandomAccessFile openedFile) {
39 return openedFile.length().chain((length) {
27 var contents = new Uint8List(length); 40 var contents = new Uint8List(length);
28 if (length != 0) { 41 if (length != 0) {
29 openedFile.readList(contents, 0, length, (read) { 42 return openedFile.readList(contents, 0, length).chain((read) {
30 if (read != length) { 43 if (read != length) {
31 _reportError(new FileIOException( 44 throw new FileIOException(
32 'Failed reading file contents in FileInputStream')); 45 'Failed reading file contents in FileInputStream');
33 } else { 46 } else {
34 _data = contents; 47 _data = contents;
35 } 48 }
36 openedFile.close(() { 49 return _closeAfterRead(openedFile);
37 _streamMarkedClosed = true;
38 _checkScheduleCallbacks();
39 });
40 }); 50 });
41 } else { 51 } else {
42 openedFile.close(() { 52 return _closeAfterRead(openedFile);
43 _streamMarkedClosed = true;
44 _checkScheduleCallbacks();
45 });
46 } 53 }
47 }); 54 });
48 } 55 }
49 56
50 int available() { 57 int available() {
51 return _closed ? 0 : _data.length - _position; 58 return _closed ? 0 : _data.length - _position;
52 } 59 }
53 60
54 void pipe(OutputStream output, [bool close = true]) { 61 void pipe(OutputStream output, [bool close = true]) {
55 _pipe(this, output, close: close); 62 _pipe(this, output, close: close);
(...skipping 22 matching lines...) Expand all
78 List<int> _data; 85 List<int> _data;
79 int _position; 86 int _position;
80 bool _closed = false; 87 bool _closed = false;
81 } 88 }
82 89
83 90
84 class _FileOutputStream extends _BaseOutputStream implements OutputStream { 91 class _FileOutputStream extends _BaseOutputStream implements OutputStream {
85 _FileOutputStream(String name, FileMode mode) { 92 _FileOutputStream(String name, FileMode mode) {
86 _pendingOperations = new List<List<int>>(); 93 _pendingOperations = new List<List<int>>();
87 var f = new File(name); 94 var f = new File(name);
88 f.open(mode, (openedFile) { 95 var openFuture = f.open(mode);
96 openFuture.then((openedFile) {
89 _file = openedFile; 97 _file = openedFile;
90 _setupFileHandlers();
91 _processPendingOperations(); 98 _processPendingOperations();
92 }); 99 });
93 f.onError = _reportError; 100 openFuture.handleException((e) {
101 _reportError(e);
102 return true;
103 });
94 } 104 }
95 105
96 _FileOutputStream.fromStdio(int fd) { 106 _FileOutputStream.fromStdio(int fd) {
97 assert(1 <= fd && fd <= 2); 107 assert(1 <= fd && fd <= 2);
98 _file = _File._openStdioSync(fd); 108 _file = _File._openStdioSync(fd);
99 _setupFileHandlers();
100 }
101
102
103 void _setupFileHandlers() {
104 _file.onError = _reportError;
105 _file.onNoPendingWrites = () {
106 if (!_streamMarkedClosed && _onNoPendingWrites != null) {
107 _onNoPendingWrites();
108 }
109 };
110 } 109 }
111 110
112 bool write(List<int> buffer, [bool copyBuffer = false]) { 111 bool write(List<int> buffer, [bool copyBuffer = false]) {
113 var data = buffer; 112 var data = buffer;
114 if (copyBuffer) { 113 if (copyBuffer) {
115 var length = buffer.length; 114 var length = buffer.length;
116 data = new Uint8List(length); 115 data = new Uint8List(length);
117 data.setRange(0, length, buffer, 0); 116 data.setRange(0, length, buffer, 0);
118 } 117 }
119 if (_file == null) { 118 if (_file == null) {
(...skipping 13 matching lines...) Expand all
133 } 132 }
134 var copy = new Uint8List(length); 133 var copy = new Uint8List(length);
135 copy.setRange(0, length, buffer, offset); 134 copy.setRange(0, length, buffer, offset);
136 return write(copy); 135 return write(copy);
137 } 136 }
138 137
139 void close() { 138 void close() {
140 if (_file == null) { 139 if (_file == null) {
141 _pendingOperations.add(null); 140 _pendingOperations.add(null);
142 } else if (!_streamMarkedClosed) { 141 } else if (!_streamMarkedClosed) {
143 _file.close(() { 142 _file.close().then((ignore) {
144 if (_onClosed != null) _onClosed(); 143 if (_onClosed != null) _onClosed();
145 }); 144 });
146 _streamMarkedClosed = true; 145 _streamMarkedClosed = true;
147 } 146 }
148 } 147 }
149 148
150 void set onNoPendingWrites(void callback()) { 149 void set onNoPendingWrites(void callback()) {
151 _onNoPendingWrites = callback; 150 _onNoPendingWrites = callback;
151 if (((_pendingOperations == null) || (_pendingOperations.length == 0)) &&
152 (outstandingWrites == 0) &&
153 !_streamMarkedClosed &&
154 (_onNoPendingWrites != null)) {
155 _onNoPendingWrites();
Søren Gjesse 2012/05/10 11:24:45 Call this on the event loop using a Timer.
Mads Ager (google) 2012/05/10 12:42:38 Done.
156 }
152 } 157 }
153 158
154 void set onClosed(void callback()) { 159 void set onClosed(void callback()) {
155 _onClosed = callback; 160 _onClosed = callback;
156 } 161 }
157 162
158 void _processPendingOperations() { 163 void _processPendingOperations() {
159 _pendingOperations.forEach((buffer) { 164 _pendingOperations.forEach((buffer) {
160 (buffer != null) ? write(buffer) : close(); 165 (buffer != null) ? write(buffer) : close();
161 }); 166 });
162 _pendingOperations = null; 167 _pendingOperations = null;
163 } 168 }
164 169
165 void _write(List<int> buffer, int offset, int len) { 170 void _write(List<int> buffer, int offset, int len) {
166 _file.writeList(buffer, offset, len); 171 outstandingWrites++;
172 var writeListFuture = _file.writeList(buffer, offset, len);
173 writeListFuture.then((ignore) {
174 outstandingWrites--;
175 if ((outstandingWrites == 0) &&
176 !_streamMarkedClosed &&
177 (_onNoPendingWrites != null)) {
178 _onNoPendingWrites();
179 }
180 });
181 writeListFuture.handleException((e) {
182 outstandingWrites--;
183 _reportError(e);
184 return true;
185 });
167 } 186 }
168 187
169 RandomAccessFile _file; 188 RandomAccessFile _file;
170 189
171 // When this is set to true the stream is marked closed. When a 190 // When this is set to true the stream is marked closed. When a
172 // stream is marked closed no more data can be written. 191 // stream is marked closed no more data can be written.
173 bool _streamMarkedClosed = false; 192 bool _streamMarkedClosed = false;
174 193
175 // When this is set to true the close callback has been called and 194 // When this is set to true the close callback has been called and
176 // the stream is fully closed. 195 // the stream is fully closed.
177 bool _closeCallbackCalled = false; 196 bool _closeCallbackCalled = false;
178 197
198 // Number of writes that have not yet completed.
199 int outstandingWrites = 0;
200
179 // List of pending writes that were issued before the underlying 201 // List of pending writes that were issued before the underlying
180 // file was successfully opened. 202 // file was successfully opened.
181 List<List<int>> _pendingOperations; 203 List<List<int>> _pendingOperations;
182 204
183 Function _onNoPendingWrites; 205 Function _onNoPendingWrites;
184 Function _onClosed; 206 Function _onClosed;
185 } 207 }
186 208
187 209
188 // Helper class containing static file helper methods. 210 // Helper class containing static file helper methods.
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 383
362 static int checkedWriteString(int id, String string) { 384 static int checkedWriteString(int id, String string) {
363 if (string is !String) return -1; 385 if (string is !String) return -1;
364 return writeString(id, string); 386 return writeString(id, string);
365 } 387 }
366 388
367 } 389 }
368 390
369 // Base class for _File and _RandomAccessFile with shared functions. 391 // Base class for _File and _RandomAccessFile with shared functions.
370 class _FileBase { 392 class _FileBase {
371 void _reportError(e) {
372 if (_onError != null) {
373 _onError(e);
374 } else {
375 throw e;
376 }
377 }
378
379 bool _isErrorResponse(response) { 393 bool _isErrorResponse(response) {
380 return response is List && response[0] != _FileUtils.kSuccessResponse; 394 return response is List && response[0] != _FileUtils.kSuccessResponse;
381 } 395 }
382 396
383 void _handleErrorResponse(response, String message) { 397 Exception _exceptionFromResponse(response, String message) {
384 assert(_isErrorResponse(response)); 398 assert(_isErrorResponse(response));
385 switch (response[_FileUtils.kErrorResponseErrorType]) { 399 switch (response[_FileUtils.kErrorResponseErrorType]) {
386 case _FileUtils.kIllegalArgumentResponse: 400 case _FileUtils.kIllegalArgumentResponse:
387 _reportError(new IllegalArgumentException()); 401 return new IllegalArgumentException();
388 break;
389 case _FileUtils.kOSErrorResponse: 402 case _FileUtils.kOSErrorResponse:
390 var err = new OSError(response[_FileUtils.kOSErrorResponseMessage], 403 var err = new OSError(response[_FileUtils.kOSErrorResponseMessage],
391 response[_FileUtils.kOSErrorResponseErrorCode]); 404 response[_FileUtils.kOSErrorResponseErrorCode]);
392 _reportError(new FileIOException(message, err)); 405 return new FileIOException(message, err);
393 break;
394 case _FileUtils.kFileClosedResponse: 406 case _FileUtils.kFileClosedResponse:
395 _reportError(new FileIOException("File closed")); 407 return new FileIOException("File closed");
396 break;
397 default: 408 default:
398 _reportError(new Exception("Unknown error")); 409 return new Exception("Unknown error");
399 break;
400 } 410 }
401 } 411 }
402
403 void set onError(void handler(e)) {
404 _onError = handler;
405 }
406
407 Function _onError;
408 } 412 }
409 413
410 // Class for encapsulating the native implementation of files. 414 // Class for encapsulating the native implementation of files.
411 class _File extends _FileBase implements File { 415 class _File extends _FileBase implements File {
412 // Constructor for file. 416 // Constructor for file.
413 _File(String this._name); 417 _File(String this._name);
414 418
415 void exists(void callback(bool exists)) { 419 Future<bool> exists() {
416 _ensureFileService(); 420 _ensureFileService();
421 Completer<bool> completer = new Completer<bool>();
417 List request = new List(2); 422 List request = new List(2);
418 request[0] = _FileUtils.kExistsRequest; 423 request[0] = _FileUtils.kExistsRequest;
419 request[1] = _name; 424 request[1] = _name;
420 _fileService.call(request).then((response) { 425 _fileService.call(request).then((response) {
421 if (_isErrorResponse(response)) { 426 if (_isErrorResponse(response)) {
422 _handleErrorResponse(response, "Cannot open file '$_name'"); 427 var e = _exceptionFromResponse(response, "Cannot open file '$_name'");
428 completer.completeException(e);
423 } else { 429 } else {
424 callback(response); 430 completer.complete(response);
425 } 431 }
426 }); 432 });
433 return completer.future;
427 } 434 }
428 435
429 bool existsSync() { 436 bool existsSync() {
430 return _FileUtils.checkedExists(_name); 437 return _FileUtils.checkedExists(_name);
431 } 438 }
432 439
433 void create(void callback()) { 440 Future<File> create() {
434 _ensureFileService(); 441 _ensureFileService();
442 Completer<File> completer = new Completer<File>();
435 List request = new List(2); 443 List request = new List(2);
436 request[0] = _FileUtils.kCreateRequest; 444 request[0] = _FileUtils.kCreateRequest;
437 request[1] = _name; 445 request[1] = _name;
438 _fileService.call(request).then((response) { 446 _fileService.call(request).then((response) {
439 if (_isErrorResponse(response)) { 447 if (_isErrorResponse(response)) {
440 _handleErrorResponse(response, "Cannot create file"); 448 var e = _exceptionFromResponse(response, "Cannot create file '$_name'");
449 completer.completeException(e);
441 } else { 450 } else {
442 callback(); 451 completer.complete(this);
443 } 452 }
444 }); 453 });
454 return completer.future;
445 } 455 }
446 456
447 void createSync() { 457 void createSync() {
448 bool created = _FileUtils.checkedCreate(_name); 458 bool created = _FileUtils.checkedCreate(_name);
449 if (!created) { 459 if (!created) {
450 throw new FileIOException("Cannot create file '$_name'"); 460 throw new FileIOException("Cannot create file '$_name'");
451 } 461 }
452 } 462 }
453 463
454 void delete(void callback()) { 464 Future<File> delete() {
455 _ensureFileService(); 465 _ensureFileService();
466 Completer<File> completer = new Completer<File>();
456 List request = new List(2); 467 List request = new List(2);
457 request[0] = _FileUtils.kDeleteRequest; 468 request[0] = _FileUtils.kDeleteRequest;
458 request[1] = _name; 469 request[1] = _name;
459 _fileService.call(request).then((response) { 470 _fileService.call(request).then((response) {
460 if (_isErrorResponse(response)) { 471 if (_isErrorResponse(response)) {
461 _handleErrorResponse(response, "Cannot delete file '$_name'"); 472 var e = _exceptionFromResponse(response, "Cannot delete file '$_name'");
473 completer.completeException(e);
462 } else { 474 } else {
463 callback(); 475 completer.complete(this);
464 } 476 }
465 }); 477 });
478 return completer.future;
466 } 479 }
467 480
468 void deleteSync() { 481 void deleteSync() {
469 _FileUtils.checkedDelete(_name); 482 _FileUtils.checkedDelete(_name);
470 } 483 }
471 484
472 void directory(void callback(Directory dir)) { 485 Future<Directory> directory() {
473 _ensureFileService(); 486 _ensureFileService();
487 Completer<Directory> completer = new Completer<Directory>();
474 List request = new List(2); 488 List request = new List(2);
475 request[0] = _FileUtils.kDirectoryRequest; 489 request[0] = _FileUtils.kDirectoryRequest;
476 request[1] = _name; 490 request[1] = _name;
477 _fileService.call(request).then((response) { 491 _fileService.call(request).then((response) {
478 if (_isErrorResponse(response)) { 492 if (_isErrorResponse(response)) {
479 _handleErrorResponse(response, "Cannot retrieve directory for file"); 493 var e = _exceptionFromResponse(response,
494 "Cannot retrieve directory for "
495 "file '$_name'");
496 completer.completeException(e);
480 } else { 497 } else {
481 callback(new Directory(response)); 498 completer.complete(new Directory(response));
482 } 499 }
483 }); 500 });
501 return completer.future;
484 } 502 }
485 503
486 Directory directorySync() { 504 Directory directorySync() {
487 _FileUtils.checkedDirectory(_name); 505 _FileUtils.checkedDirectory(_name);
488 return new Directory(_FileUtils.directory(_name)); 506 return new Directory(_FileUtils.directory(_name));
489 } 507 }
490 508
491 void open(FileMode mode, void callback(RandomAccessFile file)) { 509 Future<RandomAccessFile> open(FileMode mode) {
492 _ensureFileService(); 510 _ensureFileService();
511 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
493 if (mode != FileMode.READ && 512 if (mode != FileMode.READ &&
494 mode != FileMode.WRITE && 513 mode != FileMode.WRITE &&
495 mode != FileMode.APPEND) { 514 mode != FileMode.APPEND) {
496 _reportError(new IllegalArgumentException()); 515 new Timer(0, (t) {
497 return; 516 completer.completeException(new IllegalArgumentException());
517 });
518 return completer.future;
498 } 519 }
499 List request = new List(3); 520 List request = new List(3);
500 request[0] = _FileUtils.kOpenRequest; 521 request[0] = _FileUtils.kOpenRequest;
501 request[1] = _name; 522 request[1] = _name;
502 request[2] = mode._mode; // Direct int value for serialization. 523 request[2] = mode._mode; // Direct int value for serialization.
503 _fileService.call(request).then((response) { 524 _fileService.call(request).then((response) {
504 if (_isErrorResponse(response)) { 525 if (_isErrorResponse(response)) {
505 _handleErrorResponse(response, "Cannot open file '$_name'"); 526 var e = _exceptionFromResponse(response, "Cannot open file '$_name'");
527 completer.completeException(e);
506 } else { 528 } else {
507 callback(new _RandomAccessFile(response, _name)); 529 completer.complete(new _RandomAccessFile(response, _name));
508 } 530 }
509 }); 531 });
532 return completer.future;
510 } 533 }
511 534
512 void length(void callback(int length)) { 535 Future<int> length() {
513 _ensureFileService(); 536 _ensureFileService();
537 Completer<int> completer = new Completer<int>();
514 List request = new List(2); 538 List request = new List(2);
515 request[0] = _FileUtils.kLengthFromNameRequest; 539 request[0] = _FileUtils.kLengthFromNameRequest;
516 request[1] = _name; 540 request[1] = _name;
517 _fileService.call(request).then((response) { 541 _fileService.call(request).then((response) {
518 if (_isErrorResponse(response)) { 542 if (_isErrorResponse(response)) {
519 _handleErrorResponse(response, 543 var e = _exceptionFromResponse(response,
520 "Cannot retrieve length of file '$_name'"); 544 "Cannot retrieve length of "
545 "file '$_name'");
546 completer.completeException(e);
521 } else { 547 } else {
522 callback(response); 548 completer.complete(response);
523 } 549 }
524 }); 550 });
551 return completer.future;
525 } 552 }
526 553
527 int lengthSync() { 554 int lengthSync() {
528 var result = _FileUtils.checkedLengthFromName(_name); 555 var result = _FileUtils.checkedLengthFromName(_name);
529 if (result is OSError) { 556 if (result is OSError) {
530 throw new FileIOException("Cannot retrieve length of file '$_name'", 557 throw new FileIOException("Cannot retrieve length of file '$_name'",
531 result); 558 result);
532 } 559 }
533 return result; 560 return result;
534 } 561 }
(...skipping 11 matching lines...) Expand all
546 } 573 }
547 574
548 static RandomAccessFile _openStdioSync(int fd) { 575 static RandomAccessFile _openStdioSync(int fd) {
549 var id = _FileUtils.openStdio(fd); 576 var id = _FileUtils.openStdio(fd);
550 if (id == 0) { 577 if (id == 0) {
551 throw new FileIOException("Cannot open stdio file for: $fd"); 578 throw new FileIOException("Cannot open stdio file for: $fd");
552 } 579 }
553 return new _RandomAccessFile(id, ""); 580 return new _RandomAccessFile(id, "");
554 } 581 }
555 582
556 void fullPath(void callback(String result)) { 583 Future<String> fullPath() {
557 _ensureFileService(); 584 _ensureFileService();
585 Completer<String> completer = new Completer<String>();
558 List request = new List(2); 586 List request = new List(2);
559 request[0] = _FileUtils.kFullPathRequest; 587 request[0] = _FileUtils.kFullPathRequest;
560 request[1] = _name; 588 request[1] = _name;
561 _fileService.call(request).then((response) { 589 _fileService.call(request).then((response) {
562 if (_isErrorResponse(response)) { 590 if (_isErrorResponse(response)) {
563 _handleErrorResponse(response, "Cannot retrieve full path"); 591 var e = _exceptionFromResponse(response,
592 "Cannot retrieve full path"
593 " for '$_name'");
594 completer.completeException(e);
564 } else { 595 } else {
565 callback(response); 596 completer.complete(response);
566 } 597 }
567 }); 598 });
599 return completer.future;
568 } 600 }
569 601
570 String fullPathSync() { 602 String fullPathSync() {
571 return _FileUtils.checkedFullPath(_name); 603 return _FileUtils.checkedFullPath(_name);
572 } 604 }
573 605
574 InputStream openInputStream() { 606 InputStream openInputStream() {
575 return new _FileInputStream(_name); 607 return new _FileInputStream(_name);
576 } 608 }
577 609
578 OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) { 610 OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) {
579 if (mode != FileMode.WRITE && 611 if (mode != FileMode.WRITE &&
580 mode != FileMode.APPEND) { 612 mode != FileMode.APPEND) {
581 throw new FileIOException( 613 throw new FileIOException(
582 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); 614 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND");
583 } 615 }
584 return new _FileOutputStream(_name, mode); 616 return new _FileOutputStream(_name, mode);
585 } 617 }
586 618
587 void readAsBytes(void callback(List<int> bytes)) { 619 Future<List<int>> readAsBytes() {
588 _ensureFileService(); 620 _ensureFileService();
621 Completer<List<int>> completer = new Completer<List<int>>();
589 var chunks = new _BufferList(); 622 var chunks = new _BufferList();
590 var stream = openInputStream(); 623 var stream = openInputStream();
591 stream.onClosed = () { 624 stream.onClosed = () {
592 callback(chunks.readBytes(chunks.length)); 625 completer.complete(chunks.readBytes(chunks.length));
593 }; 626 };
594 stream.onData = () { 627 stream.onData = () {
595 var chunk = stream.read(); 628 var chunk = stream.read();
596 chunks.add(chunk); 629 chunks.add(chunk);
597 }; 630 };
598 stream.onError = (e) => _reportError(e); 631 stream.onError = completer.completeException;
632 return completer.future;
599 } 633 }
600 634
601 List<int> readAsBytesSync() { 635 List<int> readAsBytesSync() {
602 var opened = openSync(); 636 var opened = openSync();
603 var length = opened.lengthSync(); 637 var length = opened.lengthSync();
604 var result = new Uint8List(length); 638 var result = new Uint8List(length);
605 var read = opened.readListSync(result, 0, length); 639 var read = opened.readListSync(result, 0, length);
606 if (read != length) { 640 if (read != length) {
607 throw new FileIOException("Failed to read file"); 641 throw new FileIOException("Failed to read file");
608 } 642 }
609 opened.closeSync(); 643 opened.closeSync();
610 return result; 644 return result;
611 } 645 }
612 646
613 void readAsText(Encoding encoding, void callback(String text)) { 647 Future<String> readAsText(Encoding encoding) {
614 _ensureFileService(); 648 _ensureFileService();
615 var decoder = _StringDecoders.decoder(encoding); 649 var decoder = _StringDecoders.decoder(encoding);
616 readAsBytes((bytes) { 650 return readAsBytes().transform((bytes) {
617 try { 651 decoder.write(bytes);
618 decoder.write(bytes); 652 return decoder.decoded;
619 } catch (var e) {
620 _reportError(e);
621 return;
622 }
623 callback(decoder.decoded);
624 }); 653 });
625 } 654 }
626 655
627 String readAsTextSync([Encoding encoding = Encoding.UTF_8]) { 656 String readAsTextSync([Encoding encoding = Encoding.UTF_8]) {
628 var decoder = _StringDecoders.decoder(encoding); 657 var decoder = _StringDecoders.decoder(encoding);
629 List<int> bytes = readAsBytesSync(); 658 List<int> bytes = readAsBytesSync();
630 decoder.write(bytes); 659 decoder.write(bytes);
631 return decoder.decoded; 660 return decoder.decoded;
632 } 661 }
633 662
634 List<String> _getDecodedLines(_StringDecoder decoder) { 663 List<String> _getDecodedLines(_StringDecoder decoder) {
635 List<String> result = []; 664 List<String> result = [];
636 var line = decoder.decodedLine; 665 var line = decoder.decodedLine;
637 while (line != null) { 666 while (line != null) {
638 result.add(line); 667 result.add(line);
639 line = decoder.decodedLine; 668 line = decoder.decodedLine;
640 } 669 }
641 // If there is more data with no terminating line break we treat 670 // If there is more data with no terminating line break we treat
642 // it as the last line. 671 // it as the last line.
643 var data = decoder.decoded; 672 var data = decoder.decoded;
644 if (data != null) { 673 if (data != null) {
645 result.add(data); 674 result.add(data);
646 } 675 }
647 return result; 676 return result;
648 } 677 }
649 678
650 void readAsLines(Encoding encoding, void callback(List<String> lines)) { 679 Future<List<String>> readAsLines(Encoding encoding) {
651 _ensureFileService(); 680 _ensureFileService();
681 Completer<List<String>> completer = new Completer<List<String>>();
652 var decoder = _StringDecoders.decoder(encoding); 682 var decoder = _StringDecoders.decoder(encoding);
653 readAsBytes((bytes) { 683 return readAsBytes().transform((bytes) {
654 try { 684 decoder.write(bytes);
655 decoder.write(bytes); 685 return _getDecodedLines(decoder);
656 } catch (var e) {
657 _reportError(e);
658 return;
659 }
660 callback(_getDecodedLines(decoder));
661 }); 686 });
662 } 687 }
663 688
664 List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) { 689 List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) {
665 var decoder = _StringDecoders.decoder(encoding); 690 var decoder = _StringDecoders.decoder(encoding);
666 List<int> bytes = readAsBytesSync(); 691 List<int> bytes = readAsBytesSync();
667 decoder.write(bytes); 692 decoder.write(bytes);
668 return _getDecodedLines(decoder); 693 return _getDecodedLines(decoder);
669 } 694 }
670 695
671 String get name() => _name; 696 String get name() => _name;
672 697
673 void _ensureFileService() { 698 void _ensureFileService() {
674 if (_fileService == null) { 699 if (_fileService == null) {
675 _fileService = _FileUtils.newServicePort(); 700 _fileService = _FileUtils.newServicePort();
676 } 701 }
677 } 702 }
678 703
679 String _name; 704 final String _name;
680 705
681 SendPort _fileService; 706 SendPort _fileService;
682 } 707 }
683 708
684 709
685 class _RandomAccessFile extends _FileBase implements RandomAccessFile { 710 class _RandomAccessFile extends _FileBase implements RandomAccessFile {
686 _RandomAccessFile(int this._id, String this._name); 711 _RandomAccessFile(int this._id, String this._name);
687 712
688 void close(void callback()) { 713 Future<RandomAccessFile> close() {
714 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
689 if (_id == 0) { 715 if (_id == 0) {
690 _reportError(new FileIOException("Cannot close file '$_name'")); 716 // Complete asynchronously so the user has a chance to setup
691 return; 717 // handlers without getting exceptions when registering the
718 // then handler.
Søren Gjesse 2012/05/10 11:24:45 So we do always want to throw exceptions through t
Mads Ager (google) 2012/05/10 12:42:38 Yes, at least I did that consistently for the file
719 new Timer(0, (t) {
720 completer.completeException(
721 new FileIOException("Cannot close file '$_name'"));
722 });
723 return completer.future;
692 } 724 }
693 _ensureFileService(); 725 _ensureFileService();
694 List request = new List(2); 726 List request = new List(2);
695 request[0] = _FileUtils.kCloseRequest; 727 request[0] = _FileUtils.kCloseRequest;
696 request[1] = _id; 728 request[1] = _id;
697 // Set the id_ to 0 (NULL) to ensure the no more async requests 729 // Set the id_ to 0 (NULL) to ensure the no more async requests
698 // can be issues for this file. 730 // can be issues for this file.
699 _id = 0; 731 _id = 0;
700 _fileService.call(request).then((result) { 732 _fileService.call(request).then((result) {
701 if (result != -1) { 733 if (result != -1) {
702 _id = result; 734 _id = result;
703 callback(); 735 completer.complete(this);
704 } else { 736 } else {
705 _reportError(new FileIOException("Cannot close file '$_name'")); 737 completer.completeException(
738 new FileIOException("Cannot close file '$_name'"));
706 } 739 }
707 }); 740 });
741 return completer.future;
708 } 742 }
709 743
710 void closeSync() { 744 void closeSync() {
711 var id = _FileUtils.close(_id); 745 var id = _FileUtils.close(_id);
712 if (id == -1) { 746 if (id == -1) {
713 throw new FileIOException("Cannot close file '$_name'"); 747 throw new FileIOException("Cannot close file '$_name'");
714 } 748 }
715 _id = id; 749 _id = id;
716 } 750 }
717 751
718 void readByte(void callback(int byte)) { 752 Future<int> readByte() {
719 _ensureFileService(); 753 _ensureFileService();
754 Completer<int> completer = new Completer<int>();
720 List request = new List(2); 755 List request = new List(2);
721 request[0] = _FileUtils.kReadByteRequest; 756 request[0] = _FileUtils.kReadByteRequest;
722 request[1] = _id; 757 request[1] = _id;
723 _fileService.call(request).then((response) { 758 _fileService.call(request).then((response) {
724 if (_isErrorResponse(response)) { 759 if (_isErrorResponse(response)) {
725 _handleErrorResponse(response, "readByte failed for file '$_name'"); 760 var e = _exceptionFromResponse(response,
761 "readByte failed for file '$_name'");
762 completer.completeException(e);
726 } else { 763 } else {
727 callback(response); 764 completer.complete(response);
728 } 765 }
729 }); 766 });
767 return completer.future;
730 } 768 }
731 769
732 int readByteSync() { 770 int readByteSync() {
733 _checkNotClosed(); 771 _checkNotClosed();
734 var result = _FileUtils.readByte(_id); 772 var result = _FileUtils.readByte(_id);
735 if (result is OSError) { 773 if (result is OSError) {
736 throw new FileIOException("readByte failed for file '$_name'", result); 774 throw new FileIOException("readByte failed for file '$_name'", result);
737 } 775 }
738 return result; 776 return result;
739 } 777 }
740 778
741 void readList(List<int> buffer, int offset, int bytes, 779 Future<int> readList(List<int> buffer, int offset, int bytes) {
742 void callback(int read)) {
743 _ensureFileService(); 780 _ensureFileService();
781 Completer<int> completer = new Completer<int>();
744 if (buffer is !List || offset is !int || bytes is !int) { 782 if (buffer is !List || offset is !int || bytes is !int) {
745 _reportError(new FileIOException( 783 // Complete asynchronously so the user has a chance to setup
746 "Invalid arguments to readList for file '$_name'")); 784 // handlers without getting exceptions when registering the
747 return; 785 // then handler.
786 new Timer(0, (t) {
787 completer.completeException(new FileIOException(
788 "Invalid arguments to readList for file '$_name'"));
789 });
790 return completer.future;
748 }; 791 };
749 List request = new List(3); 792 List request = new List(3);
750 request[0] = _FileUtils.kReadListRequest; 793 request[0] = _FileUtils.kReadListRequest;
751 request[1] = _id; 794 request[1] = _id;
752 request[2] = bytes; 795 request[2] = bytes;
753 _fileService.call(request).then((response) { 796 _fileService.call(request).then((response) {
754 if (_isErrorResponse(response)) { 797 if (_isErrorResponse(response)) {
755 _handleErrorResponse(response, "readList failed for file '$_name'"); 798 var e = _exceptionFromResponse(response,
799 "readList failed for file '$_name'");
800 completer.completeException(e);
756 } else { 801 } else {
757 var read = response[1]; 802 var read = response[1];
758 var data = response[2]; 803 var data = response[2];
759 buffer.setRange(offset, read, data); 804 buffer.setRange(offset, read, data);
760 callback(read); 805 completer.complete(read);
761 } 806 }
762 }); 807 });
808 return completer.future;
763 } 809 }
764 810
765 int readListSync(List<int> buffer, int offset, int bytes) { 811 int readListSync(List<int> buffer, int offset, int bytes) {
766 _checkNotClosed(); 812 _checkNotClosed();
767 if (buffer is !List || offset is !int || bytes is !int) { 813 if (buffer is !List || offset is !int || bytes is !int) {
768 throw new FileIOException( 814 throw new FileIOException(
769 "Invalid arguments to readList for file '$_name'"); 815 "Invalid arguments to readList for file '$_name'");
770 } 816 }
771 if (bytes == 0) return 0; 817 if (bytes == 0) return 0;
772 int index = 818 int index =
773 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); 819 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes);
774 if (index != 0) { 820 if (index != 0) {
775 throw new IndexOutOfRangeException(index); 821 throw new IndexOutOfRangeException(index);
776 } 822 }
777 var result = _FileUtils.readList(_id, buffer, offset, bytes); 823 var result = _FileUtils.readList(_id, buffer, offset, bytes);
778 if (result is OSError) { 824 if (result is OSError) {
779 throw new FileIOException("readList failed for file '$_name'", 825 throw new FileIOException("readList failed for file '$_name'",
780 result); 826 result);
781 } 827 }
782 return result; 828 return result;
783 } 829 }
784 830
785 void writeByte(int value) { 831 Future<RandomAccessFile> writeByte(int value) {
786 _ensureFileService(); 832 _ensureFileService();
833 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
787 if (value is !int) { 834 if (value is !int) {
788 _reportError(new FileIOException( 835 // Complete asynchronously so the user has a chance to setup
789 "Invalid argument to writeByte for file '$_name'")); 836 // handlers without getting exceptions when registering the
790 return; 837 // then handler.
838 new Timer(0, (t) {
839 completer.completeException(new FileIOException(
840 "Invalid argument to writeByte for file '$_name'"));
841 });
842 return completer.future;
791 } 843 }
792 List request = new List(3); 844 List request = new List(3);
793 request[0] = _FileUtils.kWriteByteRequest; 845 request[0] = _FileUtils.kWriteByteRequest;
794 request[1] = _id; 846 request[1] = _id;
795 request[2] = value; 847 request[2] = value;
796 _writeEnqueued();
797 _fileService.call(request).then((response) { 848 _fileService.call(request).then((response) {
798 _writeCompleted();
799 if (_isErrorResponse(response)) { 849 if (_isErrorResponse(response)) {
800 _handleErrorResponse(response, "writeByte failed for file '$_name'"); 850 var e = _exceptionFromResponse(response,
851 "writeByte failed for file '$_name'");
852 completer.completeException(e);
853 } else {
854 completer.complete(this);
801 } 855 }
802 }); 856 });
857 return completer.future;
803 } 858 }
804 859
805 int writeByteSync(int value) { 860 int writeByteSync(int value) {
806 _checkNotClosed(); 861 _checkNotClosed();
807 if (value is !int) { 862 if (value is !int) {
808 throw new FileIOException( 863 throw new FileIOException(
809 "Invalid argument to writeByte for file '$_name'"); 864 "Invalid argument to writeByte for file '$_name'");
810 } 865 }
811 var result = _FileUtils.writeByte(_id, value); 866 var result = _FileUtils.writeByte(_id, value);
812 if (result is OSError) { 867 if (result is OSError) {
813 throw new FileIOException("writeByte failed for file '$_name'", 868 throw new FileIOException("writeByte failed for file '$_name'",
814 result); 869 result);
815 } 870 }
816 return result; 871 return result;
817 } 872 }
818 873
819 void writeList(List<int> buffer, int offset, int bytes) { 874 Future<RandomAccessFile> writeList(List<int> buffer, int offset, int bytes) {
820 _ensureFileService(); 875 _ensureFileService();
876 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
821 if (buffer is !List || offset is !int || bytes is !int) { 877 if (buffer is !List || offset is !int || bytes is !int) {
822 _reportError(new FileIOException( 878 // Complete asynchronously so the user has a chance to setup
879 // handlers without getting exceptions when registering the
880 // then handler.
881 new Timer(0, (t) {
882 completer.completeException(new FileIOException(
823 "Invalid arguments to writeList for file '$_name'")); 883 "Invalid arguments to writeList for file '$_name'"));
824 return; 884 });
885 return completer.future;
825 } 886 }
826 887
827 List result = 888 List result =
828 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes); 889 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes);
829 List outBuffer = result[0]; 890 List outBuffer = result[0];
830 int outOffset = result[1]; 891 int outOffset = result[1];
831 892
832 List request = new List(5); 893 List request = new List(5);
833 request[0] = _FileUtils.kWriteListRequest; 894 request[0] = _FileUtils.kWriteListRequest;
834 request[1] = _id; 895 request[1] = _id;
835 request[2] = outBuffer; 896 request[2] = outBuffer;
836 request[3] = outOffset; 897 request[3] = outOffset;
837 request[4] = bytes; 898 request[4] = bytes;
838 _writeEnqueued();
839 _fileService.call(request).then((response) { 899 _fileService.call(request).then((response) {
840 _writeCompleted();
841 if (_isErrorResponse(response)) { 900 if (_isErrorResponse(response)) {
842 _handleErrorResponse(response, "writeList failed for file '$_name'"); 901 var e = _exceptionFromResponse(response,
902 "writeList failed for file '$_name'");
903 completer.completeException(e);
904 } else {
905 completer.complete(this);
843 } 906 }
844 }); 907 });
908 return completer.future;
845 } 909 }
846 910
847 int writeListSync(List<int> buffer, int offset, int bytes) { 911 int writeListSync(List<int> buffer, int offset, int bytes) {
848 _checkNotClosed(); 912 _checkNotClosed();
849 if (buffer is !List || offset is !int || bytes is !int) { 913 if (buffer is !List || offset is !int || bytes is !int) {
850 throw new FileIOException( 914 throw new FileIOException(
851 "Invalid arguments to writeList for file '$_name'"); 915 "Invalid arguments to writeList for file '$_name'");
852 } 916 }
853 if (bytes == 0) return 0; 917 if (bytes == 0) return 0;
854 int index = 918 int index =
855 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); 919 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes);
856 if (index != 0) { 920 if (index != 0) {
857 throw new IndexOutOfRangeException(index); 921 throw new IndexOutOfRangeException(index);
858 } 922 }
859 var result = _FileUtils.writeList(_id, buffer, offset, bytes); 923 var result = _FileUtils.writeList(_id, buffer, offset, bytes);
860 if (result is OSError) { 924 if (result is OSError) {
861 throw new FileIOException("writeList failed for file '$_name'", result); 925 throw new FileIOException("writeList failed for file '$_name'", result);
862 } 926 }
863 return result; 927 return result;
864 } 928 }
865 929
866 void writeString(String string, [Encoding encoding = Encoding.UTF_8]) { 930 Future<RandomAccessFile> writeString(String string,
931 [Encoding encoding = Encoding.UTF_8]) {
867 _ensureFileService(); 932 _ensureFileService();
933 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
868 List request = new List(3); 934 List request = new List(3);
869 request[0] = _FileUtils.kWriteStringRequest; 935 request[0] = _FileUtils.kWriteStringRequest;
870 request[1] = _id; 936 request[1] = _id;
871 request[2] = string; 937 request[2] = string;
872 _writeEnqueued();
873 _fileService.call(request).then((response) { 938 _fileService.call(request).then((response) {
874 _writeCompleted();
875 if (_isErrorResponse(response)) { 939 if (_isErrorResponse(response)) {
876 _handleErrorResponse(response, "writeString failed for file '$_name'"); 940 var e = _exceptionFromResponse(response,
941 "writeString failed for file '$_name'");
942 completer.completeException(e);
943 } else {
944 completer.complete(this);
877 } 945 }
878 }); 946 });
947 return completer.future;
879 } 948 }
880 949
881 int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) { 950 int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) {
882 _checkNotClosed(); 951 _checkNotClosed();
883 var result = _FileUtils.checkedWriteString(_id, string); 952 var result = _FileUtils.checkedWriteString(_id, string);
884 if (result is OSError) { 953 if (result is OSError) {
885 throw new FileIOException("writeString failed for file '$_name'", result); 954 throw new FileIOException("writeString failed for file '$_name'", result);
886 } 955 }
887 return result; 956 return result;
888 } 957 }
889 958
890 void position(void callback(int position)) { 959 Future<int> position() {
891 _ensureFileService(); 960 _ensureFileService();
961 Completer<int> completer = new Completer<int>();
892 List request = new List(2); 962 List request = new List(2);
893 request[0] = _FileUtils.kPositionRequest; 963 request[0] = _FileUtils.kPositionRequest;
894 request[1] = _id; 964 request[1] = _id;
895 _fileService.call(request).then((response) { 965 _fileService.call(request).then((response) {
896 if (_isErrorResponse(response)) { 966 if (_isErrorResponse(response)) {
897 _handleErrorResponse(response, "position failed for file '$_name'"); 967 var e = _exceptionFromResponse(response,
968 "position failed for file '$_name'");
969 completer.completeException(e);
898 } else { 970 } else {
899 callback(response); 971 completer.complete(response);
900 } 972 }
901 }); 973 });
974 return completer.future;
902 } 975 }
903 976
904 int positionSync() { 977 int positionSync() {
905 _checkNotClosed(); 978 _checkNotClosed();
906 var result = _FileUtils.position(_id); 979 var result = _FileUtils.position(_id);
907 if (result is OSError) { 980 if (result is OSError) {
908 throw new FileIOException("position failed for file '$_name'", result); 981 throw new FileIOException("position failed for file '$_name'", result);
909 } 982 }
910 return result; 983 return result;
911 } 984 }
912 985
913 void setPosition(int position, void callback()) { 986 Future<RandomAccessFile> setPosition(int position) {
914 _ensureFileService(); 987 _ensureFileService();
988 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
915 List request = new List(3); 989 List request = new List(3);
916 request[0] = _FileUtils.kSetPositionRequest; 990 request[0] = _FileUtils.kSetPositionRequest;
917 request[1] = _id; 991 request[1] = _id;
918 request[2] = position; 992 request[2] = position;
919 _fileService.call(request).then((response) { 993 _fileService.call(request).then((response) {
920 if (_isErrorResponse(response)) { 994 if (_isErrorResponse(response)) {
921 _handleErrorResponse(response, "setPosition failed for file '$_name'"); 995 var e = _exceptionFromResponse(response,
996 "setPosition failed for file '$_name'");
997 completer.completeException(e);
922 } else { 998 } else {
923 callback(); 999 completer.complete(this);
924 } 1000 }
925 }); 1001 });
1002 return completer.future;
926 } 1003 }
927 1004
928 void setPositionSync(int position) { 1005 void setPositionSync(int position) {
929 _checkNotClosed(); 1006 _checkNotClosed();
930 var result = _FileUtils.setPosition(_id, position); 1007 var result = _FileUtils.setPosition(_id, position);
931 if (result is OSError) { 1008 if (result is OSError) {
932 throw new FileIOException("setPosition failed for file '$_name'", result); 1009 throw new FileIOException("setPosition failed for file '$_name'", result);
933 } 1010 }
934 } 1011 }
935 1012
936 void truncate(int length, void callback()) { 1013 Future<RandomAccessFile> truncate(int length) {
937 _ensureFileService(); 1014 _ensureFileService();
1015 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
938 List request = new List(3); 1016 List request = new List(3);
939 request[0] = _FileUtils.kTruncateRequest; 1017 request[0] = _FileUtils.kTruncateRequest;
940 request[1] = _id; 1018 request[1] = _id;
941 request[2] = length; 1019 request[2] = length;
942 _fileService.call(request).then((response) { 1020 _fileService.call(request).then((response) {
943 if (_isErrorResponse(response)) { 1021 if (_isErrorResponse(response)) {
944 _handleErrorResponse(response, "truncate failed for file '$_name'"); 1022 var e = _exceptionFromResponse(response,
1023 "truncate failed for file '$_name'");
1024 completer.completeException(e);
945 } else { 1025 } else {
946 callback(); 1026 completer.complete(this);
947 } 1027 }
948 }); 1028 });
1029 return completer.future;
949 } 1030 }
950 1031
951 void truncateSync(int length) { 1032 void truncateSync(int length) {
952 _checkNotClosed(); 1033 _checkNotClosed();
953 var result = _FileUtils.truncate(_id, length); 1034 var result = _FileUtils.truncate(_id, length);
954 if (result is OSError) { 1035 if (result is OSError) {
955 throw new FileIOException("truncate failed for file '$_name'", result); 1036 throw new FileIOException("truncate failed for file '$_name'", result);
956 } 1037 }
957 } 1038 }
958 1039
959 void length(void callback(int length)) { 1040 Future<int> length() {
960 _ensureFileService(); 1041 _ensureFileService();
1042 Completer<int> completer = new Completer<int>();
961 List request = new List(2); 1043 List request = new List(2);
962 request[0] = _FileUtils.kLengthRequest; 1044 request[0] = _FileUtils.kLengthRequest;
963 request[1] = _id; 1045 request[1] = _id;
964 _fileService.call(request).then((response) { 1046 _fileService.call(request).then((response) {
965 if (_isErrorResponse(response)) { 1047 if (_isErrorResponse(response)) {
966 _handleErrorResponse(response, "length failed for file '$_name'"); 1048 var e = _exceptionFromResponse(response,
1049 "length failed for file '$_name'");
1050 completer.completeException(e);
967 } else { 1051 } else {
968 callback(response); 1052 completer.complete(response);
969 } 1053 }
970 }); 1054 });
1055 return completer.future;
971 } 1056 }
972 1057
973 int lengthSync() { 1058 int lengthSync() {
974 _checkNotClosed(); 1059 _checkNotClosed();
975 var result = _FileUtils.length(_id); 1060 var result = _FileUtils.length(_id);
976 if (result is OSError) { 1061 if (result is OSError) {
977 throw new FileIOException("length failed for file '$_name'", result); 1062 throw new FileIOException("length failed for file '$_name'", result);
978 } 1063 }
979 return result; 1064 return result;
980 } 1065 }
981 1066
982 void flush(void callback()) { 1067 Future<RandomAccessFile> flush() {
983 _ensureFileService(); 1068 _ensureFileService();
1069 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
984 List request = new List(2); 1070 List request = new List(2);
985 request[0] = _FileUtils.kFlushRequest; 1071 request[0] = _FileUtils.kFlushRequest;
986 request[1] = _id; 1072 request[1] = _id;
987 _fileService.call(request).then((response) { 1073 _fileService.call(request).then((response) {
988 if (_isErrorResponse(response)) { 1074 if (_isErrorResponse(response)) {
989 _handleErrorResponse(response, "flush failed for file '$_name'"); 1075 var e = _exceptionFromResponse(response,
1076 "flush failed for file '$_name'");
1077 completer.completeException(e);
990 } else { 1078 } else {
991 callback(); 1079 completer.complete(this);
992 } 1080 }
993 }); 1081 });
1082 return completer.future;
994 } 1083 }
995 1084
996 void flushSync() { 1085 void flushSync() {
997 _checkNotClosed(); 1086 _checkNotClosed();
998 var result = _FileUtils.flush(_id); 1087 var result = _FileUtils.flush(_id);
999 if (result is OSError) { 1088 if (result is OSError) {
1000 throw new FileIOException("flush failed for file '$_name'", result); 1089 throw new FileIOException("flush failed for file '$_name'", result);
1001 } 1090 }
1002 } 1091 }
1003 1092
1004 String get name() => _name; 1093 String get name() => _name;
1005 1094
1006 void set onNoPendingWrites(void handler()) {
1007 _onNoPendingWrites = handler;
1008 if (_pendingWrites == 0) {
1009 _noPendingWriteTimer = new Timer(0, (t) {
1010 if (_onNoPendingWrites != null) _onNoPendingWrites();
1011 });
1012 }
1013 }
1014
1015 void _ensureFileService() { 1095 void _ensureFileService() {
1016 if (_fileService == null) { 1096 if (_fileService == null) {
1017 _fileService = _FileUtils.newServicePort(); 1097 _fileService = _FileUtils.newServicePort();
1018 } 1098 }
1019 } 1099 }
1020 1100
1021 void _writeEnqueued() {
1022 _pendingWrites++;
1023 if (_noPendingWriteTimer != null) {
1024 _noPendingWriteTimer.cancel();
1025 _noPendingWriteTimer = null;
1026 }
1027 }
1028
1029 void _writeCompleted() {
1030 _pendingWrites--;
1031 if (_pendingWrites == 0 && _onNoPendingWrites != null) {
1032 _onNoPendingWrites();
1033 }
1034 }
1035
1036 void _checkNotClosed() { 1101 void _checkNotClosed() {
1037 if (_id == 0) { 1102 if (_id == 0) {
1038 throw new FileIOException("File closed '$_name'"); 1103 throw new FileIOException("File closed '$_name'");
1039 } 1104 }
1040 } 1105 }
1041 1106
1042 String _name; 1107 final String _name;
1043 int _id; 1108 int _id;
1044 int _pendingWrites = 0;
1045 1109
1046 SendPort _fileService; 1110 SendPort _fileService;
1047
1048 Timer _noPendingWriteTimer;
1049
1050 Function _onNoPendingWrites;
1051 } 1111 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698