Figuring out how to close an Input Stream

32 views
Skip to first unread message

John McMahon

unread,
Mar 11, 2022, 1:25:58 AMMar 11
to Dart Misc
Hey folks,

I'm kind of baffled by this. I've done google searches and saw a thread on GitHub about something similar (which is where I sot the idea to use stdin.listen().cancel();, but I'm getting ahead of myself).

I haven't worked much with Streams, mostly Subscriptions and Futures in AngularDart,

I have a scenario where I have a command-line tool and I prompt the user for input and I have a timeout on that request largely due to unit tests failing if I don't find someway to end the prompt.

I am using stdin to wait for input from the user, a simply yes/no or y/n.

But when I run my tests, the first test fails at the end I have stdin.listen().cancel(); because the stream is "has already been listened to". If I remove this, the tests work fine, locally. But I feel like I should close the stream when I no longer need it.

############### Example ################
import 'dart:convert';
import 'dart:io';

String _userDecision = '';
final _inputStream = utf8.decoder.bind(stdin);

Future<void> _promptUser() async {
    _userDecision = await _inputStream
        .timeout(const Duration(seconds: 15), onTimeout: (sink) => sink.add('N'))
        .first;

    _userDecision = _userDecision.toLowerCase();

    if (_userDecision.isNotEmpty) {
        // Closing Stream once userDecision has a proper value
        await _inputStream.listen((event) => event).cancel();
        stdout.writeln('Stream closed');
    }
}
##################

Chris Norman

unread,
Mar 11, 2022, 6:29:12 AMMar 11
to mi...@dartlang.org
Hi,
You need to hold a reference to the subscription object.

Calling `listen` returns a StreamSubscription instance. You can (and should) call `cancel` on that.

As a tip, if you don't call cancel on it, but you're holding the reference, the analyzer will complain.

HTH,

Take care,

Chris Norman



--
For more ways to connect visit https://dart.dev/community
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.
To view this discussion on the web visit https://groups.google.com/a/dartlang.org/d/msgid/misc/18efe4e0-b292-4b9e-a66d-8d3f831961a4n%40dartlang.org.

John McMahon

unread,
Mar 13, 2022, 8:35:36 AMMar 13
to Dart Misc, chris....@googlemail.com
Thanks Chris, I'll give that a shot this evening.

John McMahon

unread,
Mar 13, 2022, 8:36:06 AMMar 13
to Dart Misc, chris....@googlemail.com
Thanks Chris, that helped me properly cancel it. Now I refactored the example to include your guidance (see below). The issue I have now is how to stop listening once my criteria is met. As soon as the user responds, I'd like the subscription to quit out of the listen(). I have tried return, but I think because listen() returns void, that doesn't do anything.

I also tried throwing an exception thinking the onError parameter would serve as a catch to prevent it from propagating up the chain.

On Friday, March 11, 2022 at 6:29:12 AM UTC-5 chris....@googlemail.com wrote:

John McMahon

unread,
Mar 14, 2022, 1:20:20 AMMar 14
to Dart Misc, John McMahon, chris....@googlemail.com
Updated Example:
import 'dart:async';

import 'dart:convert';
import 'dart:io';

String _userDecision = '';

Future<void> _promptUser() async {
    final StreamSubscription _inputStream = utf8.decoder.bind(stdin)
        .listen((input) {
            _userDecision = input.toLowerCase();

            if (_userDecision.isNotEmpty) {
            // I want the subscription to stop listening
               return;

            }
        });

       if (_userDecision.isNotEmpty) {
         // Closing Stream once userDecision has a proper value
          await _inputStream.cancel();
          stdout.writeln('Stream closed');
Reply all
Reply to author
Forward
0 new messages