import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import '../core/config.dart'; import '../core/exceptions.dart'; import '../core/models.dart'; import '../utils/cache_manager.dart'; import '../utils/performance_monitor.dart'; import '../utils/string_utils.dart'; import '../utils/type_validator.dart'; /// Swagger数据解析器 /// 负责解析Swagger JSON文档并提取相关信息 class SwaggerDataParser { final CacheManager _cacheManager; final PerformanceMonitor _performanceMonitor; final TypeValidator _typeValidator; // 缓存解析结果 SwaggerDocument? _cachedDocument; SwaggerDataParser() : _cacheManager = CacheManager(), _performanceMonitor = PerformanceMonitor(), _typeValidator = TypeValidator(); /// 获取并解析Swagger JSON文档 Future fetchAndParseSwaggerDocument() async { // 如果有缓存且未过期,直接返回缓存结果 if (_cachedDocument != null) { return _cachedDocument!; } return _performanceMonitor.measure( 'fetchAndParseSwaggerDocument', () async { try { print('🔄 正在获取Swagger JSON文档...'); Map jsonData; if (SwaggerConfig.swaggerJsonUrl.startsWith('file://')) { // 处理本地文件 final filePath = SwaggerConfig.swaggerJsonUrl.replaceFirst('file://', ''); final file = File(filePath); if (await file.exists()) { final content = await file.readAsString(); jsonData = json.decode(content) as Map; } else { throw SwaggerParseException( '本地文件不存在', url: SwaggerConfig.swaggerJsonUrl, details: '文件路径: $filePath', ); } } else { // 处理远程URL final response = await http.get( Uri.parse(SwaggerConfig.swaggerJsonUrl), headers: SwaggerConfig.httpHeaders, ); if (response.statusCode == 200) { jsonData = json.decode(response.body) as Map; } else { throw SwaggerParseException( 'HTTP请求失败', url: SwaggerConfig.swaggerJsonUrl, statusCode: response.statusCode, details: 'HTTP响应状态码: ${response.statusCode}', ); } } _cachedDocument = await parseSwaggerDocument(jsonData); print('✅ Swagger文档解析完成'); return _cachedDocument!; } catch (e) { if (e is SwaggerParseException) { rethrow; } throw SwaggerParseException( '获取Swagger文档失败', url: SwaggerConfig.swaggerJsonUrl, details: e.toString(), ); } }, ); } /// 解析Swagger JSON文档 Future parseSwaggerDocument( Map jsonData, ) async { return _performanceMonitor.measure('parseSwaggerDocument', () async { // 尝试从缓存获取 final cacheKey = 'swagger_doc_${jsonData.hashCode}'; final cachedResult = _cacheManager.get(cacheKey); if (cachedResult != null) { _cachedDocument = cachedResult; return cachedResult; } // 解析文档基本信息 final info = jsonData['info'] as Map? ?? {}; final title = info['title'] as String? ?? 'API Documentation'; final version = info['version'] as String? ?? '1.0.0'; final description = info['description'] as String? ?? ''; // 解析其他基本信息 final host = jsonData['host'] as String? ?? ''; final basePath = jsonData['basePath'] as String? ?? '/'; final schemes = List.from(jsonData['schemes'] ?? ['https']); final consumes = List.from(jsonData['consumes'] ?? []); final produces = List.from(jsonData['produces'] ?? []); // 解析tags信息 (用于获取控制器描述) final tagsInfo = _parseTagsInfo(jsonData); // 解析API路径 final paths = _parseApiPaths(jsonData); // 解析API模型 final models = _parseApiModels(jsonData); // 解析API控制器 (传入tags信息) final controllers = _parseApiControllers(paths, tagsInfo); final document = SwaggerDocument( title: title, version: version, description: description, host: host, basePath: basePath, schemes: schemes, consumes: consumes, produces: produces, paths: paths, models: models, controllers: controllers, ); // 缓存结果 _cacheManager.put(cacheKey, document); _cachedDocument = document; return document; }); } /// 解析tags信息 Map _parseTagsInfo(Map jsonData) { final tagsInfo = {}; try { final tags = jsonData['tags'] as List?; if (tags != null) { for (final tag in tags) { if (tag is Map) { final name = tag['name'] as String?; final description = tag['description'] as String?; if (name != null && description != null) { tagsInfo[name] = description; } } } } } catch (e) { print('⚠️ 解析tags信息时发生错误: $e'); } return tagsInfo; } /// 解析API路径 Map _parseApiPaths(Map jsonData) { final paths = {}; final pathsData = jsonData['paths'] as Map?; if (pathsData == null) { throw SwaggerParseException('未发现API路径定义'); } try { pathsData.forEach((pathKey, pathValue) { if (pathValue is Map) { pathValue.forEach((methodKey, methodValue) { if (methodValue is Map) { final method = HttpMethod.fromString(methodKey); final apiPath = ApiPath.fromJson( pathKey, methodKey, // 传入字符串而不是HttpMethod对象 methodValue, ); final key = '${method.value.toUpperCase()}_${pathKey.replaceAll('/', '_')}'; paths[key] = apiPath; } }); } }); } catch (e) { throw SwaggerParseException('解析API路径失败', details: e.toString()); } return paths; } /// 解析API模型 Map _parseApiModels(Map jsonData) { final models = {}; // 优先解析 components/schemas (Swagger 3.0) final schemas = jsonData['components']?['schemas'] as Map?; // 如果没有 components/schemas,尝试解析 definitions (Swagger 2.0) final definitions = jsonData['definitions'] as Map?; final modelDefinitions = schemas ?? definitions; if (modelDefinitions == null) { print('ℹ️ 未发现模型定义 (components/schemas 或 definitions)'); return models; } print( '🔍 发现模型定义位置: ${schemas != null ? 'components/schemas' : 'definitions'}', ); try { modelDefinitions.forEach((name, definition) { final model = ApiModel.fromJson( name, definition as Map, ); models[name] = model; }); } catch (e) { throw SwaggerParseException('解析API模型失败', details: e.toString()); } return models; } /// 解析API控制器 Map _parseApiControllers( Map paths, Map tagsInfo, ) { final controllers = >{}; try { // 根据tags分组API路径 for (final apiPath in paths.values) { for (final tag in apiPath.tags) { controllers.putIfAbsent(tag, () => []).add(apiPath); } } // 创建控制器对象 final result = {}; controllers.forEach((name, pathList) { // 从tags信息中获取描述 final swaggerDescription = tagsInfo[name]; // 使用通用的描述获取方法 final description = SwaggerConfig.getControllerDescription( name, swaggerDescription: swaggerDescription, ); result[name] = ApiController( name: name, description: description, paths: pathList, ); }); return result; } catch (e) { throw SwaggerParseException('解析API控制器失败', details: e.toString()); } } /// 解析属性类型 String parsePropertyType(Map propData) { try { // 直接类型 if (propData['type'] != null) { return propData['type'] as String; } // 引用类型 ($ref) if (propData['\$ref'] != null) { final ref = propData['\$ref'] as String; // 从 #/components/schemas/ModelName 或 #/definitions/ModelName 中提取类型名 final parts = ref.split('/'); if (parts.isNotEmpty) { return parts.last; } } // 数组类型 if (propData['items'] != null) { final items = propData['items'] as Map; final itemType = parsePropertyType(items); return 'array<$itemType>'; } // 默认类型 return 'string'; } catch (e) { throw SwaggerParseException('解析属性类型失败', details: e.toString()); } } /// 获取Dart类型映射 String getDartType(String swaggerType, String? format) { switch (swaggerType.toLowerCase()) { case 'string': switch (format?.toLowerCase()) { case 'date': case 'date-time': return 'DateTime'; case 'byte': case 'binary': return 'String'; default: return 'String'; } case 'integer': switch (format?.toLowerCase()) { case 'int64': return 'int'; case 'int32': default: return 'int'; } case 'number': switch (format?.toLowerCase()) { case 'float': case 'double': return 'double'; default: return 'double'; } case 'boolean': return 'bool'; case 'array': return 'List'; case 'object': return 'Map'; case 'file': return 'String'; default: // 检查是否为数组类型 if (swaggerType.startsWith('array<') && swaggerType.endsWith('>')) { final itemType = swaggerType.substring(6, swaggerType.length - 1); final dartItemType = getDartType(itemType, null); return 'List<$dartItemType>'; } // 默认为自定义类型 return StringUtils.generateClassName(swaggerType); } } /// 清除缓存 void clearCache() { _cachedDocument = null; _cacheManager.clear(); } /// 获取文档统计信息 Map getDocumentStats() { if (_cachedDocument == null) { return {}; } final doc = _cachedDocument!; // 统计HTTP方法 final methodStats = {}; for (final path in doc.paths.values) { final method = path.method.value; methodStats[method] = (methodStats[method] ?? 0) + 1; } // 统计模型类型 final modelStats = {}; for (final model in doc.models.values) { if (model.isEnum) { modelStats['enum'] = (modelStats['enum'] ?? 0) + 1; } else { modelStats['class'] = (modelStats['class'] ?? 0) + 1; } } return { 'title': doc.title, 'version': doc.version, 'paths': doc.paths.length, 'models': doc.models.length, 'controllers': doc.controllers.length, 'methods': methodStats, 'modelTypes': modelStats, }; } }