106 lines
2.3 KiB
Go
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()
|
|
}
|
|
}
|