2

I would like to have simple API in my http server so everytime I write to HttpResponse I use stream.

so I convert all object into stream, ie object->json->stream

Stream<List<int>> toStream(Object value) {
    var json = JSON.encode(value);
    var controller = new StreamController<List<int>>(onListen: () => UTF8.encode(json));
    return controller.stream;
}

and later

(response as HttpResponse).addStream(toStream({"a": 1, "B": 2})
.then(() => response.flush())
.catchError((e, stack) {
    _logger.error("Handling ${context.path} finished with an error: $e");
    _logger.debug(stack.toString());
})
.whenComplete(() => response.close());

but I get error

Uncaught Error: Bad state: StreamSink is bound to a stream
Stack Trace: 
#0      _StreamSinkImpl.close (io_sink.dart:122)
#1      _HttpOutboundMessage.close (http_impl.dart:481)

Im not sure what I am doing wrong here. I saw examples where File's input stream was piped to response but I cannot make it work either.

any help appreciated!

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
kamiseq
  • 593
  • 4
  • 17

1 Answers1

2

There are a couple of things to note here:

First, the JSON and UTF8 encoders will produce a single value when you're calling encode(), so you'll be creating a Stream of just a single value. I wonder how much value you get from that.

Second, your Stream doesn't actually get any values. onListen is called when the first listener subscribes, but any value returned from onListen isn't used for anything. To create a Stream from a single value you probably want to use new Stream.fromIterable():

<List<int>> toStream(Object value) =>
    new Stream.fromIterable([UTF8.encode(JSON.encode(value))])

So that should cause a value to actually get into the Stream, and take care of your error. I think the source of you error is that the input stream is not closed, and creating it from an Iterable will close the Stream when the Iterable is exhausted.

pipe() should also now work, so you can try this:

toStream({"a": 1, "B": 2}).pipe(response)
  .then((_) {
    print("done");
  });

All said though, I don't see how this is better than:

response
  ..write(JSON.encode(value))
  ..close();
Justin Fagnani
  • 10,483
  • 2
  • 27
  • 37
  • well of course, but having simple API that always return Stream is nicer if you want add files and other stuff that actually can produce data in chunks. If I work on stream I can transform it (ie. Gzip) in other part of server, am I wrong? for example I have a use case where I send large JSON object like 70MB! crazy :) – kamiseq Feb 18 '14 at 06:55
  • And you right, I somehow missed pretty important thing to use controller.add(UTF8.encode(json)); controller.close(); as described here https://www.dartlang.org/articles/creating-streams/ – kamiseq Feb 18 '14 at 08:11