Add example/example.dart (dart-lang/stream_channel#52)
diff --git a/pkgs/stream_channel/CHANGELOG.md b/pkgs/stream_channel/CHANGELOG.md index 0d73828..8932188 100644 --- a/pkgs/stream_channel/CHANGELOG.md +++ b/pkgs/stream_channel/CHANGELOG.md
@@ -1,6 +1,7 @@ ## 2.1.2-dev * Require Dart 2.19 +* Add an example. ## 2.1.1
diff --git a/pkgs/stream_channel/example/example.dart b/pkgs/stream_channel/example/example.dart new file mode 100644 index 0000000..dd16f67 --- /dev/null +++ b/pkgs/stream_channel/example/example.dart
@@ -0,0 +1,110 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. 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:convert'; +import 'dart:io'; +import 'dart:isolate'; + +import 'package:stream_channel/isolate_channel.dart'; +import 'package:stream_channel/stream_channel.dart'; + +Future<void> main() async { + // A StreamChannel<T>, is in simplest terms, a wrapper around a Stream<T> and + // a StreamSink<T>. For example, you can create a channel that wraps standard + // IO: + var stdioChannel = StreamChannel(stdin, stdout); + stdioChannel.sink.add('Hello!\n'.codeUnits); + + // Like a Stream<T> can be transformed with a StreamTransformer<T>, a + // StreamChannel<T> can be transformed with a StreamChannelTransformer<T>. + // For example, we can handle standard input as strings: + var stringChannel = stdioChannel + .transform(StreamChannelTransformer.fromCodec(utf8)) + .transformStream(LineSplitter()); + stringChannel.sink.add('world!\n'); + + // You can implement StreamChannel<T> by extending StreamChannelMixin<T>, but + // it's much easier to use a StreamChannelController<T>. A controller has two + // StreamChannel<T> members: `local` and `foreign`. The creator of a + // controller should work with the `local` channel, while the recipient should + // work with the `foreign` channel, and usually will not have direct access to + // the underlying controller. + var ctrl = StreamChannelController<String>(); + ctrl.local.stream.listen((event) { + // Do something useful here... + }); + + // You can also pipe events from one channel to another. + ctrl + ..foreign.pipe(stringChannel) + ..local.sink.add('Piped!\n'); + await ctrl.local.sink.close(); + + // The StreamChannel<T> interface provides several guarantees, which can be + // found here: + // https://pub.dev/documentation/stream_channel/latest/stream_channel/StreamChannel-class.html + // + // By calling `StreamChannel<T>.withGuarantees()`, you can create a + // StreamChannel<T> that provides all guarantees. + var dummyCtrl0 = StreamChannelController<String>(); + var guaranteedChannel = StreamChannel.withGuarantees( + dummyCtrl0.foreign.stream, dummyCtrl0.foreign.sink); + + // To close a StreamChannel, use `sink.close()`. + await guaranteedChannel.sink.close(); + + // A MultiChannel<T> multiplexes multiple virtual channels across a single + // underlying transport layer. For example, an application listening over + // standard I/O can still support multiple clients if it has a mechanism to + // separate events from different clients. + // + // A MultiChannel<T> splits events into numbered channels, which are + // instances of VirtualChannel<T>. + var dummyCtrl1 = StreamChannelController<String>(); + var multiChannel = MultiChannel<String>(dummyCtrl1.foreign); + var channel1 = multiChannel.virtualChannel(); + await multiChannel.sink.close(); + + // The client/peer should also create its own MultiChannel<T>, connected to + // the underlying transport, use the corresponding ID's to handle events in + // their respective channels. It is up to you how to communicate channel ID's + // across different endpoints. + var dummyCtrl2 = StreamChannelController<String>(); + var multiChannel2 = MultiChannel<String>(dummyCtrl2.foreign); + var channel2 = multiChannel2.virtualChannel(channel1.id); + await channel2.sink.close(); + await multiChannel2.sink.close(); + + // Multiple instances of a Dart application can communicate easily across + // `SendPort`/`ReceivePort` pairs by means of the `IsolateChannel<T>` class. + // Typically, one endpoint will create a `ReceivePort`, and call the + // `IsolateChannel.connectReceive` constructor. The other endpoint will be + // given the corresponding `SendPort`, and then call + // `IsolateChannel.connectSend`. + var recv = ReceivePort(); + var recvChannel = IsolateChannel.connectReceive(recv); + var sendChannel = IsolateChannel.connectSend(recv.sendPort); + + // You must manually close `IsolateChannel<T>` sinks, however. + await recvChannel.sink.close(); + await sendChannel.sink.close(); + + // You can use the `Disconnector` transformer to cause a channel to act as + // though the remote end of its transport had disconnected. + var disconnector = Disconnector<String>(); + var disconnectable = stringChannel.transform(disconnector); + disconnectable.sink.add('Still connected!'); + await disconnector.disconnect(); + + // Additionally: + // * The `DelegatingStreamController<T>` class can be extended to build a + // basis for wrapping other `StreamChannel<T>` objects. + // * The `jsonDocument` transformer converts events to/from JSON, using + // the `json` codec from `dart:convert`. + // * `package:json_rpc_2` directly builds on top of + // `package:stream_channel`, so any compatible transport can be used to + // create interactive client/server or peer-to-peer applications (i.e. + // language servers, microservices, etc. +}