import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:frontend/providers/auth.dart'; import 'package:logging/logging.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:shared_models/jwt.dart'; part 'dio.g.dart'; final logger = Logger('Dio'); @riverpod Dio dio(Ref ref) { final dio = Dio(BaseOptions( baseUrl: 'http://localhost:8080', connectTimeout: const Duration(seconds: 5), receiveTimeout: const Duration(seconds: 3), validateStatus: (status) => true, )); final jwt = ref.watch(jwtNotifierProvider).valueOrNull; final jwtBody = ref.read(jwtBodyProvider); dio.interceptors.addAll([ JwtInterceptor( jwt: jwt, jwtBody: jwtBody, invalidateJwtCallback: () => ref.read(jwtNotifierProvider.notifier).eraseJwt()), CustomLogInterceptor() ]); logger.fine('Created new Dio object'); return dio; } // Adds the jwt to class JwtInterceptor extends Interceptor { final String? jwt; final JWTBody? jwtBody; final Function invalidateJwtCallback; JwtInterceptor({required this.jwt, required this.jwtBody, required this.invalidateJwtCallback}); @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { if (jwt == null || jwtBody == null) { handler.next(options); return; } if (jwtBody != null && jwtBody!.exp < DateTime.now().millisecondsSinceEpoch ~/ 1000) { invalidateJwtCallback(); handler.next(options); return; } if (jwt != null) { options.headers['Authorization'] = 'Bearer $jwt'; handler.next(options); } } // on unauthorized request, remove jwt @override // ignore: strict_raw_type void onResponse(Response response, ResponseInterceptorHandler handler) { if (response.statusCode == 401) { invalidateJwtCallback(); } handler.next(response); } } // Create a custom LogInterceptor using the logger object class CustomLogInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { logger.info('REQUEST[${options.method}] => PATH: ${options.path}'); return super.onRequest(options, handler); } @override // ignore: strict_raw_type void onResponse(Response response, ResponseInterceptorHandler handler) { logger.info( 'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}', ); return super.onResponse(response, handler); } @override void onError(DioException err, ErrorInterceptorHandler handler) { logger.severe( 'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}', ); return super.onError(err, handler); } }