import 'package:sunny_mochi/core/error/exception_mapper.dart' show ExceptionMapper; /// 应用层统一失败模型。 /// /// 所有数据/网络/缓存层的异常通过 [ExceptionMapper] 转换为 [Failure] 子类, /// presentation 层只面对 Failure,避免散落 try-catch DioException / DriftException。 /// /// **实现 [Exception]**:让 datasource/repository 可以直接 `throw failure;` /// 不触发 `only_throw_errors` lint。 /// sealed class Failure implements Exception { const Failure({required this.message, this.cause, this.stackTrace}); final String message; final Object? cause; final StackTrace? stackTrace; /// 子类自我描述前缀(避免直接用 [Object.runtimeType],Release 混淆友好)。 String get _typeName; /// 适合展示给用户的文案(区别于 [message],后者含技术细节,供 Sentry/Talker 日志使用)。 String get userMessage; @override String toString() => '$_typeName: $message'; } /// 网络层失败:超时 / 无网 / DNS 解析失败 / 证书绑定失败 / 连接断开。 class NetworkFailure extends Failure { const NetworkFailure({ required super.message, this.kind = NetworkFailureKind.unknown, super.cause, super.stackTrace, }); final NetworkFailureKind kind; @override String get _typeName => 'NetworkFailure'; @override String get userMessage => message; } enum NetworkFailureKind { timeout, noNetwork, badCertificate, cancelled, unknown, } /// 鉴权失败:未登录 / Token 过期 / refresh 失败 → 应跳登录。 class AuthFailure extends Failure { const AuthFailure({ required super.message, this.kind = AuthFailureKind.unauthorized, super.cause, super.stackTrace, }); final AuthFailureKind kind; @override String get _typeName => 'AuthFailure'; @override String get userMessage => message; } enum AuthFailureKind { unauthorized, // A0401 forbidden, // 403 refreshFailed, cryptoFailed, // 客户端加密失败(如登录密码 RSA 加密前置错) } /// 服务端业务失败:500/501 / 业务校验失败 / 参数错误。 class ServerFailure extends Failure { const ServerFailure({ required super.message, this.code, this.statusCode, super.cause, super.stackTrace, }); final String? code; // 业务错误码(如 A0500 / A0400 / A0404) final int? statusCode; // HTTP 状态码 @override String get _typeName => 'ServerFailure'; @override String get userMessage { // HTTP 5xx:服务端内部错误,后端 message 可能含技术细节(SQL/堆栈),统一遮蔽 if (statusCode != null && statusCode! >= 500) return '服务器开小差了,请稍后再试'; // 业务码 / 4xx:message 已经过 ResponseCode.friendlyMessage 映射,安全展示 return message; } } /// 本地缓存/数据库失败:Drift 异常 / SQLCipher 解密失败 / 文件 IO 错误。 class CacheFailure extends Failure { const CacheFailure({ required super.message, super.cause, super.stackTrace, }); @override String get _typeName => 'CacheFailure'; @override String get userMessage => '本地数据异常,请重启应用试试'; } /// 兜底未知错误。 class UnknownFailure extends Failure { const UnknownFailure({ required super.message, super.cause, super.stackTrace, }); @override String get _typeName => 'UnknownFailure'; @override String get userMessage => '遇到了点问题,已自动上报'; }