import json import logging from flask import Flask, jsonify, request from pathlib import Path app = Flask(__name__) logging.basicConfig(level=logging.INFO) # --- 模拟数据和内存数据库 --- DMS_ASSETS_DIR = Path(__file__).parent / 'assets' / 'doc' / 'dms' API_LIST_DATA = {} MODEL_DATA = {} MOCK_SCHEMAS_CACHE = {} IN_MEMORY_DB = {} # 新增: 作为内存数据库 try: with open(DMS_ASSETS_DIR / '列表.json', 'r', encoding='utf-8') as f: API_LIST_DATA = json.load(f) except FileNotFoundError as e: logging.error(f"错误: 模拟数据文件 '列表.json' 未找到。详情: {e}") API_LIST_DATA = {"code": 500, "message": "模拟数据 '列表.json' 未找到."} def generate_fake_schema(record: dict) -> dict: """根据列表中的单条记录,生成一个假的、但结构合理的schema""" name = record.get('name', 'unknown_name') title = record.get('title', 'Unknown Title') version = record.get('version', '0.0.0') # 假设第一个属性是主键 pk_name = f"{name}_id" schema_properties = { pk_name: {"type": "string", "title": "主键", "description": f"主键 for {name}"}, "description": {"type": "string", "title": "描述", "description": "一个简单的描述字段"}, "update_date": {"type": "string", "format": "date-time", "title": "更新日期"}, "status": { "type": "string", "title": "状态", "enum": ["active", "inactive", "archived"] }, "record_count": { "type": "integer", "title": "记录数", "minimum": 0, "maximum": 10000 } } model = { "type": "object", "title": title, "properties": schema_properties, "required": [pk_name, "status"] } # 按照parser.py中的逻辑构建删除请求的schema delete_pk_schema = { "type": "array", "items": { "type": "object", "properties": { pk_name: schema_properties[pk_name] }, "required": [pk_name] } } return { "code": 0, "message": "操作处理成功", "data": { "version": version, "model": model, "_delete_schema_for_mock": delete_pk_schema # 内部使用,方便查找主键 } } def preload_schemas(): """在服务器启动时,预先生成并缓存所有schema""" if API_LIST_DATA.get("code") == 0: records = API_LIST_DATA.get("data", {}).get("records", []) logging.info(f"预加载 {len(records)} 个API的模拟schema...") for record in records: record_id = record.get("id") if record_id: MOCK_SCHEMAS_CACHE[record_id] = generate_fake_schema(record) logging.info("Schema预加载完成。") # --- 元数据模拟端点 --- @app.route('/api/schema/manage/schema', methods=['GET']) def get_api_list(): """模拟获取DMS中所有API列表的接口。""" logging.info("Mock服务器: 收到API列表请求。") return jsonify(API_LIST_DATA) @app.route('/api/schema/manage/schema/', methods=['GET']) def get_schema_details(model_id): """模拟根据ID获取单个API模型(schema)的接口。""" logging.info(f"Mock服务器: 收到ID为 '{model_id}' 的schema详情请求。") schema_data = MOCK_SCHEMAS_CACHE.get(model_id) if schema_data: return jsonify(schema_data) else: return jsonify({"code": 404, "message": f"未找到ID为 '{model_id}' 的schema。"}), 404 # --- CRUD 模拟端点 --- def get_pk_name_from_model(name: str) -> str: """辅助函数:根据资源名找到其主键字段名""" # 这是一个简化逻辑。真实场景可能更复杂。 # 我们根据generate_fake_schema的逻辑,假设主键是 '资源名_id' return f"{name}_id" @app.route('/api/dms//v1/', methods=['POST']) def create_resource(dms_instance_code, name): """Create (POST): 创建资源""" logging.info(f"Mock服务器: 收到对 '{name}' 的CREATE请求") request_data = request.get_json(silent=True) if not request_data or 'data' not in request_data or not isinstance(request_data['data'], list): return jsonify({"code": 400, "message": "请求体格式错误,应为 {'data': [...]}"}), 400 if name not in IN_MEMORY_DB: IN_MEMORY_DB[name] = {} pk_name = get_pk_name_from_model(name) for item in request_data['data']: if pk_name not in item: return jsonify({"code": 400, "message": f"创建失败,数据项缺少主键 '{pk_name}'"}), 400 pk_value = item[pk_name] IN_MEMORY_DB[name][pk_value] = item logging.info(f" > 在 '{name}' 中创建/更新了资源 ID: {pk_value}") return jsonify({"code": 0, "message": "创建成功", "data": True}) @app.route('/api/dms//v1/', methods=['PUT']) def update_resource(dms_instance_code, name): """Update (PUT): 更新资源""" logging.info(f"Mock服务器: 收到对 '{name}' 的UPDATE请求") # 实现逻辑与Create完全相同 return create_resource(dms_instance_code, name) @app.route('/api/dms//v1///', methods=['GET']) def read_resource(dms_instance_code, name, version, id): """Read (GET by ID): 读取单个资源""" logging.info(f"Mock服务器: 收到对 '{name}' 的READ请求, ID: {id}") resource = IN_MEMORY_DB.get(name, {}).get(id) if resource: return jsonify({"code": 0, "message": "读取成功", "data": resource}) else: return jsonify({"code": 404, "message": f"资源 '{name}' with ID '{id}' 未找到."}), 404 @app.route('/api/dms//v1/', methods=['DELETE']) def delete_resource(dms_instance_code, name): """Delete (DELETE): 删除资源""" logging.info(f"Mock服务器: 收到对 '{name}' 的DELETE请求") request_data = request.get_json(silent=True) if not request_data or 'data' not in request_data or not isinstance(request_data['data'], list): return jsonify({"code": 400, "message": "请求体格式错误,应为 {'data': [{pk: value}, ...]}"}), 400 pk_name = get_pk_name_from_model(name) deleted_count = 0 for item_to_delete in request_data['data']: if pk_name in item_to_delete: pk_value = item_to_delete[pk_name] if IN_MEMORY_DB.get(name, {}).pop(pk_value, None): logging.info(f" > 从 '{name}' 删除了资源 ID: {pk_value}") deleted_count += 1 if deleted_count > 0: return jsonify({"code": 0, "message": "删除成功", "data": True}) else: return jsonify({"code": 404, "message": "未找到要删除的资源", "data": False}) @app.route('/api/dms//v1//', methods=['POST']) def list_resources(dms_instance_code, name, version): """List (POST): 获取资源列表""" logging.info(f"Mock服务器: 收到对 '{name}' 的LIST请求") all_resources = list(IN_MEMORY_DB.get(name, {}).values()) return jsonify({ "code": 0, "message": f"获取 '{name}' 列表成功", "data": all_resources }) def print_routes(app): """打印应用中所有已注册的路由。""" logging.info("\n--- 已注册的API路由 ---") for rule in sorted(app.url_map.iter_rules(), key=lambda r: str(r)): methods = ','.join(sorted(list(rule.methods))) logging.info(f"URL: {rule!s:55s} 方法: {methods:25s} 端点: {rule.endpoint}") logging.info("-------------------------\n") if __name__ == '__main__': preload_schemas() print_routes(app) port = 5001 logging.info(f"正在启动用于DMS API的Flask模拟服务器,地址为 http://127.0.0.1:{port}") app.run(host='0.0.0.0', port=port, debug=False)