| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 | package swagger_apiimport (	"context"	"fmt"	"git.ikuban.com/server/swagger-api/v2/generator"	"github.com/go-kratos/kratos/v2/api/metadata"	"github.com/xmkuban/utils/utils"	"google.golang.org/protobuf/compiler/protogen"	"google.golang.org/protobuf/types/descriptorpb"	"google.golang.org/protobuf/types/pluginpb")// Service is servicetype Service struct {	ser *Server}// New servicefunc New(skipError bool) *Service {	return &Service{		ser: NewServer(nil, skipError),	}}// ListServices list servicesfunc (s *Service) ListServices(ctx context.Context, in *metadata.ListServicesRequest) (*metadata.ListServicesReply, error) {	return s.ser.ListServices(ctx, &metadata.ListServicesRequest{})}// GetServiceOpenAPI get service open apifunc (s *Service) GetServiceOpenAPI(ctx context.Context, in *metadata.GetServiceDescRequest) (string, error) {	protoSet, err := s.ser.GetServiceDesc(ctx, in)	if err != nil {		return "", err	}	files := protoSet.FileDescSet.File	newFiles := make([]*descriptorpb.FileDescriptorProto, 0)	newFileMap := make(map[string]byte)	for _, v := range files {		if _, ok := newFileMap[v.GetName()]; !ok {			newFiles = append(newFiles, v)			newFileMap[v.GetName()] = 1		}	}	files = newFiles	var target string	if len(files) == 0 {		return "", fmt.Errorf("proto file is empty")	}	if files[len(files)-1].Name == nil {		return "", fmt.Errorf("proto file's name is null")	}	target = files[len(files)-1].GetName()	req := new(pluginpb.CodeGeneratorRequest)	req.FileToGenerate = []string{target}	var para = ""	req.Parameter = ¶	req.ProtoFile = files	opts := protogen.Options{}	plugin, err := opts.New(req)	if err != nil {		return "", err	}	plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)	var content []byte	gen := generator.NewOpenAPIv3Generator(plugin, generator.Configuration{		Version:         utils.ToPointString("1.0"),		Title:           utils.ToPointString(""),		Description:     utils.ToPointString(""),		Naming:          utils.ToPointString("proto"),		FQSchemaNaming:  utils.ToPointBool(true),		EnumType:        utils.ToPointString("integer"),		CircularDepth:   utils.ToPointInt(2),		DefaultResponse: utils.ToPointBool(false),		OutputMode:      utils.ToPointString("merged"),	}, plugin.Files)	content, err = gen.RunV2()	if err != nil {		return "", err	}	return string(content), nil}// GetAllServicesOpenAPI get all services merged into one openapi document// servicesList: specific services to include, pass nil or empty slice to include all services// title: the title for the merged API document// description: the description for the merged API documentfunc (s *Service) GetAllServicesOpenAPI(ctx context.Context, servicesList []string, title, description string) (string, error) {	// Determine which services to process	var servicesToProcess []string	if len(servicesList) > 0 {		// Use the specified services list		servicesToProcess = servicesList	} else {		// Get all services if no list specified		allServices, err := s.ser.ListServices(ctx, &metadata.ListServicesRequest{})		if err != nil {			return "", err		}		servicesToProcess = allServices.Services	}	if len(servicesToProcess) == 0 {		return "", fmt.Errorf("no services found")	}	// Collect all proto files from specified services	allFiles := make([]*descriptorpb.FileDescriptorProto, 0)	fileMap := make(map[string]byte)	filesToGenerate := make([]string, 0)	for _, serviceName := range servicesToProcess {		protoSet, err := s.ser.GetServiceDesc(ctx, &metadata.GetServiceDescRequest{Name: serviceName})		if err != nil {			// Skip services that fail to load			continue		}		for _, file := range protoSet.FileDescSet.File {			if _, ok := fileMap[file.GetName()]; !ok {				allFiles = append(allFiles, file)				fileMap[file.GetName()] = 1				// Add files that contain services to the generation list				if len(file.Service) > 0 {					filesToGenerate = append(filesToGenerate, file.GetName())				}			}		}	}	if len(allFiles) == 0 {		return "", fmt.Errorf("no proto files found")	}	if len(filesToGenerate) == 0 {		return "", fmt.Errorf("no service files found")	}	// Create code generator request	req := new(pluginpb.CodeGeneratorRequest)	req.FileToGenerate = filesToGenerate	var para = ""	req.Parameter = ¶	req.ProtoFile = allFiles	opts := protogen.Options{}	plugin, err := opts.New(req)	if err != nil {		return "", err	}	plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)	// Generate merged OpenAPI document	gen := generator.NewOpenAPIv3Generator(plugin, generator.Configuration{		Version:         utils.ToPointString("1.0"),		Title:           utils.ToPointString(title),		Description:     utils.ToPointString(description),		Naming:          utils.ToPointString("proto"),		FQSchemaNaming:  utils.ToPointBool(true),		EnumType:        utils.ToPointString("integer"),		CircularDepth:   utils.ToPointInt(2),		DefaultResponse: utils.ToPointBool(false),		OutputMode:      utils.ToPointString("merged"),		PreserveInfo:    utils.ToPointBool(true),	}, plugin.Files)	content, err := gen.RunV2()	if err != nil {		return "", err	}	return string(content), nil}
 |