zeroclaw / backend /cmd /server /main.go
personalbotai
Initial commit from picoclaw
da590a7
package server
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/yourusername/repo-diagram/backend/internal/analyzer"
"github.com/yourusername/repo-diagram/backend/internal/diagram"
"github.com/yourusername/repo-diagram/backend/pkg/models"
"github.com/yourusername/repo-diagram/backend/pkg/utils"
)
type Server struct {
router *gin.Engine
analyzer *analyzer.Service
diagramSvc *diagram.Service
port string
}
func NewServer() *Server {
// Initialize services
analyzerSvc := analyzer.NewService()
diagramSvc := diagram.NewService()
// Setup router
router := gin.Default()
// Setup CORS
router.Use(func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
})
// Initialize server
server := &Server{
router: router,
analyzer: analyzerSvc,
diagramSvc: diagramSvc,
port: getEnv("PORT", "8080"),
}
// Setup routes
server.setupRoutes()
return server
}
func (s *Server) setupRoutes() {
api := s.router.Group("/api")
{
api.POST("/analyze", s.handleAnalyze)
api.GET("/diagram/:id", s.handleGetDiagram)
api.GET("/status/:id", s.handleGetStatus)
api.GET("/export/:id", s.handleExport)
api.GET("/health", s.handleHealth)
}
}
func (s *Server) handleAnalyze(c *gin.Context) {
var req models.AnalysisRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: err.Error()})
return
}
// Validate repository URL
if !utils.IsValidGitHubURL(req.RepoURL) {
c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: "Invalid GitHub repository URL"})
return
}
// Start analysis in background
go func() {
ctx := context.Background()
result, err := s.analyzer.AnalyzeRepository(ctx, req)
if err != nil {
log.Printf("Analysis failed: %v", err)
return
}
// Generate diagram
diagram, err := s.diagramSvc.Generate(ctx, result)
if err != nil {
log.Printf("Diagram generation failed: %v", err)
return
}
// Store result (in production, use database)
utils.SaveResult(result.ID, diagram)
}()
c.JSON(http.StatusAccepted, models.AnalysisResponse{
ID: utils.GenerateID(),
Status: "processing",
Message: "Analysis started",
})
}
func (s *Server) handleGetDiagram(c *gin.Context) {
id := c.Param("id")
diagram := utils.GetDiagram(id)
if diagram == nil {
c.JSON(http.StatusNotFound, models.ErrorResponse{Error: "Diagram not found"})
return
}
c.JSON(http.StatusOK, diagram)
}
func (s *Server) handleGetStatus(c *gin.Context) {
id := c.Param("id")
status := utils.GetStatus(id)
if status == nil {
c.JSON(http.StatusNotFound, models.ErrorResponse{Error: "Analysis not found"})
return
}
c.JSON(http.StatusOK, status)
}
func (s *Server) handleExport(c *gin.Context) {
id := c.Param("id")
format := c.DefaultQuery("format", "svg")
diagram := utils.GetDiagram(id)
if diagram == nil {
c.JSON(http.StatusNotFound, models.ErrorResponse{Error: "Diagram not found"})
return
}
switch format {
case "svg":
c.Data(http.StatusOK, "image/svg+xml", diagram.SVG)
case "json":
c.JSON(http.StatusOK, diagram)
default:
c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: "Unsupported format"})
}
}
func (s *Server) handleHealth(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
"time": time.Now().Unix(),
})
}
func (s *Server) Start() error {
return s.router.Run(":" + s.port)
}
func (s *Server) Shutdown(ctx context.Context) error {
// Graceful shutdown logic here
return nil
}
func getEnv(key, defaultValue string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultValue
}
func main() {
server := NewServer()
// Setup signal handling for graceful shutdown
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-quit
log.Println("Shutting down server...")
// Add cleanup logic here
os.Exit(0)
}()
log.Printf("Server starting on port %s", server.port)
if err := server.Start(); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}