feat: Implement DataErrorHandler mixin and update imports for consistency

This commit is contained in:
Achintha Isuru
2026-02-17 13:21:00 -05:00
parent 9e1af17328
commit 506da5e26f
4 changed files with 3 additions and 3 deletions

View File

@@ -6,7 +6,7 @@ import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../krow_data_connect.dart' as dc;
import '../mixins/data_error_handler.dart';
import 'mixins/data_error_handler.dart';
/// A centralized service for interacting with Firebase Data Connect.
///

View File

@@ -0,0 +1,71 @@
import 'dart:async';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:krow_domain/krow_domain.dart';
/// Mixin to handle Data Layer errors and map them to Domain Failures.
///
/// Use this in Repositories to wrap remote calls.
/// It catches [SocketException], [FirebaseException], etc., and throws [AppException].
mixin DataErrorHandler {
/// Executes a Future and maps low-level exceptions to [AppException].
///
/// [timeout] defaults to 30 seconds.
Future<T> executeProtected<T>(
Future<T> Function() action, {
Duration timeout = const Duration(seconds: 30),
}) async {
try {
return await action().timeout(timeout);
} on TimeoutException {
throw ServiceUnavailableException(
technicalMessage: 'Request timed out after ${timeout.inSeconds}s');
} on SocketException catch (e) {
throw NetworkException(technicalMessage: 'SocketException: ${e.message}');
} on FirebaseException catch (e) {
final String code = e.code.toLowerCase();
final String msg = (e.message ?? '').toLowerCase();
if (code == 'unavailable' ||
code == 'network-request-failed' ||
msg.contains('offline') ||
msg.contains('network') ||
msg.contains('connection failed')) {
throw NetworkException(
technicalMessage: 'Firebase ${e.code}: ${e.message}');
}
if (code == 'deadline-exceeded') {
throw ServiceUnavailableException(
technicalMessage: 'Firebase ${e.code}: ${e.message}');
}
// Fallback for other Firebase errors
throw ServerException(
technicalMessage: 'Firebase ${e.code}: ${e.message}');
} catch (e) {
final String errorStr = e.toString().toLowerCase();
if (errorStr.contains('socketexception') ||
errorStr.contains('network') ||
errorStr.contains('offline') ||
errorStr.contains('connection failed') ||
errorStr.contains('unavailable') ||
errorStr.contains('handshake') ||
errorStr.contains('clientexception') ||
errorStr.contains('failed host lookup') ||
errorStr.contains('connection error') ||
errorStr.contains('grpc error') ||
errorStr.contains('terminated') ||
errorStr.contains('connectexception')) {
throw NetworkException(technicalMessage: e.toString());
}
// If it's already an AppException, rethrow it
if (e is AppException) rethrow;
// Debugging: Log unexpected errors
debugPrint('DataErrorHandler: Unhandled exception caught: $e');
throw UnknownException(technicalMessage: e.toString());
}
}
}