package backend
import (
"fmt"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
type SwaggerFile struct {
Name string `json:"name"`
Path string `json:"path"`
Size int64 `json:"size"`
ModifiedTime string `json:"modifiedTime"`
}
type SwaggerServer struct {
server *http.Server
port int
running bool
mu sync.Mutex
}
var swaggerServer *SwaggerServer
var swaggerServerMu sync.Mutex
func (a *App) GetSwaggerFiles(dirPath string) ([]SwaggerFile, error) {
if dirPath == "" {
return nil, fmt.Errorf("directory path is empty")
}
var files []SwaggerFile
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if strings.HasSuffix(strings.ToLower(info.Name()), ".swagger.json") {
files = append(files, SwaggerFile{
Name: info.Name(),
Path: path,
Size: info.Size(),
ModifiedTime: info.ModTime().Format("2006-01-02 15:04:05"),
})
}
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to walk directory: %w", err)
}
return files, nil
}
func (a *App) ReadSwaggerFile(filePath string) (string, error) {
if filePath == "" {
return "", fmt.Errorf("file path is empty")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", fmt.Errorf("failed to read file: %w", err)
}
return string(content), nil
}
func (a *App) StartSwaggerServer(dirPath string) (string, error) {
if dirPath == "" {
return "", fmt.Errorf("directory path is empty")
}
swaggerServerMu.Lock()
defer swaggerServerMu.Unlock()
if swaggerServer != nil && swaggerServer.running {
return fmt.Sprintf("http://localhost:%d", swaggerServer.port), nil
}
port := 8080
for i := 0; i < 100; i++ {
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err == nil {
listener.Close()
break
}
port++
}
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
swaggerHTML := `
Swagger UI
`
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write([]byte(swaggerHTML))
})
mux.HandleFunc("/swagger.json", func(w http.ResponseWriter, r *http.Request) {
files, err := a.GetSwaggerFiles(dirPath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if len(files) == 0 {
http.Error(w, "No swagger files found", http.StatusNotFound)
return
}
fileName := r.URL.Query().Get("file")
selectedFile := files[0]
if fileName != "" {
for _, file := range files {
if file.Name == fileName {
selectedFile = file
break
}
}
}
content, err := os.ReadFile(selectedFile.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(content)
})
server := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: mux,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
}
swaggerServer = &SwaggerServer{
server: server,
port: port,
running: true,
}
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Printf("Swagger server error: %v\n", err)
}
}()
return fmt.Sprintf("http://localhost:%d", port), nil
}
func (a *App) StopSwaggerServer() error {
swaggerServerMu.Lock()
defer swaggerServerMu.Unlock()
if swaggerServer == nil || !swaggerServer.running {
return nil
}
if err := swaggerServer.server.Close(); err != nil {
return fmt.Errorf("failed to stop server: %w", err)
}
swaggerServer.running = false
return nil
}
func (a *App) IsSwaggerServerRunning() bool {
swaggerServerMu.Lock()
defer swaggerServerMu.Unlock()
if swaggerServer == nil {
return false
}
return swaggerServer.running
}
func (a *App) GetSwaggerServerURL() string {
swaggerServerMu.Lock()
defer swaggerServerMu.Unlock()
if swaggerServer == nil || !swaggerServer.running {
return ""
}
return fmt.Sprintf("http://localhost:%d", swaggerServer.port)
}