fix: timeout when sending large files

fixes https://gitlab.com/famedly/company/frontend/famedly-web/-/issues/540
This commit is contained in:
Nicolas Werner 2022-09-06 21:18:07 +02:00
parent 61369c4b1d
commit ab73047e51
2 changed files with 4 additions and 59 deletions

View File

@ -189,8 +189,8 @@ class Client extends MatrixApi {
? NativeImplementationsIsolate(compute)
: nativeImplementations,
super(
httpClient:
VariableTimeoutHttpClient(httpClient ?? http.Client())) {
httpClient: FixedTimeoutHttpClient(
httpClient ?? http.Client(), Duration(seconds: 35))) {
if (logLevel != null) Logs().level = logLevel;
importantStateEvents.addAll([
EventTypes.RoomName,

View File

@ -20,19 +20,6 @@ import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:matrix/matrix.dart';
/// Stream.timeout fails if no progress is made in timeLimit.
/// In contrast, streamTotalTimeout fails if the stream isn't completed
/// until timeoutFuture.
Stream<T> streamTotalTimeout<T>(
Stream<T> stream, Future<Never> timeoutFuture) async* {
final si = StreamIterator(stream);
while (await Future.any([si.moveNext(), timeoutFuture])) {
yield si.current;
}
}
http.StreamedResponse replaceStream(
http.StreamedResponse base, Stream<List<int>> stream) =>
http.StreamedResponse(
@ -57,10 +44,8 @@ abstract class TimeoutHttpClient extends http.BaseClient {
@override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
final timeoutFuture = Completer<Never>().future.timeout(timeout);
final response = await Future.any([inner.send(request), timeoutFuture]);
return replaceStream(
response, streamTotalTimeout(response.stream, timeoutFuture));
final response = await inner.send(request);
return replaceStream(response, response.stream.timeout(timeout));
}
}
@ -69,43 +54,3 @@ class FixedTimeoutHttpClient extends TimeoutHttpClient {
@override
Duration timeout;
}
class VariableTimeoutHttpClient extends TimeoutHttpClient {
/// Matrix synchronisation is done with https long polling. This needs a
/// timeout which is usually 30 seconds.
int syncTimeoutSec;
int _timeoutFactor = 1;
@override
Duration get timeout =>
Duration(seconds: _timeoutFactor * syncTimeoutSec + 5);
VariableTimeoutHttpClient(http.Client inner, [this.syncTimeoutSec = 30])
: super(inner);
@override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
try {
final response = await super.send(request);
return replaceStream(response, (() async* {
try {
await for (final chunk in response.stream) {
yield chunk;
}
_timeoutFactor = 1;
} on TimeoutException catch (e, s) {
_timeoutFactor *= 2;
throw MatrixConnectionException(e, s);
} catch (e, s) {
throw MatrixConnectionException(e, s);
}
})());
} on TimeoutException catch (e, s) {
_timeoutFactor *= 2;
throw MatrixConnectionException(e, s);
} catch (e, s) {
throw MatrixConnectionException(e, s);
}
}
}