LCOV - code coverage report
Current view: top level - Users/duwen/Documents/code/dio/dio/lib/src - interceptor.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 106 126 84.1 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          Line data    Source code
       1             : part of 'dio_mixin.dart';
       2             : 
       3             : typedef _WaitCallback<T> = FutureOr<T> Function();
       4             : 
       5             : /// Add lock/unlock API for interceptors.
       6             : class Lock {
       7             :   Future? _lock;
       8             : 
       9             :   late Completer _completer;
      10             : 
      11             :   /// Whether this interceptor has been locked.
      12          16 :   bool get locked => _lock != null;
      13             : 
      14             :   /// Lock the interceptor.
      15             :   ///
      16             :   /// Once the request/response/error interceptor is locked, the incoming request/response/error
      17             :   /// will wait before entering the interceptor until the interceptor is unlocked.
      18           0 :   void lock() {
      19           0 :     if (!locked) {
      20           0 :       _completer = Completer();
      21           0 :       _lock = _completer.future;
      22             :     }
      23             :   }
      24             : 
      25             :   /// Unlock the interceptor. please refer to [lock()]
      26           0 :   void unlock() {
      27           0 :     if (locked) {
      28           0 :       _completer.complete();
      29           0 :       _lock = null;
      30             :     }
      31             :   }
      32             : 
      33             :   /// Clean the interceptor queue.
      34           0 :   void clear([String msg = 'cancelled']) {
      35           0 :     if (locked) {
      36           0 :       _completer.completeError(msg);
      37           0 :       _lock = null;
      38             :     }
      39             :   }
      40             : 
      41             :   /// If the interceptor is locked, the incoming request/response/error task
      42             :   /// will wait before entering the interceptor until the interceptor is unlocked
      43             :   ///
      44             :   /// [callback] the function  will return a `Future`
      45             :   /// @nodoc
      46           0 :   Future<T>? _wait<T>(_WaitCallback<T> callback) {
      47           0 :     if (locked) {
      48             :       // we use a future as a queue
      49           0 :       return _lock!.then((d) => callback());
      50             :     }
      51             :     return null;
      52             :   }
      53             : }
      54             : 
      55             : /// Internal enum
      56             : /// @nodoc
      57          11 : enum InterceptorResultType {
      58             :   next,
      59             :   resolve,
      60             :   resolveCallFollowing,
      61             :   reject,
      62             :   rejectCallFollowing,
      63             : }
      64             : 
      65             : /// Internal class, It is used to pass state between current and next interceptors.
      66             : /// @nodoc
      67             : class InterceptorState<T> {
      68           8 :   InterceptorState(this.data, [this.type = InterceptorResultType.next]);
      69             : 
      70             :   T data;
      71             :   InterceptorResultType type;
      72             : }
      73             : 
      74             : class _BaseHandler {
      75             :   final _completer = Completer<InterceptorState>();
      76             :   void Function()? _processNextInQueue;
      77             : 
      78          24 :   Future<InterceptorState> get future => _completer.future;
      79             : 
      80           0 :   bool get isCompleted => _completer.isCompleted;
      81             : }
      82             : 
      83             : /// Handler for request interceptor.
      84             : class RequestInterceptorHandler extends _BaseHandler {
      85             :   /// Continue to call the next request interceptor.
      86           2 :   void next(RequestOptions requestOptions) {
      87           6 :     _completer.complete(InterceptorState<RequestOptions>(requestOptions));
      88           2 :     _processNextInQueue?.call();
      89             :   }
      90             : 
      91             :   /// Return the response directly! Other request interceptor(s) will not be executed,
      92             :   /// but response and error interceptor(s) may be executed, which depends on whether
      93             :   /// the value of parameter [callFollowingResponseInterceptor] is true.
      94             :   ///
      95             :   /// [response]: Response object to return.
      96             :   /// [callFollowingResponseInterceptor]: Whether to call the response interceptor(s).
      97           7 :   void resolve(Response response,
      98             :       [bool callFollowingResponseInterceptor = false]) {
      99          14 :     _completer.complete(
     100           7 :       InterceptorState<Response>(
     101             :         response,
     102             :         callFollowingResponseInterceptor
     103             :             ? InterceptorResultType.resolveCallFollowing
     104             :             : InterceptorResultType.resolve,
     105             :       ),
     106             :     );
     107           7 :     _processNextInQueue?.call();
     108             :   }
     109             : 
     110             :   /// Complete the request with an error! Other request/response interceptor(s) will not
     111             :   /// be executed, but error interceptor(s) may be executed, which depends on whether the
     112             :   /// value of parameter [callFollowingErrorInterceptor] is true.
     113             :   ///
     114             :   /// [error]: Error info to reject.
     115             :   /// [callFollowingErrorInterceptor]: Whether to call the error interceptor(s).
     116           6 :   void reject(DioError error, [bool callFollowingErrorInterceptor = false]) {
     117          12 :     _completer.completeError(
     118           6 :       InterceptorState<DioError>(
     119             :         error,
     120             :         callFollowingErrorInterceptor
     121             :             ? InterceptorResultType.rejectCallFollowing
     122             :             : InterceptorResultType.reject,
     123             :       ),
     124           6 :       error.stackTrace,
     125             :     );
     126           6 :     _processNextInQueue?.call();
     127             :   }
     128             : }
     129             : 
     130             : /// Handler for response interceptor.
     131             : class ResponseInterceptorHandler extends _BaseHandler {
     132             :   /// Continue to call the next response interceptor.
     133           2 :   void next(Response response) {
     134           4 :     _completer.complete(
     135           2 :       InterceptorState<Response>(response),
     136             :     );
     137           2 :     _processNextInQueue?.call();
     138             :   }
     139             : 
     140             :   /// Return the response directly! Other response interceptor(s) will not be executed.
     141             :   /// [response]: Response object to return.
     142           1 :   void resolve(Response response) {
     143           2 :     _completer.complete(
     144           1 :       InterceptorState<Response>(
     145             :         response,
     146             :         InterceptorResultType.resolve,
     147             :       ),
     148             :     );
     149           1 :     _processNextInQueue?.call();
     150             :   }
     151             : 
     152             :   /// Complete the request with an error! Other response interceptor(s) will not
     153             :   /// be executed, but error interceptor(s) may be executed, which depends on whether the
     154             :   /// value of parameter [callFollowingErrorInterceptor] is true.
     155             :   ///
     156             :   /// [error]: Error info to reject.
     157             :   /// [callFollowingErrorInterceptor]: Whether to call the error interceptor(s).
     158           1 :   void reject(DioError error, [bool callFollowingErrorInterceptor = false]) {
     159           2 :     _completer.completeError(
     160           1 :       InterceptorState<DioError>(
     161             :         error,
     162             :         callFollowingErrorInterceptor
     163             :             ? InterceptorResultType.rejectCallFollowing
     164             :             : InterceptorResultType.reject,
     165             :       ),
     166           1 :       error.stackTrace,
     167             :     );
     168           1 :     _processNextInQueue?.call();
     169             :   }
     170             : }
     171             : 
     172             : /// Handler for error interceptor.
     173             : class ErrorInterceptorHandler extends _BaseHandler {
     174             :   /// Continue to call the next error interceptor.
     175           2 :   void next(DioError err) {
     176           4 :     _completer.completeError(
     177           2 :       InterceptorState<DioError>(err),
     178           2 :       err.stackTrace,
     179             :     );
     180           2 :     _processNextInQueue?.call();
     181             :   }
     182             : 
     183             :   /// Complete the request with Response object and other error interceptor(s) will not be executed.
     184             :   /// This will be considered a successful request!
     185             :   ///
     186             :   /// [response]: Response object to return.
     187           1 :   void resolve(Response response) {
     188           3 :     _completer.complete(InterceptorState<Response>(
     189             :       response,
     190             :       InterceptorResultType.resolve,
     191             :     ));
     192           1 :     _processNextInQueue?.call();
     193             :   }
     194             : 
     195             :   /// Complete the request with a error directly! Other error interceptor(s) will not be executed.
     196           1 :   void reject(DioError error) {
     197           2 :     _completer.completeError(
     198           1 :       InterceptorState<DioError>(
     199             :         error,
     200             :         InterceptorResultType.reject,
     201             :       ),
     202           1 :       error.stackTrace,
     203             :     );
     204           1 :     _processNextInQueue?.call();
     205             :   }
     206             : }
     207             : 
     208             : ///  Dio instance may have interceptor(s) by which you can intercept
     209             : ///  requests/responses/errors before they are handled by `then` or `catchError`.
     210             : ///  See also:
     211             : ///   - [InterceptorsWrapper]  A helper class to create Interceptor(s).
     212             : ///   - [QueuedInterceptor] Serialize the request/response/error before they enter the interceptor.
     213             : ///   - [QueuedInterceptorsWrapper]  A helper class to create QueuedInterceptor(s).
     214             : class Interceptor {
     215             :   /// The callback will be executed before the request is initiated.
     216             :   ///
     217             :   /// If you want to continue the request, call [handler.next].
     218             :   ///
     219             :   /// If you want to complete the request with some custom data,
     220             :   /// you can resolve a [Response] object with [handler.resolve].
     221             :   ///
     222             :   /// If you want to complete the request with an error message,
     223             :   /// you can reject a [DioError] object with [handler.reject].
     224           1 :   void onRequest(
     225             :     RequestOptions options,
     226             :     RequestInterceptorHandler handler,
     227             :   ) =>
     228           1 :       handler.next(options);
     229             : 
     230             :   /// The callback will be executed on success.
     231             :   /// If you want to continue the response, call [handler.next].
     232             :   ///
     233             :   /// If you want to complete the response with some custom data directly,
     234             :   /// you can resolve a [Response] object with [handler.resolve] and other
     235             :   /// response interceptor(s) will not be executed.
     236             :   ///
     237             :   /// If you want to complete the response with an error message,
     238             :   /// you can reject a [DioError] object with [handler.reject].
     239           1 :   void onResponse(
     240             :     Response response,
     241             :     ResponseInterceptorHandler handler,
     242             :   ) =>
     243           1 :       handler.next(response);
     244             : 
     245             :   /// The callback will be executed on error.
     246             :   ///
     247             :   /// If you want to continue the error , call [handler.next].
     248             :   ///
     249             :   /// If you want to complete the response with some custom data directly,
     250             :   /// you can resolve a [Response] object with [handler.resolve] and other
     251             :   /// error interceptor(s) will be skipped.
     252             :   ///
     253             :   /// If you want to complete the response with an error message directly,
     254             :   /// you can reject a [DioError] object with [handler.reject], and other
     255             :   ///  error interceptor(s) will be skipped.
     256           0 :   void onError(
     257             :     DioError err,
     258             :     ErrorInterceptorHandler handler,
     259             :   ) =>
     260           0 :       handler.next(err);
     261             : }
     262             : 
     263             : typedef InterceptorSendCallback = void Function(
     264             :   RequestOptions options,
     265             :   RequestInterceptorHandler handler,
     266             : );
     267             : 
     268             : typedef InterceptorSuccessCallback = void Function(
     269             :   Response e,
     270             :   ResponseInterceptorHandler handler,
     271             : );
     272             : 
     273             : typedef InterceptorErrorCallback = void Function(
     274             :     DioError e, ErrorInterceptorHandler handler);
     275             : 
     276             : mixin _InterceptorWrapperMixin on Interceptor {
     277             :   InterceptorSendCallback? _onRequest;
     278             : 
     279             :   InterceptorSuccessCallback? _onResponse;
     280             : 
     281             :   InterceptorErrorCallback? _onError;
     282             : 
     283           2 :   @override
     284             :   void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
     285           2 :     if (_onRequest != null) {
     286           2 :       _onRequest!(options, handler);
     287             :     } else {
     288           1 :       handler.next(options);
     289             :     }
     290             :   }
     291             : 
     292           2 :   @override
     293             :   void onResponse(Response response, ResponseInterceptorHandler handler) {
     294           2 :     if (_onResponse != null) {
     295           1 :       _onResponse!(response, handler);
     296             :     } else {
     297           2 :       handler.next(response);
     298             :     }
     299             :   }
     300             : 
     301           2 :   @override
     302             :   void onError(DioError err, ErrorInterceptorHandler handler) {
     303           2 :     if (_onError != null) {
     304           2 :       _onError!(err, handler);
     305             :     } else {
     306           0 :       handler.next(err);
     307             :     }
     308             :   }
     309             : }
     310             : 
     311             : /// [InterceptorsWrapper] is a helper class, which is used to conveniently
     312             : /// create interceptor(s).
     313             : /// See also:
     314             : ///  - [Interceptor]
     315             : ///  - [QueuedInterceptor] Serialize the request/response/error before they enter the interceptor.
     316             : ///  - [QueuedInterceptorsWrapper]  A helper class to create QueuedInterceptor(s).
     317             : class InterceptorsWrapper extends Interceptor with _InterceptorWrapperMixin {
     318             :   InterceptorSendCallback? __onRequest;
     319             : 
     320             :   InterceptorSuccessCallback? __onResponse;
     321             : 
     322             :   InterceptorErrorCallback? __onError;
     323             : 
     324           1 :   InterceptorsWrapper({
     325             :     InterceptorSendCallback? onRequest,
     326             :     InterceptorSuccessCallback? onResponse,
     327             :     InterceptorErrorCallback? onError,
     328             :   })  : __onRequest = onRequest,
     329             :         __onResponse = onResponse,
     330             :         __onError = onError;
     331             : 
     332           1 :   @override
     333           1 :   InterceptorErrorCallback? get _onError => __onError;
     334             : 
     335           1 :   @override
     336           1 :   InterceptorSendCallback? get _onRequest => __onRequest;
     337             : 
     338           1 :   @override
     339           1 :   InterceptorSuccessCallback? get _onResponse => __onResponse;
     340             : }
     341             : 
     342             : /// Interceptors are a queue, and you can add any number of interceptors,
     343             : /// All interceptors will be executed in first in first out order.
     344             : class Interceptors extends ListMixin<Interceptor> {
     345             :   final _list = <Interceptor>[];
     346             :   final Lock _requestLock = Lock();
     347             :   final Lock _responseLock = Lock();
     348             :   final Lock _errorLock = Lock();
     349             : 
     350           8 :   @Deprecated(
     351             :       'Will delete in v5.0. Use `QueuedInterceptor` instead, more detail see'
     352             :       ' https://github.com/flutterchina/dio/issues/1308')
     353           8 :   Lock get requestLock => _requestLock;
     354           7 :   @Deprecated(
     355             :       'Will delete in v5.0. Use `QueuedInterceptor` instead, more detail see'
     356             :       ' https://github.com/flutterchina/dio/issues/1308')
     357           7 :   Lock get responseLock => _responseLock;
     358           2 :   @Deprecated(
     359             :       'Will delete in v5.0. Use `QueuedInterceptor` instead, more detail see'
     360             :       ' https://github.com/flutterchina/dio/issues/1308')
     361           2 :   Lock get errorLock => _errorLock;
     362             : 
     363             :   @override
     364             :   int length = 0;
     365             : 
     366           2 :   @override
     367             :   Interceptor operator [](int index) {
     368           4 :     return _list[index];
     369             :   }
     370             : 
     371           2 :   @override
     372             :   void operator []=(int index, value) {
     373           6 :     if (_list.length == index) {
     374           4 :       _list.add(value);
     375             :     } else {
     376           2 :       _list[index] = value;
     377             :     }
     378             :   }
     379             : }
     380             : 
     381             : class _InterceptorParams<T, V> {
     382           1 :   _InterceptorParams(this.data, this.handler);
     383             : 
     384             :   T data;
     385             :   V handler;
     386             : }
     387             : 
     388             : class _TaskQueue {
     389             :   final queue = Queue<_InterceptorParams>();
     390             :   bool processing = false;
     391             : }
     392             : 
     393             : /// Serialize the request/response/error before they enter the interceptor.
     394             : ///
     395             : /// If there are multiple concurrent requests, the request is added to a queue before
     396             : /// entering the interceptor. Only one request at a time enters the interceptor, and
     397             : /// after that request is processed by the interceptor, the next request will enter
     398             : /// the interceptor.
     399             : class QueuedInterceptor extends Interceptor {
     400             :   _TaskQueue _requestQueue = _TaskQueue();
     401             :   _TaskQueue _responseQueue = _TaskQueue();
     402             :   _TaskQueue _errorQueue = _TaskQueue();
     403             : 
     404           1 :   void _handleRequest(
     405             :       RequestOptions options, RequestInterceptorHandler handler) {
     406           3 :     _handleQueue(_requestQueue, options, handler, onRequest);
     407             :   }
     408             : 
     409           1 :   void _handleResponse(Response response, ResponseInterceptorHandler handler) {
     410           3 :     _handleQueue(_responseQueue, response, handler, onResponse);
     411             :   }
     412             : 
     413           1 :   void _handleError(DioError err, ErrorInterceptorHandler handler) {
     414           3 :     _handleQueue(_errorQueue, err, handler, onError);
     415             :   }
     416             : 
     417           1 :   void _handleQueue<T, V extends _BaseHandler>(
     418             :     _TaskQueue taskQueue,
     419             :     T data,
     420             :     V handler,
     421             :     callback,
     422             :   ) {
     423           1 :     var task = _InterceptorParams<T, V>(data, handler);
     424           2 :     task.handler._processNextInQueue =
     425           1 :         _processNextTaskInQueueCallback(taskQueue, callback);
     426           2 :     taskQueue.queue.add(task);
     427           1 :     if (!taskQueue.processing) {
     428           1 :       taskQueue.processing = true;
     429           2 :       final _task = taskQueue.queue.removeFirst();
     430             :       try {
     431           3 :         callback(_task.data, _task.handler);
     432             :       } catch (e) {
     433           0 :         _task.handler._processNextInQueue();
     434             :       }
     435             :     }
     436             :   }
     437             : }
     438             : 
     439           1 : void Function() _processNextTaskInQueueCallback(_TaskQueue taskQueue, cb) {
     440           1 :   return () {
     441           2 :     if (taskQueue.queue.isNotEmpty) {
     442           2 :       final next = taskQueue.queue.removeFirst();
     443           2 :       assert(next.handler._processNextInQueue != null);
     444           3 :       cb(next.data, next.handler);
     445             :     } else {
     446           1 :       taskQueue.processing = false;
     447             :     }
     448             :   };
     449             : }
     450             : 
     451             : /// [QueuedInterceptorsWrapper] is a helper class, which is used to conveniently
     452             : /// create QueuedInterceptor(s).
     453             : /// See also:
     454             : ///  - [Interceptor]
     455             : ///  - [InterceptorsWrapper]
     456             : ///  - [QueuedInterceptors]
     457             : class QueuedInterceptorsWrapper extends QueuedInterceptor
     458             :     with _InterceptorWrapperMixin {
     459             :   InterceptorSendCallback? __onRequest;
     460             : 
     461             :   InterceptorSuccessCallback? __onResponse;
     462             : 
     463             :   InterceptorErrorCallback? __onError;
     464             : 
     465           1 :   QueuedInterceptorsWrapper({
     466             :     InterceptorSendCallback? onRequest,
     467             :     InterceptorSuccessCallback? onResponse,
     468             :     InterceptorErrorCallback? onError,
     469             :   })  : __onRequest = onRequest,
     470             :         __onResponse = onResponse,
     471             :         __onError = onError;
     472             : 
     473           1 :   @override
     474           1 :   InterceptorErrorCallback? get _onError => __onError;
     475             : 
     476           1 :   @override
     477           1 :   InterceptorSendCallback? get _onRequest => __onRequest;
     478             : 
     479           1 :   @override
     480           1 :   InterceptorSuccessCallback? get _onResponse => __onResponse;
     481             : }

Generated by: LCOV version 1.14