cursor / main.go
cacode's picture
Upload 48 files
1766992 verified
package main
import (
"context"
"github.com/libaxuan/cursor2api-go/config"
"github.com/libaxuan/cursor2api-go/handlers"
"github.com/libaxuan/cursor2api-go/middleware"
"github.com/libaxuan/cursor2api-go/models"
"fmt"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
func main() {
// ๅŠ ่ฝฝ้…็ฝฎ
cfg, err := config.LoadConfig()
if err != nil {
logrus.Fatalf("Failed to load config: %v", err)
}
// ่ฎพ็ฝฎๆ—ฅๅฟ—็บงๅˆซๅ’Œ GIN ๆจกๅผ๏ผˆๅฟ…้กปๅœจๅˆ›ๅปบ่ทฏ็”ฑๅ™จไน‹ๅ‰่ฎพ็ฝฎ๏ผ‰
if cfg.Debug {
logrus.SetLevel(logrus.DebugLevel)
gin.SetMode(gin.DebugMode)
} else {
logrus.SetLevel(logrus.InfoLevel)
gin.SetMode(gin.ReleaseMode)
}
// ็ฆ็”จ Gin ็š„่ฐƒ่ฏ•ไฟกๆฏ่พ“ๅ‡บ
gin.DisableConsoleColor()
// ๅˆ›ๅปบ่ทฏ็”ฑๅ™จ๏ผˆไฝฟ็”จ gin.New() ่€Œไธๆ˜ฏ gin.Default() ไปฅ้ฟๅ…้ป˜่ฎคๆ—ฅๅฟ—๏ผ‰
router := gin.New()
// ๆทปๅŠ ไธญ้—ดไปถ
router.Use(gin.Recovery())
router.Use(middleware.CORS())
router.Use(middleware.ErrorHandler())
// ๅชๅœจ Debug ๆจกๅผไธ‹ๅฏ็”จ GIN ็š„ๆ—ฅๅฟ—
if cfg.Debug {
router.Use(gin.Logger())
}
// ๅˆ›ๅปบๅค„็†ๅ™จ
handler := handlers.NewHandler(cfg)
// ๆณจๅ†Œ่ทฏ็”ฑ
setupRoutes(router, handler)
// ๅˆ›ๅปบHTTPๆœๅŠกๅ™จ
server := &http.Server{
Addr: fmt.Sprintf(":%d", cfg.Port),
Handler: router,
}
// ๆ‰“ๅฐๅฏๅŠจไฟกๆฏ
printStartupBanner(cfg)
// ๅฏๅŠจๆœๅŠกๅ™จ็š„goroutine
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logrus.Fatalf("Failed to start server: %v", err)
}
}()
// ็ญ‰ๅพ…ไธญๆ–ญไฟกๅทไปฅไผ˜้›…ๅ…ณ้—ญๆœๅŠกๅ™จ
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logrus.Info("Shutting down server...")
// ็ป™ๆœๅŠกๅ™จ5็ง’ๆ—ถ้—ดๅฎŒๆˆๅค„็†ๆญฃๅœจ่ฟ›่กŒ็š„่ฏทๆฑ‚
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
logrus.Fatalf("Server forced to shutdown: %v", err)
}
logrus.Info("Server exited")
}
func setupRoutes(router *gin.Engine, handler *handlers.Handler) {
// ๅฅๅบทๆฃ€ๆŸฅ
router.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"time": time.Now().Unix(),
})
})
// APIๆ–‡ๆกฃ้กต้ข
router.GET("/", handler.ServeDocs)
// API v1่ทฏ็”ฑ็ป„
v1 := router.Group("/v1")
{
// ๆจกๅž‹ๅˆ—่กจ
v1.GET("/models", middleware.AuthRequired(), handler.ListModels)
// ่ŠๅคฉๅฎŒๆˆ
v1.POST("/chat/completions", middleware.AuthRequired(), handler.ChatCompletions)
// Responses API
v1.POST("/responses", middleware.AuthRequired(), handler.Responses)
}
// ้™ๆ€ๆ–‡ไปถๆœๅŠก๏ผˆๅฆ‚ๆžœ้œ€่ฆ๏ผ‰
router.Static("/static", "./static")
}
// printStartupBanner ๆ‰“ๅฐๅฏๅŠจๆจชๅน…
func printStartupBanner(cfg *config.Config) {
banner := `
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘ Cursor2API Server โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
`
fmt.Println(banner)
fmt.Printf("๐Ÿš€ ๆœๅŠกๅœฐๅ€: http://localhost:%d\n", cfg.Port)
fmt.Printf("๐Ÿ“š API ๆ–‡ๆกฃ: http://localhost:%d/\n", cfg.Port)
fmt.Printf("๐Ÿ’Š ๅฅๅบทๆฃ€ๆŸฅ: http://localhost:%d/health\n", cfg.Port)
fmt.Printf("๐Ÿ”‘ API ๅฏ†้’ฅ: %s\n", maskAPIKey(cfg.APIKey))
modelList := cfg.GetModels()
fmt.Printf("\n๐Ÿค– ๆ”ฏๆŒๆจกๅž‹ (%d ไธช):\n", len(modelList))
// ๆŒ‰็ฑปๅˆซๅˆ†็ป„ๆ˜พ็คบๆจกๅž‹
providers := make(map[string][]string)
for _, modelID := range modelList {
if config, exists := models.GetModelConfig(modelID); exists {
providers[config.Provider] = append(providers[config.Provider], modelID)
} else {
providers["Other"] = append(providers["Other"], modelID)
}
}
// ๆŒ‰ProviderๆŽ’ๅบๅนถๆ˜พ็คบ
for _, provider := range []string{"Anthropic", "OpenAI", "Google", "Other"} {
if models, ok := providers[provider]; ok && len(models) > 0 {
fmt.Printf(" %s: %s\n", provider, strings.Join(models, ", "))
}
}
if cfg.Debug {
fmt.Println("\n๐Ÿ› ่ฐƒ่ฏ•ๆจกๅผ: ๅทฒๅฏ็”จ")
}
fmt.Println("\nโœจ ๆœๅŠกๅทฒๅฏๅŠจ๏ผŒๆŒ‰ Ctrl+C ๅœๆญข")
fmt.Println("โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”")
}
// maskAPIKey ๆŽฉ็  API ๅฏ†้’ฅ๏ผŒๅชๆ˜พ็คบๅ‰ 4 ไฝ
func maskAPIKey(key string) string {
if len(key) <= 4 {
return "****"
}
return key[:4] + "****"
}