Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(offline_first_with_rest): add request/response callbacks to the RestOfflineQueueClient #447

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ class GraphqlOfflineQueueLink extends Link {

final GraphqlRequestSqliteCacheManager requestManager;

GraphqlOfflineQueueLink(this.requestManager)
: _logger = Logger('GraphqlOfflineQueueLink#${requestManager.databaseName}');
/// A callback triggered when a request failed, but will be reattempted.
final void Function(Request request, int statusCode)? onReattemptableResponse;

/// A callback triggered when a request throws an exception during execution.
final void Function(Request request, Object error)? onRequestError;

GraphqlOfflineQueueLink(
this.requestManager, {
this.onReattemptableResponse,
this.onRequestError,
}) : _logger = Logger('GraphqlOfflineQueueLink#${requestManager.databaseName}');

@override
Stream<Response> request(Request request, [NextLink? forward]) async* {
Expand All @@ -33,6 +42,7 @@ class GraphqlOfflineQueueLink extends Link {
yield* forward!(request).handleError(
(e) async {
_logger.warning('GraphqlOfflineQueueLink#request: error $e');
onRequestError?.call(request, e);
final db = await requestManager.getDb();
await cacheItem.unlock(db);
},
Expand All @@ -46,6 +56,8 @@ class GraphqlOfflineQueueLink extends Link {
// request was successfully sent and can be removed
_logger.finest('removing from queue: ${cacheItem.toSqlite()}');
await cacheItem.delete(db);
} else {
onReattemptableResponse?.call(request, response.response['statusCode'] as int);
}
final db = await requestManager.getDb();
await cacheItem.unlock(db);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ abstract class OfflineFirstWithRestRepository
@protected
late RestOfflineRequestQueue offlineRequestQueue;

/// A callback triggered when the response of a request has a status code
/// which is present in the [reattemptForStatusCodes] list.
///
/// Forwarded to [RestOfflineQueueClient].
void Function(http.Request request, int statusCode)? onReattemptableResponse;

/// A callback triggered when a request throws an exception during execution.
///
/// Forwarded to [RestOfflineQueueClient].
void Function(http.Request, Object)? onRequestError;

OfflineFirstWithRestRepository({
super.autoHydrate,
super.loggerName,
Expand All @@ -47,6 +58,12 @@ abstract class OfflineFirstWithRestRepository
/// This property is forwarded to `RestOfflineQueueClient` and assumes
/// its defaults
List<int>? reattemptForStatusCodes,

/// This property is forwarded to `RestOfflineQueueClient`.
this.onReattemptableResponse,

/// This property is forwarded to `RestOfflineQueueClient`.
this.onRequestError,
required RestProvider restProvider,
required super.sqliteProvider,
}) : remoteProvider = restProvider,
Expand All @@ -57,6 +74,8 @@ abstract class OfflineFirstWithRestRepository
restProvider.client,
offlineQueueManager,
reattemptForStatusCodes: reattemptForStatusCodes,
onRequestError: onRequestError,
onReattemptableResponse: onReattemptableResponse,
);
offlineRequestQueue = RestOfflineRequestQueue(
client: remoteProvider.client as RestOfflineQueueClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ class RestOfflineQueueClient extends http.BaseClient {

final RequestSqliteCacheManager<http.Request> requestManager;

/// A callback triggered when the response of a request has a status code
/// which is present in the [reattemptForStatusCodes] list.
void Function(http.Request request, int statusCode)? onReattemptableResponse;

/// A callback triggered when a request throws an exception during execution.
devj3ns marked this conversation as resolved.
Show resolved Hide resolved
///
/// `SocketException`s (errors thrown due to missing connectivity) will also be forwarded to this callback.
void Function(http.Request request, Object error)? onRequestError;

/// If the response returned from the client is one of these error codes, the request
/// **will not** be removed from the queue. For example, if the result of a request produces a
/// 404 status code response (such as in a Tunnel not found exception), the request will
Expand All @@ -37,6 +46,8 @@ class RestOfflineQueueClient extends http.BaseClient {
RestOfflineQueueClient(
this._inner,
this.requestManager, {
this.onReattemptableResponse,
this.onRequestError,
List<int>? reattemptForStatusCodes,

/// Any request URI that begins with one of these paths will not be
Expand Down Expand Up @@ -89,17 +100,27 @@ class RestOfflineQueueClient extends http.BaseClient {
// Attempt to make HTTP Request
final resp = await _inner.send(request);

if (cacheItem.requestIsPush && !reattemptForStatusCodes.contains(resp.statusCode)) {
final db = await requestManager.getDb();
// request was successfully sent and can be removed
_logger.finest('removing from queue: ${cacheItem.toSqlite()}');
await cacheItem.delete(db);
if (cacheItem.requestIsPush) {
if (!reattemptForStatusCodes.contains(resp.statusCode)) {
final db = await requestManager.getDb();
// request was successfully sent and can be removed
_logger.finest('removing from queue: ${cacheItem.toSqlite()}');
await cacheItem.delete(db);
} else if (onReattemptableResponse != null) {
_logger.finer(
'request failed, will be reattempted: ${cacheItem.toSqlite()}',
);
onReattemptableResponse?.call(request, resp.statusCode);
}
}

return resp;
} catch (e) {
// e.g. SocketExceptions will be caught here
onRequestError?.call(request, e);
_logger.warning('#send: $e');
} finally {
// unlock the request for a later a reattempt
final db = await requestManager.getDb();
await cacheItem.unlock(db);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ abstract class OfflineFirstWithSupabaseRepository
504,
],
bool? serialProcessing,
void Function(http.Request request, int statusCode)? onReattemptableResponse,
void Function(http.Request, Object)? onRequestError,
}) {
final client = RestOfflineQueueClient(
innerClient ?? http.Client(),
Expand All @@ -200,6 +202,8 @@ abstract class OfflineFirstWithSupabaseRepository
),
ignorePaths: ignorePaths,
reattemptForStatusCodes: reattemptForStatusCodes,
onReattemptableResponse: onReattemptableResponse,
onRequestError: onRequestError,
);
return (client, RestOfflineRequestQueue(client: client));
}
Expand Down
Loading