This commit is contained in:
Phuoc Nguyen
2025-10-17 17:22:28 +07:00
parent 2125e85d40
commit 628c81ce13
86 changed files with 31339 additions and 1710 deletions

View File

@@ -0,0 +1,351 @@
/// Custom exceptions for the Worker app
///
/// This file defines all custom exception types used throughout the application
/// for better error handling and user feedback.
library;
// ============================================================================
// Network Exceptions
// ============================================================================
/// Base exception for all network-related errors
class NetworkException implements Exception {
const NetworkException(
this.message, {
this.statusCode,
this.data,
});
final String message;
final int? statusCode;
final dynamic data;
@override
String toString() => 'NetworkException: $message${statusCode != null ? ' (Status: $statusCode)' : ''}';
}
/// Exception thrown when there's no internet connection
class NoInternetException extends NetworkException {
const NoInternetException()
: super(
'Không có kết nối internet. Vui lòng kiểm tra kết nối của bạn.',
);
}
/// Exception thrown when connection times out
class TimeoutException extends NetworkException {
const TimeoutException()
: super(
'Kết nối quá lâu. Vui lòng thử lại.',
statusCode: 408,
);
}
/// Exception thrown when server returns 500+ errors
class ServerException extends NetworkException {
const ServerException([
String message = 'Lỗi máy chủ. Vui lòng thử lại sau.',
int? statusCode,
]) : super(message, statusCode: statusCode);
}
/// Exception thrown when server is unreachable
class ServiceUnavailableException extends ServerException {
const ServiceUnavailableException()
: super(
'Dịch vụ tạm thời không khả dụng. Vui lòng thử lại sau.',
503,
);
}
// ============================================================================
// Authentication Exceptions
// ============================================================================
/// Base exception for authentication-related errors
class AuthException implements Exception {
const AuthException(
this.message, {
this.statusCode,
});
final String message;
final int? statusCode;
@override
String toString() => 'AuthException: $message';
}
/// Exception thrown when authentication credentials are invalid
class InvalidCredentialsException extends AuthException {
const InvalidCredentialsException()
: super(
'Thông tin đăng nhập không hợp lệ.',
statusCode: 401,
);
}
/// Exception thrown when user is not authenticated
class UnauthorizedException extends AuthException {
const UnauthorizedException([
super.message = 'Phiên đăng nhập hết hạn. Vui lòng đăng nhập lại.',
]) : super(statusCode: 401);
}
/// Exception thrown when user doesn't have permission
class ForbiddenException extends AuthException {
const ForbiddenException()
: super(
'Bạn không có quyền truy cập tài nguyên này.',
statusCode: 403,
);
}
/// Exception thrown when auth token is expired
class TokenExpiredException extends AuthException {
const TokenExpiredException()
: super(
'Phiên đăng nhập hết hạn. Vui lòng đăng nhập lại.',
statusCode: 401,
);
}
/// Exception thrown when refresh token is invalid
class InvalidRefreshTokenException extends AuthException {
const InvalidRefreshTokenException()
: super(
'Không thể làm mới phiên đăng nhập. Vui lòng đăng nhập lại.',
statusCode: 401,
);
}
/// Exception thrown when OTP is invalid
class InvalidOTPException extends AuthException {
const InvalidOTPException()
: super(
'Mã OTP không hợp lệ. Vui lòng thử lại.',
statusCode: 400,
);
}
/// Exception thrown when OTP is expired
class OTPExpiredException extends AuthException {
const OTPExpiredException()
: super(
'Mã OTP đã hết hạn. Vui lòng yêu cầu mã mới.',
statusCode: 400,
);
}
// ============================================================================
// Request Validation Exceptions
// ============================================================================
/// Exception thrown when request data is invalid
class ValidationException implements Exception {
const ValidationException(
this.message, {
this.errors,
});
final String message;
final Map<String, List<String>>? errors;
@override
String toString() {
if (errors != null && errors!.isNotEmpty) {
final errorMessages = errors!.entries
.map((e) => '${e.key}: ${e.value.join(", ")}')
.join('; ');
return 'ValidationException: $message - $errorMessages';
}
return 'ValidationException: $message';
}
}
/// Exception thrown when request parameters are invalid
class BadRequestException extends ValidationException {
const BadRequestException([
String message = 'Yêu cầu không hợp lệ.',
Map<String, List<String>>? errors,
]) : super(message, errors: errors);
}
// ============================================================================
// Resource Exceptions
// ============================================================================
/// Exception thrown when requested resource is not found
class NotFoundException implements Exception {
const NotFoundException([
this.message = 'Không tìm thấy tài nguyên.',
this.resourceType,
this.resourceId,
]);
final String message;
final String? resourceType;
final String? resourceId;
@override
String toString() {
if (resourceType != null && resourceId != null) {
return 'NotFoundException: $resourceType with ID $resourceId not found';
}
return 'NotFoundException: $message';
}
}
/// Exception thrown when trying to create a duplicate resource
class ConflictException implements Exception {
const ConflictException([
this.message = 'Tài nguyên đã tồn tại.',
]);
final String message;
@override
String toString() => 'ConflictException: $message';
}
// ============================================================================
// Rate Limiting Exceptions
// ============================================================================
/// Exception thrown when API rate limit is exceeded
class RateLimitException implements Exception {
const RateLimitException([
this.message = 'Bạn đã gửi quá nhiều yêu cầu. Vui lòng thử lại sau.',
this.retryAfter,
]);
final String message;
final int? retryAfter; // seconds
@override
String toString() {
if (retryAfter != null) {
return 'RateLimitException: $message (Retry after: ${retryAfter}s)';
}
return 'RateLimitException: $message';
}
}
// ============================================================================
// Payment Exceptions
// ============================================================================
/// Exception thrown for payment-related errors
class PaymentException implements Exception {
const PaymentException(
this.message, {
this.transactionId,
});
final String message;
final String? transactionId;
@override
String toString() => 'PaymentException: $message';
}
/// Exception thrown when payment fails
class PaymentFailedException extends PaymentException {
const PaymentFailedException([
String message = 'Thanh toán thất bại. Vui lòng thử lại.',
String? transactionId,
]) : super(message, transactionId: transactionId);
}
/// Exception thrown when payment is cancelled
class PaymentCancelledException extends PaymentException {
const PaymentCancelledException()
: super('Thanh toán đã bị hủy.');
}
// ============================================================================
// Cache Exceptions
// ============================================================================
/// Exception thrown for cache-related errors
class CacheException implements Exception {
const CacheException([
this.message = 'Lỗi khi truy cập bộ nhớ đệm.',
]);
final String message;
@override
String toString() => 'CacheException: $message';
}
/// Exception thrown when cache data is corrupted
class CacheCorruptedException extends CacheException {
const CacheCorruptedException()
: super('Dữ liệu bộ nhớ đệm bị hỏng.');
}
// ============================================================================
// Storage Exceptions
// ============================================================================
/// Exception thrown for local storage errors
class StorageException implements Exception {
const StorageException([
this.message = 'Lỗi khi truy cập bộ nhớ cục bộ.',
]);
final String message;
@override
String toString() => 'StorageException: $message';
}
/// Exception thrown when storage is full
class StorageFullException extends StorageException {
const StorageFullException()
: super('Bộ nhớ đã đầy. Vui lòng giải phóng không gian.');
}
// ============================================================================
// Parse Exceptions
// ============================================================================
/// Exception thrown when JSON parsing fails
class ParseException implements Exception {
const ParseException([
this.message = 'Lỗi khi phân tích dữ liệu.',
this.source,
]);
final String message;
final dynamic source;
@override
String toString() => 'ParseException: $message';
}
// ============================================================================
// Unknown Exceptions
// ============================================================================
/// Exception thrown for unexpected errors
class UnknownException implements Exception {
const UnknownException([
this.message = 'Đã xảy ra lỗi không xác định.',
this.originalError,
this.stackTrace,
]);
final String message;
final dynamic originalError;
final StackTrace? stackTrace;
@override
String toString() {
if (originalError != null) {
return 'UnknownException: $message (Original: $originalError)';
}
return 'UnknownException: $message';
}
}

View File

@@ -0,0 +1,262 @@
/// Failure classes for error handling in the Worker app
///
/// Failures represent domain-level errors that can be returned from use cases
/// and repositories. They wrap exceptions and provide user-friendly error messages.
library;
/// Base failure class
sealed class Failure {
const Failure({required this.message});
/// Network-related failure
const factory Failure.network({
required String message,
int? statusCode,
}) = NetworkFailure;
/// Server error failure (5xx errors)
const factory Failure.server({
required String message,
int? statusCode,
}) = ServerFailure;
/// Authentication failure
const factory Failure.authentication({
required String message,
int? statusCode,
}) = AuthenticationFailure;
/// Validation failure
const factory Failure.validation({
required String message,
Map<String, List<String>>? errors,
}) = ValidationFailure;
/// Not found failure (404)
const factory Failure.notFound({
required String message,
}) = NotFoundFailure;
/// Conflict failure (409)
const factory Failure.conflict({
required String message,
}) = ConflictFailure;
/// Rate limit exceeded failure (429)
const factory Failure.rateLimit({
required String message,
int? retryAfter,
}) = RateLimitFailure;
/// Payment failure
const factory Failure.payment({
required String message,
String? transactionId,
}) = PaymentFailure;
/// Cache failure
const factory Failure.cache({
required String message,
}) = CacheFailure;
/// Storage failure
const factory Failure.storage({
required String message,
}) = StorageFailure;
/// Parse failure
const factory Failure.parse({
required String message,
}) = ParseFailure;
/// No internet connection failure
const factory Failure.noInternet() = NoInternetFailure;
/// Timeout failure
const factory Failure.timeout() = TimeoutFailure;
/// Unknown failure
const factory Failure.unknown({
required String message,
}) = UnknownFailure;
final String message;
/// Check if this is a critical failure that requires immediate attention
bool get isCritical {
return switch (this) {
ServerFailure() => true,
AuthenticationFailure() => true,
PaymentFailure() => true,
UnknownFailure() => true,
_ => false,
};
}
/// Check if this failure can be retried
bool get canRetry {
return switch (this) {
NetworkFailure() => true,
ServerFailure(:final statusCode) => statusCode == 503,
AuthenticationFailure(:final statusCode) => statusCode == 401,
RateLimitFailure() => true,
CacheFailure() => true,
NoInternetFailure() => true,
TimeoutFailure() => true,
_ => false,
};
}
/// Get HTTP status code if available
int? get statusCode {
return switch (this) {
NetworkFailure(:final statusCode) => statusCode,
ServerFailure(:final statusCode) => statusCode,
AuthenticationFailure(:final statusCode) => statusCode,
_ => null,
};
}
/// Get user-friendly error message
String getUserMessage() {
return switch (this) {
ValidationFailure(:final message, :final errors) => _formatValidationMessage(message, errors),
RateLimitFailure(:final message, :final retryAfter) => _formatRateLimitMessage(message, retryAfter),
NoInternetFailure() => 'Không có kết nối internet. Vui lòng kiểm tra kết nối của bạn.',
TimeoutFailure() => 'Kết nối quá lâu. Vui lòng thử lại.',
_ => message,
};
}
String _formatValidationMessage(String message, Map<String, List<String>>? errors) {
if (errors != null && errors.isNotEmpty) {
final firstError = errors.values.first.first;
return '$message: $firstError';
}
return message;
}
String _formatRateLimitMessage(String message, int? retryAfter) {
if (retryAfter != null) {
return '$message Thử lại sau $retryAfter giây.';
}
return message;
}
}
/// Network-related failure
final class NetworkFailure extends Failure {
const NetworkFailure({
required super.message,
this.statusCode,
});
@override
final int? statusCode;
}
/// Server error failure (5xx errors)
final class ServerFailure extends Failure {
const ServerFailure({
required super.message,
this.statusCode,
});
@override
final int? statusCode;
}
/// Authentication failure
final class AuthenticationFailure extends Failure {
const AuthenticationFailure({
required super.message,
this.statusCode,
});
@override
final int? statusCode;
}
/// Validation failure
final class ValidationFailure extends Failure {
const ValidationFailure({
required super.message,
this.errors,
});
final Map<String, List<String>>? errors;
}
/// Not found failure (404)
final class NotFoundFailure extends Failure {
const NotFoundFailure({
required super.message,
});
}
/// Conflict failure (409)
final class ConflictFailure extends Failure {
const ConflictFailure({
required super.message,
});
}
/// Rate limit exceeded failure (429)
final class RateLimitFailure extends Failure {
const RateLimitFailure({
required super.message,
this.retryAfter,
});
final int? retryAfter;
}
/// Payment failure
final class PaymentFailure extends Failure {
const PaymentFailure({
required super.message,
this.transactionId,
});
final String? transactionId;
}
/// Cache failure
final class CacheFailure extends Failure {
const CacheFailure({
required super.message,
});
}
/// Storage failure
final class StorageFailure extends Failure {
const StorageFailure({
required super.message,
});
}
/// Parse failure
final class ParseFailure extends Failure {
const ParseFailure({
required super.message,
});
}
/// No internet connection failure
final class NoInternetFailure extends Failure {
const NoInternetFailure()
: super(message: 'Không có kết nối internet');
}
/// Timeout failure
final class TimeoutFailure extends Failure {
const TimeoutFailure()
: super(message: 'Kết nối quá lâu');
}
/// Unknown failure
final class UnknownFailure extends Failure {
const UnknownFailure({
required super.message,
});
}