feat: enhance RhttpCompatibleClient with cancel token support and improve error handling; add new target for Windows ARM64

This commit is contained in:
Moustapha Kodjo Amadou 2026-02-25 12:56:16 +01:00
parent 9d829a16e7
commit 099180bc34
3 changed files with 55 additions and 5 deletions

View file

@ -1,7 +1,5 @@
import 'package:http/http.dart';
import 'package:mangayomi/services/http/rhttp/src/client/rhttp_client.dart';
import 'package:mangayomi/services/http/rhttp/src/model/exception.dart';
import 'package:mangayomi/services/http/rhttp/src/model/settings.dart';
import 'package:mangayomi/services/http/rhttp/rhttp.dart';
import 'package:mangayomi/src/rust/api/rhttp/http.dart' as rust;
/// An HTTP client that is compatible with the `http` package.
@ -36,6 +34,17 @@ class RhttpCompatibleClient with BaseClient {
@override
Future<StreamedResponse> send(BaseRequest request) async {
final CancelToken? cancelToken;
switch (request) {
case Abortable(abortTrigger: final trigger?):
cancelToken = CancelToken();
trigger.then((_) {
cancelToken?.cancel();
});
break;
case _:
cancelToken = null;
}
try {
final response = await client.requestStream(
method: switch (request.method) {
@ -53,12 +62,30 @@ class RhttpCompatibleClient with BaseClient {
url: request.url.toString(),
headers: rust.HttpHeaders.map(request.headers),
body: await request.finalize().toBytes(),
cancelToken: cancelToken,
);
final responseHeaderMap = response.headerMap;
return StreamedResponse(
response.body,
response.body.handleError((e, st) {
if (e is RhttpException) {
if (e is RhttpCancelException) {
Error.throwWithStackTrace(
RhttpWrappedRequestAbortedException(request.url, e),
st,
);
}
Error.throwWithStackTrace(
RhttpWrappedClientException(e.toString(), request.url, e),
st,
);
}
Error.throwWithStackTrace(
ClientException(e.toString(), request.url),
st,
);
}),
response.statusCode,
contentLength: switch (responseHeaderMap['content-length']) {
String s => int.parse(s),
@ -71,6 +98,12 @@ class RhttpCompatibleClient with BaseClient {
reasonPhrase: null,
);
} on RhttpException catch (e, st) {
if (e is RhttpCancelException) {
Error.throwWithStackTrace(
RhttpWrappedRequestAbortedException(request.url, e),
st,
);
}
Error.throwWithStackTrace(
RhttpWrappedClientException(e.toString(), request.url, e),
st,
@ -98,6 +131,16 @@ class RhttpWrappedClientException extends ClientException {
String toString() => rhttpException.toString();
}
class RhttpWrappedRequestAbortedException extends RequestAbortedException {
/// The original exception that was thrown by rhttp.
final RhttpException rhttpException;
RhttpWrappedRequestAbortedException(super.uri, this.rhttpException);
@override
String toString() => rhttpException.toString();
}
extension on ClientSettings {
/// Makes sure that the settings conform to the requirements of [BaseClient].
ClientSettings digest() {

View file

@ -326,7 +326,10 @@ async fn make_http_request_helper(
fn header_to_vec(headers: &reqwest::header::HeaderMap) -> Vec<(String, String)> {
headers
.iter()
.map(|(k, v)| (k.as_str().to_string(), v.to_str().unwrap().to_string()))
.filter_map(|(k, v)| match v.to_str() {
Ok(v_str) => Some((k.as_str().to_string(), v_str.to_string())),
Err(_) => None,
})
.collect()
}

View file

@ -46,6 +46,10 @@ class Target {
rust: 'x86_64-pc-windows-msvc',
flutter: 'windows-x64',
),
Target(
rust: 'aarch64-pc-windows-msvc',
flutter: 'windows-arm64',
),
Target(
rust: 'x86_64-unknown-linux-gnu',
flutter: 'linux-x64',