Skip to content

Commit

Permalink
JavaClient stream response body using byte arrays (#1007)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-james-dev authored Aug 24, 2023
1 parent 0e6e58a commit 5ac7cfe
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 14 deletions.
1 change: 1 addition & 0 deletions pkgs/java_http/jnigen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class_path:
- 'classes.jar'

classes:
- 'java.io.BufferedInputStream'
- 'java.io.InputStream'
- 'java.io.OutputStream'
- 'java.lang.System'
Expand Down
55 changes: 41 additions & 14 deletions pkgs/java_http/lib/src/java_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:http/http.dart';
import 'package:jni/jni.dart';
import 'package:path/path.dart';

import 'third_party/java/io/BufferedInputStream.dart';
import 'third_party/java/lang/System.dart';
import 'third_party/java/net/HttpURLConnection.dart';
import 'third_party/java/net/URL.dart';
Expand Down Expand Up @@ -96,15 +97,15 @@ class JavaClient extends BaseClient {
}

// TODO: Rename _isolateMethod to something more descriptive.
void _isolateMethod(
Future<void> _isolateMethod(
({
SendPort sendPort,
Uint8List body,
Map<String, String> headers,
String method,
Uri url,
}) request,
) {
) async {
final httpUrlConnection = URL
.ctor3(request.url.toString().toJString())
.openConnection()
Expand Down Expand Up @@ -140,7 +141,7 @@ class JavaClient extends BaseClient {
responseHeaders,
);

_responseBody(
await _responseBody(
request.url,
httpUrlConnection,
request.sendPort,
Expand Down Expand Up @@ -230,35 +231,61 @@ class JavaClient extends BaseClient {
return contentLength;
}

void _responseBody(
Future<void> _responseBody(
Uri requestUrl,
HttpURLConnection httpUrlConnection,
SendPort sendPort,
int? expectedBodyLength,
) {
) async {
final responseCode = httpUrlConnection.getResponseCode();

final inputStream = (responseCode >= 200 && responseCode <= 299)
? httpUrlConnection.getInputStream()
: httpUrlConnection.getErrorStream();
final responseBodyStream = (responseCode >= 200 && responseCode <= 299)
? BufferedInputStream(httpUrlConnection.getInputStream())
: BufferedInputStream(httpUrlConnection.getErrorStream());

int byte;
var actualBodyLength = 0;
// TODO: inputStream.read() could throw IOException.
while ((byte = inputStream.read()) != -1) {
sendPort.send([byte]);
actualBodyLength++;
final bytesBuffer = JArray(jbyte.type, 4096);

while (true) {
// TODO: read1() could throw IOException.
final bytesCount =
responseBodyStream.read1(bytesBuffer, 0, bytesBuffer.length);

if (bytesCount == -1) {
break;
}

if (bytesCount == 0) {
// No more data is available without blocking so give other Isolates an
// opportunity to run.
await Future<void>.delayed(Duration.zero);
continue;
}

sendPort.send(bytesBuffer.toUint8List(length: bytesCount));
actualBodyLength += bytesCount;
}

if (expectedBodyLength != null && actualBodyLength < expectedBodyLength) {
sendPort.send(ClientException('Unexpected end of body', requestUrl));
}

inputStream.close();
responseBodyStream.close();
}
}

extension on Uint8List {
JArray<jbyte> toJArray() =>
JArray(jbyte.type, length)..setRange(0, length, this);
}

extension on JArray<jbyte> {
Uint8List toUint8List({int? length}) {
length ??= this.length;
final list = Uint8List(length);
for (var i = 0; i < length; i++) {
list[i] = this[i];
}
return list;
}
}
248 changes: 248 additions & 0 deletions pkgs/java_http/lib/src/third_party/java/io/BufferedInputStream.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkgs/java_http/lib/src/third_party/java/io/_package.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5ac7cfe

Please sign in to comment.