479 lines
11 KiB
Dart
479 lines
11 KiB
Dart
import 'dart:io';
|
||
|
||
import 'package:swagger_generator_flutter/utils/logger.dart';
|
||
|
||
String _formatExceptionDetails(
|
||
String header,
|
||
Map<String, Object?> fields,
|
||
) {
|
||
final buffer = StringBuffer()..writeln(header);
|
||
fields.forEach((label, value) {
|
||
if (value != null) {
|
||
buffer.writeln('$label: $value');
|
||
}
|
||
});
|
||
return buffer.toString().trim();
|
||
}
|
||
|
||
/// Swagger CLI 基础异常类
|
||
abstract class SwaggerException implements Exception {
|
||
SwaggerException(this.message, {this.details}) : timestamp = DateTime.now();
|
||
final String message;
|
||
final String? details;
|
||
final DateTime timestamp;
|
||
|
||
@override
|
||
String toString() {
|
||
if (details != null) {
|
||
return '$runtimeType: $message\n详细信息: $details';
|
||
}
|
||
return '$runtimeType: $message';
|
||
}
|
||
}
|
||
|
||
/// Swagger解析异常
|
||
class SwaggerParseException extends SwaggerException {
|
||
SwaggerParseException(
|
||
super.message, {
|
||
super.details,
|
||
this.url,
|
||
this.statusCode,
|
||
this.operation,
|
||
});
|
||
final String? url;
|
||
final int? statusCode;
|
||
final String? operation;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'SwaggerParseException: $message',
|
||
{
|
||
'URL': url,
|
||
'状态码': statusCode,
|
||
'操作': operation,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 代码生成异常
|
||
class CodeGenerationException extends SwaggerException {
|
||
CodeGenerationException(
|
||
super.message, {
|
||
super.details,
|
||
this.generatorType,
|
||
this.modelName,
|
||
this.phase,
|
||
});
|
||
final String? generatorType;
|
||
final String? modelName;
|
||
final String? phase;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'CodeGenerationException: $message',
|
||
{
|
||
'生成器类型': generatorType,
|
||
'模型名称': modelName,
|
||
'生成阶段': phase,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 文件操作异常
|
||
class FileOperationException extends SwaggerException {
|
||
FileOperationException(
|
||
super.message, {
|
||
super.details,
|
||
this.filePath,
|
||
this.operation,
|
||
this.errorCode,
|
||
});
|
||
final String? filePath;
|
||
final String? operation;
|
||
final int? errorCode;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'FileOperationException: $message',
|
||
{
|
||
'文件路径': filePath,
|
||
'操作': operation,
|
||
'错误代码': errorCode,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 命令异常
|
||
class CommandException extends SwaggerException {
|
||
CommandException(
|
||
super.message, {
|
||
super.details,
|
||
this.commandName,
|
||
this.arguments,
|
||
this.exitCode,
|
||
});
|
||
final String? commandName;
|
||
final List<String>? arguments;
|
||
final int? exitCode;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'CommandException: $message',
|
||
{
|
||
'命令': commandName,
|
||
'参数': arguments?.join(' '),
|
||
'退出代码': exitCode,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 验证异常
|
||
class ValidationException extends SwaggerException {
|
||
ValidationException(
|
||
super.message, {
|
||
super.details,
|
||
this.field,
|
||
this.value,
|
||
this.rule,
|
||
});
|
||
final String? field;
|
||
final dynamic value;
|
||
final String? rule;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'ValidationException: $message',
|
||
{
|
||
'字段': field,
|
||
'值': value,
|
||
'验证规则': rule,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 配置异常
|
||
class ConfigurationException extends SwaggerException {
|
||
ConfigurationException(
|
||
super.message, {
|
||
super.details,
|
||
this.configKey,
|
||
this.configValue,
|
||
this.source,
|
||
});
|
||
final String? configKey;
|
||
final dynamic configValue;
|
||
final String? source;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'ConfigurationException: $message',
|
||
{
|
||
'配置键': configKey,
|
||
'配置值': configValue,
|
||
'来源': source,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 网络异常
|
||
class NetworkException extends SwaggerException {
|
||
NetworkException(
|
||
super.message, {
|
||
super.details,
|
||
this.url,
|
||
this.statusCode,
|
||
this.method,
|
||
this.timeout,
|
||
});
|
||
final String? url;
|
||
final int? statusCode;
|
||
final String? method;
|
||
final Duration? timeout;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'NetworkException: $message',
|
||
{
|
||
'URL': url,
|
||
'方法': method,
|
||
'状态码': statusCode,
|
||
'超时': timeout != null ? '${timeout!.inSeconds}秒' : null,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 缓存异常
|
||
class CacheException extends SwaggerException {
|
||
CacheException(
|
||
super.message, {
|
||
super.details,
|
||
this.cacheKey,
|
||
this.operation,
|
||
this.cacheType,
|
||
});
|
||
final String? cacheKey;
|
||
final String? operation;
|
||
final String? cacheType;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'CacheException: $message',
|
||
{
|
||
'缓存键': cacheKey,
|
||
'操作': operation,
|
||
'缓存类型': cacheType,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 性能异常
|
||
class PerformanceException extends SwaggerException {
|
||
PerformanceException(
|
||
super.message, {
|
||
super.details,
|
||
this.operation,
|
||
this.duration,
|
||
this.threshold,
|
||
});
|
||
final String? operation;
|
||
final Duration? duration;
|
||
final Duration? threshold;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'PerformanceException: $message',
|
||
{
|
||
'操作': operation,
|
||
'耗时': duration != null ? '${duration!.inMilliseconds}ms' : null,
|
||
'阈值': threshold != null ? '${threshold!.inMilliseconds}ms' : null,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 类型异常
|
||
class TypeException extends SwaggerException {
|
||
TypeException(
|
||
super.message, {
|
||
super.details,
|
||
this.propertyName,
|
||
this.expectedType,
|
||
this.actualType,
|
||
this.value,
|
||
});
|
||
final String? propertyName;
|
||
final String? expectedType;
|
||
final String? actualType;
|
||
final dynamic value;
|
||
|
||
@override
|
||
String toString() => _formatExceptionDetails(
|
||
'TypeException: $message',
|
||
{
|
||
'属性名': propertyName,
|
||
'期望类型': expectedType,
|
||
'实际类型': actualType,
|
||
'值': value,
|
||
'详细信息': details,
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 异常处理器
|
||
class ExceptionHandler {
|
||
static final Map<Type, void Function(SwaggerException)> _handlers = {};
|
||
|
||
/// 注册异常处理器
|
||
static void register<T extends SwaggerException>(
|
||
void Function(T exception) handler,
|
||
) {
|
||
_handlers[T] = (exception) => handler(exception as T);
|
||
}
|
||
|
||
/// 处理异常
|
||
static void handle(SwaggerException exception) {
|
||
final handler = _handlers[exception.runtimeType];
|
||
if (handler != null) {
|
||
handler(exception);
|
||
} else {
|
||
// 默认处理
|
||
_defaultHandler(exception);
|
||
}
|
||
}
|
||
|
||
/// 默认异常处理
|
||
static void _defaultHandler(SwaggerException exception) {
|
||
appLogger.severe(
|
||
'🚨 异常: $exception',
|
||
exception,
|
||
StackTrace.current,
|
||
);
|
||
}
|
||
|
||
/// 记录异常到文件
|
||
static Future<void> logException(
|
||
SwaggerException exception, {
|
||
String? logFilePath,
|
||
}) async {
|
||
try {
|
||
final logFile = logFilePath != null
|
||
? File(logFilePath)
|
||
: File('swagger_cli_errors.log');
|
||
|
||
final logEntry = [
|
||
'[${'=' * 50}]',
|
||
'时间: ${exception.timestamp.toIso8601String()}',
|
||
'类型: ${exception.runtimeType}',
|
||
'消息: ${exception.message}',
|
||
if (exception.details != null) '详细信息: ${exception.details}',
|
||
'堆栈跟踪: ${StackTrace.current}',
|
||
'',
|
||
].join('\n');
|
||
|
||
await logFile.writeAsString(logEntry, mode: FileMode.append);
|
||
} on Exception catch (e, stackTrace) {
|
||
appLogger.severe('记录异常到文件失败', e, stackTrace);
|
||
}
|
||
}
|
||
|
||
/// 清理异常处理器
|
||
static void clear() {
|
||
_handlers.clear();
|
||
}
|
||
}
|
||
|
||
/// 异常工厂
|
||
class ExceptionFactory {
|
||
/// 创建解析异常
|
||
static SwaggerParseException createParseException(
|
||
String message, {
|
||
String? url,
|
||
int? statusCode,
|
||
String? operation,
|
||
dynamic cause,
|
||
}) {
|
||
return SwaggerParseException(
|
||
message,
|
||
details: cause?.toString(),
|
||
url: url,
|
||
statusCode: statusCode,
|
||
operation: operation,
|
||
);
|
||
}
|
||
|
||
/// 创建代码生成异常
|
||
static CodeGenerationException createCodeGenerationException(
|
||
String message, {
|
||
String? generatorType,
|
||
String? modelName,
|
||
String? phase,
|
||
dynamic cause,
|
||
}) {
|
||
return CodeGenerationException(
|
||
message,
|
||
details: cause?.toString(),
|
||
generatorType: generatorType,
|
||
modelName: modelName,
|
||
phase: phase,
|
||
);
|
||
}
|
||
|
||
/// 创建文件操作异常
|
||
static FileOperationException createFileOperationException(
|
||
String message, {
|
||
String? filePath,
|
||
String? operation,
|
||
int? errorCode,
|
||
dynamic cause,
|
||
}) {
|
||
return FileOperationException(
|
||
message,
|
||
details: cause?.toString(),
|
||
filePath: filePath,
|
||
operation: operation,
|
||
errorCode: errorCode,
|
||
);
|
||
}
|
||
|
||
/// 创建验证异常
|
||
static ValidationException createValidationException(
|
||
String message, {
|
||
String? field,
|
||
dynamic value,
|
||
String? rule,
|
||
dynamic cause,
|
||
}) {
|
||
return ValidationException(
|
||
message,
|
||
details: cause?.toString(),
|
||
field: field,
|
||
value: value,
|
||
rule: rule,
|
||
);
|
||
}
|
||
|
||
/// 创建网络异常
|
||
static NetworkException createNetworkException(
|
||
String message, {
|
||
String? url,
|
||
int? statusCode,
|
||
String? method,
|
||
Duration? timeout,
|
||
dynamic cause,
|
||
}) {
|
||
return NetworkException(
|
||
message,
|
||
details: cause?.toString(),
|
||
url: url,
|
||
statusCode: statusCode,
|
||
method: method,
|
||
timeout: timeout,
|
||
);
|
||
}
|
||
|
||
/// 从标准异常创建
|
||
static SwaggerException fromStandardException(
|
||
Exception exception, {
|
||
String? context,
|
||
}) {
|
||
if (exception is FileSystemException) {
|
||
return FileOperationException(
|
||
'文件系统错误',
|
||
details: exception.message,
|
||
filePath: exception.path,
|
||
operation: context,
|
||
);
|
||
} else if (exception is SocketException) {
|
||
return NetworkException(
|
||
'网络连接错误',
|
||
details: exception.message,
|
||
url: context,
|
||
);
|
||
} else if (exception is FormatException) {
|
||
return SwaggerParseException(
|
||
'格式错误',
|
||
details: exception.message,
|
||
operation: context,
|
||
);
|
||
} else {
|
||
return GeneralSwaggerException(
|
||
'未知错误',
|
||
details: exception.toString(),
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 通用Swagger异常(当无法确定具体类型时使用)
|
||
class GeneralSwaggerException extends SwaggerException {
|
||
GeneralSwaggerException(super.message, {super.details});
|
||
}
|