You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

250 lines
8.7KB

  1. import 'dart:developer';
  2. import 'dart:io';
  3. import 'dart:convert';
  4. import 'package:dio/adapter.dart';
  5. import 'package:dio/dio.dart';
  6. import 'package:dio/native_imp.dart';
  7. import 'package:flutter_bloc/flutter_bloc.dart';
  8. import 'package:get/get.dart' as getx;
  9. import '../../app.dart';
  10. import '../../authentication/bloc/authentication_bloc.dart';
  11. import '../../environment/app_config.dart';
  12. import '../../presentation/screens/login/login_page.dart';
  13. import '../../utils/const_enum.dart';
  14. import '../../utils/local_storage.dart';
  15. class DioProvider extends DioForNative {
  16. factory DioProvider({
  17. String? baseUrl,
  18. String contentType = Headers.jsonContentType,
  19. int timeout = 60000,
  20. }) {
  21. _instance ??= DioProvider._(baseUrl: baseUrl, contentType: contentType, timeout: timeout);
  22. return _instance!;
  23. }
  24. DioProvider._({
  25. String? baseUrl,
  26. String contentType = Headers.jsonContentType,
  27. int timeout = 60000,
  28. }) : super(BaseOptions(
  29. baseUrl: baseUrl ?? FlavorConfig.values.baseUrl,
  30. contentType: contentType,
  31. sendTimeout: timeout,
  32. connectTimeout: timeout,
  33. receiveTimeout: timeout,
  34. )) {
  35. (httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
  36. client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
  37. return client;
  38. };
  39. interceptors
  40. ..add(AuthorizationInterceptor())
  41. ..add(HttpLogInterceptor())
  42. ..add(LogoutInterceptor())
  43. ..add(UnauthorizedInterceptor());
  44. }
  45. static DioProvider? _instance;
  46. }
  47. class AuthorizationInterceptor extends InterceptorsWrapper {
  48. @override
  49. Future<void> onRequest(
  50. RequestOptions options,
  51. RequestInterceptorHandler handler,
  52. ) async {
  53. final String? token = await LocalStorage.getString(LocalStorageKey.access_token);
  54. if (token != null && !options.path.contains('authenticate')) {
  55. options.headers.putIfAbsent('Authorization', () => 'Bearer $token');
  56. }
  57. return handler.next(options);
  58. }
  59. }
  60. class HttpLogInterceptor extends InterceptorsWrapper {
  61. @override
  62. Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
  63. log('⭐⭐⭐⭐⭐⭐ onRequest: ${options.uri}\n'
  64. 'data=${options.data is Map ? json.encode(options.data) : options.data}\n'
  65. 'method=${options.method}\n'
  66. 'headers=${options.headers}\n'
  67. 'queryParameters=${options.queryParameters}');
  68. return handler.next(options);
  69. }
  70. @override
  71. void onResponse(Response<dynamic> response, ResponseInterceptorHandler handler) {
  72. // log('🍏🍏🍏🍏🍏🍏 onResponse: ${response.requestOptions.uri}\n'
  73. // 'statusCode=${response.statusCode}\n'
  74. // 'data=${response.data is Map ? json.encode(response.data) : response.data}');
  75. return handler.next(response);
  76. }
  77. @override
  78. void onError(DioError err, ErrorInterceptorHandler handler) {
  79. log('🔥🔥🔥🔥🔥🔥 onError: ${err.response?.requestOptions.uri}\n'
  80. 'errorStatusCode=${err.response?.statusCode}\n'
  81. 'errorResponseHeaders=${err.response?.headers}\n'
  82. 'errorMessage=${err.message}\n'
  83. 'errorData=${err.response?.data}');
  84. return handler.next(err);
  85. }
  86. }
  87. class LogoutInterceptor extends InterceptorsWrapper {
  88. @override
  89. Future<void> onRequest(
  90. RequestOptions options,
  91. RequestInterceptorHandler handler,
  92. ) async {
  93. final headers = options.headers;
  94. final String? token = await LocalStorage.getString(LocalStorageKey.access_token);
  95. if (token == null && headers.containsKey('Authorization')) {
  96. headers.remove('Authorization');
  97. }
  98. return handler.next(options);
  99. }
  100. }
  101. class UnauthorizedInterceptor extends InterceptorsWrapper {
  102. @override
  103. Future<void> onError(
  104. DioError err,
  105. ErrorInterceptorHandler handler,
  106. ) async {
  107. final checkUnauthorized =
  108. err.type == DioErrorType.response && err.response?.statusCode == HttpStatus.unauthorized && !err.requestOptions.path.contains('authenticate');
  109. if (checkUnauthorized) {
  110. LocalStorage.clearUserInfo();
  111. getx.Get.offAll(() => const LoginPage());
  112. BlocProvider.of<AuthenticationBloc>(globalNavigator.currentContext!).add(
  113. const AuthenticationStatusChanged(AuthenticationStatus.unauthenticated),
  114. );
  115. }
  116. return handler.next(err);
  117. }
  118. }
  119. // class DioProvider {
  120. // static Dio dio = Dio();
  121. // static FlavorValues flavorValues = FlavorConfig.values;
  122. // static Dio instance() {
  123. // dio.options.baseUrl = flavorValues.baseUrl;
  124. // (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
  125. // (HttpClient client) {
  126. // client.badCertificateCallback =
  127. // (X509Certificate cert, String host, int port) => true;
  128. // return client;
  129. // };
  130. // dio.interceptors.add(
  131. // InterceptorsWrapper(
  132. // onRequest: (options, handler) {
  133. // var token = LocalStorage.getString(LocalStorageKey.access_token);
  134. // var refreshTokenUrl =
  135. // FlavorConfig.values.baseUrl + EndpointUrl.refreshToken;
  136. // if (token.isNotEmpty && (options.path != refreshTokenUrl)) {
  137. // options.headers['Authorization'] = 'Bearer $token';
  138. // }
  139. // options.headers['Content-Type'] = 'application/json';
  140. // options.headers['accept'] = 'application/json';
  141. // options.connectTimeout = 60000;
  142. // options.receiveTimeout = 60000;
  143. // log('⭐⭐⭐⭐⭐⭐ onRequest: ${options.uri}\n'
  144. // 'data=${options.data}\n'
  145. // 'method=${options.method}\n'
  146. // // 'headers=${options.headers}\n'
  147. // 'queryParameters=${options.queryParameters}');
  148. // return handler.next(options);
  149. // },
  150. // onResponse: (response, handler) async {
  151. // // log('🍏🍏🍏🍏🍏🍏 onResponse: $response');
  152. // return handler.next(response);
  153. // },
  154. // onError: (DioError e, handler) async {
  155. // log('🔥🔥🔥🔥🔥🔥 onError: $e\n'
  156. // 'Response: ${e.response}');
  157. // if (e.response != null) {
  158. // await refreshToken(e, handler);
  159. // } else {
  160. // handler.next(e);
  161. // }
  162. // },
  163. // ),
  164. // );
  165. // return dio;
  166. // }
  167. // static void logoutAndNavigationToSplashScreen() {
  168. // LocalStorage.clearUserInfo();
  169. // BlocProvider.of<AuthenticationBloc>(globalNavigator.currentContext!).add(
  170. // const AuthenticationStatusChanged(
  171. // AuthenticationStatus.unauthenticated,
  172. // ),
  173. // );
  174. // }
  175. // static Future<void> refreshToken(
  176. // DioError e, ErrorInterceptorHandler handler) async {
  177. // try {
  178. // var isCancelPreviousRequest = false;
  179. // var isRefreshSuccess = false;
  180. // if (e.response?.statusCode == 401) {
  181. // try {
  182. // var url = FlavorConfig.values.baseUrl + EndpointUrl.login;
  183. // var refreshToken =
  184. // LocalStorage.getString(LocalStorageKey.refresh_token);
  185. // var username = LocalStorage.getString(LocalStorageKey.username);
  186. // var res = await dio.post(url, data: {
  187. // 'token': refreshToken,
  188. // 'username': username,
  189. // });
  190. // if (res.statusCode == 200) {
  191. // var data = ResponseUser.fromJson(res.data);
  192. // LocalStorage.saveUserInfo(data, username);
  193. // isRefreshSuccess = true;
  194. // } else {
  195. // logoutAndNavigationToSplashScreen();
  196. // }
  197. // } catch (e) {
  198. // logoutAndNavigationToSplashScreen();
  199. // }
  200. // } else {
  201. // handler.next(e);
  202. // }
  203. // if (isRefreshSuccess) {
  204. // var token = LocalStorage.getString(LocalStorageKey.access_token);
  205. // e.requestOptions.headers['Authorization'] = 'Bearer $token';
  206. // e.requestOptions.headers['Content-Type'] = 'application/json';
  207. // e.requestOptions.headers['accept'] = 'application/json';
  208. // e.requestOptions.connectTimeout = 60000;
  209. // e.requestOptions.receiveTimeout = 60000;
  210. // final opts = Options(
  211. // method: e.requestOptions.method,
  212. // headers: e.requestOptions.headers,
  213. // );
  214. // try {
  215. // final cloneReq = await dio.request(
  216. // e.requestOptions.path,
  217. // options: opts,
  218. // data: e.requestOptions.data,
  219. // queryParameters: e.requestOptions.queryParameters,
  220. // );
  221. // return handler.resolve(cloneReq);
  222. // } catch (ex) {
  223. // print(ex);
  224. // if (!isCancelPreviousRequest) {
  225. // isCancelPreviousRequest = true;
  226. // handler.next(e);
  227. // }
  228. // }
  229. // }
  230. // } catch (e) {
  231. // print(e);
  232. // }
  233. // }
  234. // }