Files
MonocoEditor-With-Lsp-Backend/backend/cmd/server/main.go
2026-02-15 15:55:49 +08:00

106 lines
2.3 KiB
Go

package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"monica-go-completion-backend/internal/api"
"monica-go-completion-backend/internal/completion"
"monica-go-completion-backend/internal/lsp"
)
type config struct {
Port string
GoplsPath string
WorkspaceDir string
AllowOrigin string
}
func main() {
cfg := loadConfig()
lspClient, err := lsp.NewClient(context.Background(), cfg.GoplsPath, cfg.WorkspaceDir)
if err != nil {
log.Fatalf("create gopls client failed: %v", err)
}
defer func() {
_ = lspClient.Close()
}()
completionService := completion.NewService(lspClient)
router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
router.Use(corsMiddleware(cfg.AllowOrigin))
api.RegisterRoutes(router, completionService)
server := &http.Server{
Addr: ":" + cfg.Port,
Handler: router,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 60 * time.Second,
}
go func() {
log.Printf("completion backend listening on :%s", cfg.Port)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("http server failed: %v", err)
}
}()
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
<-sigCh
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
log.Printf("http shutdown failed: %v", err)
}
}
func loadConfig() config {
cwd, err := os.Getwd()
if err != nil {
cwd = "."
}
return config{
Port: getenv("PORT", "8080"),
GoplsPath: getenv("GOPLS_PATH", "gopls"),
WorkspaceDir: getenv("WORKSPACE_DIR", cwd),
AllowOrigin: getenv("CORS_ALLOW_ORIGIN", "*"),
}
}
func getenv(key, fallback string) string {
v := os.Getenv(key)
if v == "" {
return fallback
}
return v
}
func corsMiddleware(allowOrigin string) gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", allowOrigin)
c.Header("Access-Control-Allow-Methods", "GET,POST,OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type,Authorization")
if c.Request.Method == http.MethodOptions {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}