// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; import 'package:mojo/core.dart'; // Helper class to drain the contents of a mojo data pipe to a file. class PipeToFile { MojoDataPipeConsumer _consumer; MojoEventSubscription _events; IOSink _outputStream; PipeToFile(this._consumer, String outputPath) { _events = new MojoEventSubscription(_consumer.handle); _outputStream = new File(outputPath).openWrite(); } Future<int> _doRead() async { ByteData thisRead = _consumer.beginRead(); if (thisRead == null) { throw 'Data pipe beginRead failed: ${_consumer.status}'; } // TODO(mpcomplete): Should I worry about the _eventStream listen callback // being invoked again before this completes? await _outputStream.add(thisRead.buffer.asUint8List()); return _consumer.endRead(thisRead.lengthInBytes); } Future<int> drain() { Completer<int> completer = new Completer(); _events.subscribe((int signal) { (() async { if (MojoHandleSignals.isReadable(signal)) { int result = await _doRead(); if (result != MojoResult.kOk) { _events.close(); _events = null; _outputStream.close(); completer.complete(result); } else { _events.enableReadEvents(); } } else if (MojoHandleSignals.isPeerClosed(signal)) { _events.close(); _events = null; _outputStream.close(); completer.complete(MojoResult.kOk); } else { throw 'Unexpected handle event: ${MojoHandleSignals.string(signal)}'; } })(); }); return completer.future; } static Future<int> copyToFile(MojoDataPipeConsumer consumer, String outputPath) { PipeToFile drainer = new PipeToFile(consumer, outputPath); return drainer.drain(); } }