dvReadCapped function
Reads stream up to limit bytes, or null when it is longer.
Stops at the first byte past the limit rather than reading to the end and measuring, because reading to the end is the thing being prevented. The subscription is cancelled, so a sender that keeps writing is dropped rather than served.
Implementation
Future<Uint8List?> dvReadCapped(Stream<List<int>> stream, int limit) async {
final List<Uint8List> chunks = <Uint8List>[];
int total = 0;
final Completer<Uint8List?> done = Completer<Uint8List?>();
late StreamSubscription<List<int>> sub;
sub = stream.listen(
(List<int> chunk) {
if (done.isCompleted) return;
total += chunk.length;
if (total > limit) {
done.complete(null);
sub.cancel();
return;
}
chunks.add(chunk is Uint8List ? chunk : Uint8List.fromList(chunk));
},
onError: (Object error, StackTrace stack) {
if (!done.isCompleted) done.completeError(error, stack);
},
onDone: () {
if (done.isCompleted) return;
final Uint8List out = Uint8List(total);
int offset = 0;
for (final Uint8List chunk in chunks) {
out.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length;
}
done.complete(out);
},
cancelOnError: true,
);
return done.future;
}