package plugin import ( "encoding/json" "fmt" "os" "path/filepath" ) // OpenAPIGenerator 用于生成符合OpenAPI 3.0规范的API文档 type OpenAPIGenerator struct { pm *PluginManager // 插件管理器 outputPath string // 输出路径 info map[string]interface{} } // NewOpenAPIGenerator 创建一个新的OpenAPI生成器 func NewOpenAPIGenerator(pm *PluginManager, outputPath string) *OpenAPIGenerator { return &OpenAPIGenerator{ pm: pm, outputPath: outputPath, info: map[string]interface{}{ "title": "插件系统API", "description": "插件系统提供的API接口文档", "version": "1.0.0", "contact": map[string]interface{}{ "name": "开发团队", "email": "dev@example.com", "url": "https://example.com", }, }, } } // SetInfo 设置API文档的基本信息 func (g *OpenAPIGenerator) SetInfo(title, description, version string) { g.info["title"] = title g.info["description"] = description g.info["version"] = version } // SetContact 设置联系人信息 func (g *OpenAPIGenerator) SetContact(name, email, url string) { g.info["contact"] = map[string]interface{}{ "name": name, "email": email, "url": url, } } // GenerateOpenAPI 生成OpenAPI文档 func (g *OpenAPIGenerator) GenerateOpenAPI() error { // 确保输出目录存在 if err := os.MkdirAll(g.outputPath, 0755); err != nil { return fmt.Errorf("创建输出目录失败: %v", err) } // 创建OpenAPI规范文档 openapiSpec := g.createOpenAPISpec() // 将文档保存为JSON文件 jsonPath := filepath.Join(g.outputPath, "openapi.json") jsonData, err := json.MarshalIndent(openapiSpec, "", " ") if err != nil { return fmt.Errorf("JSON序列化失败: %v", err) } if err := os.WriteFile(jsonPath, jsonData, 0644); err != nil { return fmt.Errorf("写入JSON文件失败: %v", err) } // 创建HTML查看器 htmlPath := filepath.Join(g.outputPath, "index.html") htmlContent := g.createSwaggerUIHTML() if err := os.WriteFile(htmlPath, []byte(htmlContent), 0644); err != nil { return fmt.Errorf("写入HTML文件失败: %v", err) } return nil } // createOpenAPISpec 创建完整的OpenAPI规范文档 func (g *OpenAPIGenerator) createOpenAPISpec() map[string]interface{} { // 基本结构 spec := map[string]interface{}{ "openapi": "3.0.0", "info": g.info, "servers": []map[string]interface{}{ { "url": "/api", "description": "API服务器", }, }, "tags": []map[string]interface{}{}, "paths": map[string]interface{}{}, "components": map[string]interface{}{ "schemas": map[string]interface{}{}, "parameters": map[string]interface{}{}, }, } // 获取所有插件 plugins := g.pm.GetAllPlugins() // 生成标签(按插件类型分组) pluginTypeMap := make(map[PluginType]bool) for _, p := range plugins { pluginTypeMap[p.Type()] = true } tags := make([]map[string]interface{}, 0) for pType := range pluginTypeMap { tags = append(tags, map[string]interface{}{ "name": string(pType), "description": fmt.Sprintf("%s 类型的插件", pType), }) } spec["tags"] = tags // 为每个插件生成路径 paths := make(map[string]interface{}) schemas := make(map[string]interface{}) for _, p := range plugins { pluginName := p.Name() pluginType := string(p.Type()) // 插件基本信息路径 pluginInfoPath := fmt.Sprintf("/plugins/{name}/info") if _, exists := paths[pluginInfoPath]; !exists { paths[pluginInfoPath] = map[string]interface{}{ "get": map[string]interface{}{ "summary": "获取插件信息", "description": "获取指定插件的详细信息", "operationId": "getPluginInfo", "tags": []string{"Plugin"}, "parameters": []map[string]interface{}{ { "name": "name", "in": "path", "description": "插件名称", "required": true, "schema": map[string]interface{}{ "type": "string", }, }, }, "responses": map[string]interface{}{ "200": map[string]interface{}{ "description": "成功", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": map[string]interface{}{ "$ref": "#/components/schemas/PluginInfo", }, }, }, }, "404": map[string]interface{}{ "description": "插件不存在", }, }, }, } } // 定义插件操作的路径 operations := p.GetAllOperations() for opName, opInfo := range operations { pathTemplate := fmt.Sprintf("/plugins/{name}/execute/{action}") // 如果路径不存在,创建路径 if _, exists := paths[pathTemplate]; !exists { paths[pathTemplate] = map[string]interface{}{ "post": map[string]interface{}{ "summary": "执行插件操作", "description": "对指定插件执行特定操作", "operationId": "executePluginAction", "tags": []string{"Plugin"}, "parameters": []map[string]interface{}{ { "name": "name", "in": "path", "description": "插件名称", "required": true, "schema": map[string]interface{}{ "type": "string", }, }, { "name": "action", "in": "path", "description": "操作名称", "required": true, "schema": map[string]interface{}{ "type": "string", }, }, }, "requestBody": map[string]interface{}{ "description": "操作参数", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": map[string]interface{}{ "type": "object", }, }, }, }, "responses": map[string]interface{}{ "200": map[string]interface{}{ "description": "操作成功", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": map[string]interface{}{ "type": "object", }, }, }, }, "400": map[string]interface{}{ "description": "参数错误", }, "404": map[string]interface{}{ "description": "插件或操作不存在", }, "500": map[string]interface{}{ "description": "服务器错误", }, }, }, } } // 为每个操作创建特定的路径 opPath := fmt.Sprintf("/plugins/%s/actions/%s", pluginName, opName) opRequestSchema := g.createRequestSchema(opName, opInfo, schemas) opResponseSchema := g.createResponseSchema(opName, opInfo, schemas) paths[opPath] = map[string]interface{}{ "post": map[string]interface{}{ "summary": getMapString(opInfo, "description", fmt.Sprintf("执行 %s", opName)), "description": getMapString(opInfo, "description", fmt.Sprintf("在 %s 插件上执行 %s 操作", pluginName, opName)), "operationId": fmt.Sprintf("%s_%s", pluginName, opName), "tags": []string{pluginType}, "requestBody": map[string]interface{}{ "description": "操作参数", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": opRequestSchema, }, }, "required": true, }, "responses": map[string]interface{}{ "200": map[string]interface{}{ "description": "操作成功", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": opResponseSchema, }, }, }, "400": map[string]interface{}{ "description": "参数错误", }, "500": map[string]interface{}{ "description": "服务器错误", }, }, }, } } } // 添加通用路径 // 获取所有插件 paths["/plugins"] = map[string]interface{}{ "get": map[string]interface{}{ "summary": "获取所有插件", "description": "获取系统中所有可用插件的列表", "operationId": "getAllPlugins", "tags": []string{"PluginSystem"}, "responses": map[string]interface{}{ "200": map[string]interface{}{ "description": "成功", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": map[string]interface{}{ "type": "array", "items": map[string]interface{}{ "$ref": "#/components/schemas/PluginInfo", }, }, }, }, }, }, }, } // 按类型获取插件 paths["/plugins/type/{type}"] = map[string]interface{}{ "get": map[string]interface{}{ "summary": "按类型获取插件", "description": "获取指定类型的所有插件", "operationId": "getPluginsByType", "tags": []string{"PluginSystem"}, "parameters": []map[string]interface{}{ { "name": "type", "in": "path", "description": "插件类型", "required": true, "schema": map[string]interface{}{ "type": "string", "enum": []string{ string(PluginTypeGeneral), string(PluginTypeStorage), string(PluginTypeUtils), string(PluginTypeNetwork), }, }, }, }, "responses": map[string]interface{}{ "200": map[string]interface{}{ "description": "成功", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": map[string]interface{}{ "type": "array", "items": map[string]interface{}{ "$ref": "#/components/schemas/PluginInfo", }, }, }, }, }, }, }, } // 获取插件所有操作 paths["/plugins/{name}/actions"] = map[string]interface{}{ "get": map[string]interface{}{ "summary": "获取插件所有操作", "description": "获取指定插件支持的所有操作", "operationId": "getPluginActions", "tags": []string{"PluginSystem"}, "parameters": []map[string]interface{}{ { "name": "name", "in": "path", "description": "插件名称", "required": true, "schema": map[string]interface{}{ "type": "string", }, }, }, "responses": map[string]interface{}{ "200": map[string]interface{}{ "description": "成功", "content": map[string]interface{}{ "application/json": map[string]interface{}{ "schema": map[string]interface{}{ "type": "object", "additionalProperties": map[string]interface{}{ "type": "object", }, }, }, }, }, "404": map[string]interface{}{ "description": "插件不存在", }, }, }, } // 设置路径和组件 spec["paths"] = paths // 添加基本模式 schemas["PluginInfo"] = map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "name": map[string]interface{}{ "type": "string", "description": "插件名称", }, "version": map[string]interface{}{ "type": "string", "description": "插件版本", }, "description": map[string]interface{}{ "type": "string", "description": "插件描述", }, "author": map[string]interface{}{ "type": "string", "description": "插件作者", }, "type": map[string]interface{}{ "type": "string", "description": "插件类型", "enum": []string{ string(PluginTypeGeneral), string(PluginTypeStorage), string(PluginTypeUtils), string(PluginTypeNetwork), }, }, "enabled": map[string]interface{}{ "type": "boolean", "description": "插件是否启用", }, }, "required": []string{"name", "version", "type", "enabled"}, } // 更新组件模式 spec["components"].(map[string]interface{})["schemas"] = schemas return spec } // createRequestSchema 创建操作请求的JSON Schema func (g *OpenAPIGenerator) createRequestSchema(opName string, opInfo map[string]interface{}, schemas map[string]interface{}) map[string]interface{} { schemaName := fmt.Sprintf("%sRequest", opName) // 如果没有参数,返回空对象模式 params, ok := opInfo["parameters"].(map[string]interface{}) if !ok || len(params) == 0 { return map[string]interface{}{ "type": "object", } } // 创建请求模式 schema := map[string]interface{}{ "type": "object", "properties": map[string]interface{}{}, "required": []string{}, } properties := schema["properties"].(map[string]interface{}) required := schema["required"].([]string) // 添加参数 for paramName, paramInfo := range params { if info, ok := paramInfo.(map[string]interface{}); ok { paramType := getMapString(info, "type", "string") paramDesc := getMapString(info, "description", "") paramRequired := getMapBool(info, "required", false) // 为不同类型创建不同的模式 var propSchema map[string]interface{} switch paramType { case "string": propSchema = map[string]interface{}{ "type": "string", "description": paramDesc, } case "integer": propSchema = map[string]interface{}{ "type": "integer", "description": paramDesc, } case "float": propSchema = map[string]interface{}{ "type": "number", "description": paramDesc, } case "boolean": propSchema = map[string]interface{}{ "type": "boolean", "description": paramDesc, } case "array": propSchema = map[string]interface{}{ "type": "array", "description": paramDesc, "items": map[string]interface{}{ "type": "object", }, } // 如果有元素类型信息,使用它 if elemType, ok := info["elemType"].(map[string]interface{}); ok { elemTypeStr := getMapString(elemType, "type", "string") propSchema["items"] = map[string]interface{}{ "type": g.mapTypeToOpenAPI(elemTypeStr), } } case "object", "struct": // 对于结构体和对象,创建一个引用 structName := fmt.Sprintf("%s_%s", schemaName, paramName) propSchema = map[string]interface{}{ "$ref": fmt.Sprintf("#/components/schemas/%s", structName), "description": paramDesc, } // 创建结构体模式 structSchema := map[string]interface{}{ "type": "object", "properties": map[string]interface{}{}, "required": []string{}, } // 添加结构体字段 if fields, ok := info["fields"].(map[string]interface{}); ok { structProps := structSchema["properties"].(map[string]interface{}) structReq := structSchema["required"].([]string) for fieldName, fieldInfo := range fields { if fi, ok := fieldInfo.(map[string]interface{}); ok { fieldType := getMapString(fi, "type", "string") fieldDesc := getMapString(fi, "description", "") fieldRequired := getMapBool(fi, "required", false) structProps[fieldName] = map[string]interface{}{ "type": g.mapTypeToOpenAPI(fieldType), "description": fieldDesc, } if fieldRequired { structReq = append(structReq, fieldName) } } } structSchema["required"] = structReq } // 添加到模式 schemas[structName] = structSchema default: propSchema = map[string]interface{}{ "type": "string", "description": paramDesc, } } properties[paramName] = propSchema if paramRequired { required = append(required, paramName) } } } // 如果没有必填参数,删除required数组 if len(required) == 0 { delete(schema, "required") } else { schema["required"] = required } // 添加到模式 schemas[schemaName] = schema return map[string]interface{}{ "$ref": fmt.Sprintf("#/components/schemas/%s", schemaName), } } // createResponseSchema 创建操作响应的JSON Schema func (g *OpenAPIGenerator) createResponseSchema(opName string, opInfo map[string]interface{}, schemas map[string]interface{}) map[string]interface{} { schemaName := fmt.Sprintf("%sResponse", opName) // 如果没有返回值,返回空对象模式 returns, ok := opInfo["returns"].(map[string]interface{}) if !ok || len(returns) == 0 { return map[string]interface{}{ "type": "object", } } // 如果只有一个错误返回,使用简单响应 if len(returns) == 1 && returns["error"] != nil { return map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "success": map[string]interface{}{ "type": "boolean", "description": "操作是否成功", }, "error": map[string]interface{}{ "type": "string", "description": "错误信息", "nullable": true, }, }, } } // 创建响应模式 schema := map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "success": map[string]interface{}{ "type": "boolean", "description": "操作是否成功", }, }, } properties := schema["properties"].(map[string]interface{}) // 遍历所有返回值 for retName, retInfo := range returns { if retName == "error" { properties["error"] = map[string]interface{}{ "type": "string", "description": "错误信息", "nullable": true, } continue } if info, ok := retInfo.(map[string]interface{}); ok { retType := getMapString(info, "type", "string") retDesc := getMapString(info, "description", "") // 为不同类型创建不同的模式 var propSchema map[string]interface{} switch retType { case "string": propSchema = map[string]interface{}{ "type": "string", "description": retDesc, } case "integer": propSchema = map[string]interface{}{ "type": "integer", "description": retDesc, } case "float": propSchema = map[string]interface{}{ "type": "number", "description": retDesc, } case "boolean": propSchema = map[string]interface{}{ "type": "boolean", "description": retDesc, } case "array": propSchema = map[string]interface{}{ "type": "array", "description": retDesc, "items": map[string]interface{}{ "type": "object", }, } // 如果有元素类型信息,使用它 if elemType, ok := info["elemType"].(map[string]interface{}); ok { elemTypeStr := getMapString(elemType, "type", "string") propSchema["items"] = map[string]interface{}{ "type": g.mapTypeToOpenAPI(elemTypeStr), } } case "object": // 对于对象,创建嵌套模式 propSchema = map[string]interface{}{ "type": "object", "description": retDesc, "properties": map[string]interface{}{}, } // 如果有属性信息,添加它们 if props, ok := info["properties"].(map[string]interface{}); ok { propsMap := propSchema["properties"].(map[string]interface{}) for propName, propInfo := range props { if pi, ok := propInfo.(map[string]interface{}); ok { propType := getMapString(pi, "type", "string") propDesc := getMapString(pi, "description", "") propsMap[propName] = map[string]interface{}{ "type": g.mapTypeToOpenAPI(propType), "description": propDesc, } } } } default: propSchema = map[string]interface{}{ "type": "string", "description": retDesc, } } properties[retName] = propSchema } } // 添加到模式 schemas[schemaName] = schema return map[string]interface{}{ "$ref": fmt.Sprintf("#/components/schemas/%s", schemaName), } } // createSwaggerUIHTML 创建包含Swagger UI的HTML文件 func (g *OpenAPIGenerator) createSwaggerUIHTML() string { return ` 插件系统API文档
` } // mapTypeToOpenAPI 将内部类型映射到OpenAPI类型 func (g *OpenAPIGenerator) mapTypeToOpenAPI(internalType string) string { switch internalType { case "integer": return "integer" case "float": return "number" case "boolean": return "boolean" case "array": return "array" case "object", "struct": return "object" default: return "string" } }