kopia lustrzana https://gitlab.com/mysocialportal/relatica
Add very short term (2 second) HTTP GET request cache for when multiple calls to same endpoint from redraws
rodzic
782d3ba14d
commit
4ff673e6fd
|
@ -12,6 +12,133 @@ final _logger = Logger('NetworkUtils');
|
||||||
|
|
||||||
http.Response requestTimeout() => http.Response('Client side timeout', 408);
|
http.Response requestTimeout() => http.Response('Client side timeout', 408);
|
||||||
|
|
||||||
|
enum _RequestType {
|
||||||
|
get,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _expireDuration = Duration(seconds: 2);
|
||||||
|
|
||||||
|
class _CachedResponse {
|
||||||
|
final _RequestType requestType;
|
||||||
|
final Uri requestUri;
|
||||||
|
final Map<String, dynamic> requestBody;
|
||||||
|
final Map<String, String> headers;
|
||||||
|
final http.Response response;
|
||||||
|
final DateTime requestTime;
|
||||||
|
|
||||||
|
_CachedResponse(
|
||||||
|
{required this.requestType,
|
||||||
|
required this.requestUri,
|
||||||
|
required this.requestBody,
|
||||||
|
required this.headers,
|
||||||
|
required this.response,
|
||||||
|
required this.requestTime});
|
||||||
|
|
||||||
|
factory _CachedResponse.requestStub(_RequestType type, Uri uri,
|
||||||
|
Map<String, String>? headers, Map<String, dynamic>? body) =>
|
||||||
|
_CachedResponse(
|
||||||
|
requestType: type,
|
||||||
|
requestUri: uri,
|
||||||
|
requestBody: body ?? {},
|
||||||
|
headers: headers ?? {},
|
||||||
|
response: http.Response('', 555),
|
||||||
|
requestTime: DateTime(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
factory _CachedResponse.response(
|
||||||
|
_RequestType type,
|
||||||
|
Uri uri,
|
||||||
|
Map<String, String>? headers,
|
||||||
|
Map<String, dynamic>? body,
|
||||||
|
http.Response response,
|
||||||
|
) =>
|
||||||
|
_CachedResponse(
|
||||||
|
requestType: type,
|
||||||
|
requestUri: uri,
|
||||||
|
requestBody: body ?? {},
|
||||||
|
headers: headers ?? {},
|
||||||
|
response: response,
|
||||||
|
requestTime: DateTime.now(),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is _CachedResponse &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
requestType == other.requestType &&
|
||||||
|
requestUri == other.requestUri;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => requestType.hashCode ^ requestUri.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ExpiringRequestCache {
|
||||||
|
final _responses = <_CachedResponse, _CachedResponse>{};
|
||||||
|
|
||||||
|
void _cleanupCache() {
|
||||||
|
final expireTime = DateTime.now().subtract(_expireDuration);
|
||||||
|
_logger
|
||||||
|
.finest('Cleaning up request cache with ${_responses.length} entries');
|
||||||
|
_responses.removeWhere((key, value) {
|
||||||
|
final expired = key.requestTime.isBefore(expireTime);
|
||||||
|
if (expired) {
|
||||||
|
_logger.finest(
|
||||||
|
'Expiring request: ${value.requestType} => ${value.requestUri}');
|
||||||
|
}
|
||||||
|
return expired;
|
||||||
|
});
|
||||||
|
_logger.finest('Cleaned up request cache has ${_responses.length} entries');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<http.Response> getRequestOrExecute({
|
||||||
|
required Uri url,
|
||||||
|
Map<String, String>? headers,
|
||||||
|
Map<String, dynamic>? body,
|
||||||
|
Duration? timeout,
|
||||||
|
}) async {
|
||||||
|
_cleanupCache();
|
||||||
|
const type = _RequestType.get;
|
||||||
|
final requestStub = _CachedResponse.requestStub(
|
||||||
|
type,
|
||||||
|
url,
|
||||||
|
headers,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
late final http.Response response;
|
||||||
|
if (_responses.containsKey(requestStub)) {
|
||||||
|
print('Returning cached response for $type => $url');
|
||||||
|
response = _responses[requestStub]?.response ?? http.Response('', 555);
|
||||||
|
} else {
|
||||||
|
final request = http.get(
|
||||||
|
url,
|
||||||
|
headers: headers,
|
||||||
|
);
|
||||||
|
|
||||||
|
response = await request.timeout(
|
||||||
|
timeout ?? apiCallTimeout,
|
||||||
|
onTimeout: requestTimeout,
|
||||||
|
);
|
||||||
|
|
||||||
|
final cacheEntry = _CachedResponse.response(
|
||||||
|
type,
|
||||||
|
url,
|
||||||
|
headers ?? {},
|
||||||
|
body ?? {},
|
||||||
|
response,
|
||||||
|
);
|
||||||
|
|
||||||
|
print('Adding cached response for $type => $url');
|
||||||
|
_responses[cacheEntry] = cacheEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final _cache = _ExpiringRequestCache();
|
||||||
|
|
||||||
FutureResult<PagedResponse<String>, ExecError> getUrl(
|
FutureResult<PagedResponse<String>, ExecError> getUrl(
|
||||||
Uri url, {
|
Uri url, {
|
||||||
Map<String, String>? headers,
|
Map<String, String>? headers,
|
||||||
|
@ -23,14 +150,10 @@ FutureResult<PagedResponse<String>, ExecError> getUrl(
|
||||||
requestHeaders['Cookie'] = 'XDEBUG_SESSION=PHPSTORM;path=/';
|
requestHeaders['Cookie'] = 'XDEBUG_SESSION=PHPSTORM;path=/';
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final request = http.get(
|
final response = await _cache.getRequestOrExecute(
|
||||||
url,
|
url: url,
|
||||||
headers: requestHeaders,
|
headers: headers,
|
||||||
);
|
timeout: timeout ?? apiCallTimeout,
|
||||||
|
|
||||||
final response = await request.timeout(
|
|
||||||
timeout ?? apiCallTimeout,
|
|
||||||
onTimeout: requestTimeout,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
|
@ -87,6 +210,7 @@ FutureResult<String, ExecError> putUrl(
|
||||||
Uri url,
|
Uri url,
|
||||||
Map<String, dynamic> body, {
|
Map<String, dynamic> body, {
|
||||||
Map<String, String>? headers,
|
Map<String, String>? headers,
|
||||||
|
Duration? timeout,
|
||||||
}) async {
|
}) async {
|
||||||
_logger.fine('PUT: $url \n Body: $body');
|
_logger.fine('PUT: $url \n Body: $body');
|
||||||
try {
|
try {
|
||||||
|
@ -97,7 +221,7 @@ FutureResult<String, ExecError> putUrl(
|
||||||
);
|
);
|
||||||
|
|
||||||
final response = await request.timeout(
|
final response = await request.timeout(
|
||||||
apiCallTimeout,
|
timeout ?? apiCallTimeout,
|
||||||
onTimeout: requestTimeout,
|
onTimeout: requestTimeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -117,6 +241,7 @@ FutureResult<String, ExecError> deleteUrl(
|
||||||
Uri url,
|
Uri url,
|
||||||
Map<String, dynamic> body, {
|
Map<String, dynamic> body, {
|
||||||
Map<String, String>? headers,
|
Map<String, String>? headers,
|
||||||
|
Duration? timeout,
|
||||||
}) async {
|
}) async {
|
||||||
_logger.fine('DELETE: $url');
|
_logger.fine('DELETE: $url');
|
||||||
try {
|
try {
|
||||||
|
@ -127,7 +252,7 @@ FutureResult<String, ExecError> deleteUrl(
|
||||||
);
|
);
|
||||||
|
|
||||||
final response = await request.timeout(
|
final response = await request.timeout(
|
||||||
apiCallTimeout,
|
timeout ?? apiCallTimeout,
|
||||||
onTimeout: requestTimeout,
|
onTimeout: requestTimeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue