fix: 修复语法问题

This commit is contained in:
tbphp
2025-06-09 22:27:30 +08:00
parent 9562f0f6dd
commit 6b33f7054d
11 changed files with 124 additions and 39 deletions

View File

@@ -38,26 +38,11 @@ REQUEST_TIMEOUT=30000
# =========================================== # ===========================================
# 性能优化配置 # 性能优化配置
# =========================================== # ===========================================
# 最大连接 # 最大并发请求
MAX_SOCKETS=100 MAX_CONCURRENT_REQUESTS=100
# 最大空闲连接数 # 启用 Gzip 压缩
MAX_FREE_SOCKETS=20 ENABLE_GZIP=false
# 启用 Keep-Alive
ENABLE_KEEP_ALIVE=true
# 禁用压缩减少CPU开销
DISABLE_COMPRESSION=true
# 缓冲区大小字节建议流式响应使用64KB或更大
BUFFER_SIZE=65536
# 流式传输缓冲区大小字节默认64KB
STREAM_BUFFER_SIZE=65536
# 流式请求响应头超时毫秒默认10秒
STREAM_HEADER_TIMEOUT=10000
# =========================================== # ===========================================
# 日志配置 # 日志配置

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 GPT-Load Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -187,20 +187,36 @@ make help # Show all commands
```text ```text
/ /
├── cmd/ ├── cmd/
│ └── gpt-load/
│ └── main.go # Main entry point │ └── main.go # Main entry point
├── internal/ ├── internal/
│ ├── config/ │ ├── config/
│ │ └── config.go # Configuration management │ │ └── manager.go # Configuration management
│ ├── errors/
│ │ └── errors.go # Custom error types
│ ├── handler/
│ │ └── handler.go # HTTP handlers
│ ├── keymanager/ │ ├── keymanager/
│ │ └── keymanager.go # Key manager │ │ └── manager.go # Key manager
│ ├── middleware/
│ │ └── middleware.go # HTTP middleware
│ └── proxy/ │ └── proxy/
│ └── proxy.go # Proxy server core │ └── server.go # Proxy server core
├── pkg/
│ └── types/
│ └── interfaces.go # Common interfaces and types
├── scripts/
│ └── validate-keys.py # Key validation script
├── .github/
│ └── workflows/
│ └── docker-build.yml # GitHub Actions CI/CD
├── build/ # Build output directory ├── build/ # Build output directory
├── .env.example # Configuration template ├── .env.example # Configuration template
├── Dockerfile # Docker build file ├── Dockerfile # Docker build file
├── docker-compose.yml # Docker Compose configuration ├── docker-compose.yml # Docker Compose configuration
├── Makefile # Build scripts ├── Makefile # Build scripts
├── go.mod # Go module file ├── go.mod # Go module file
├── LICENSE # MIT License
└── README.md # Project documentation └── README.md # Project documentation
``` ```

View File

@@ -187,20 +187,36 @@ make help # 显示所有命令
```text ```text
/ /
├── cmd/ ├── cmd/
│ └── gpt-load/
│ └── main.go # 主入口文件 │ └── main.go # 主入口文件
├── internal/ ├── internal/
│ ├── config/ │ ├── config/
│ │ └── config.go # 配置管理 │ │ └── manager.go # 配置管理
│ ├── errors/
│ │ └── errors.go # 自定义错误类型
│ ├── handler/
│ │ └── handler.go # HTTP 处理器
│ ├── keymanager/ │ ├── keymanager/
│ │ └── keymanager.go # 密钥管理器 │ │ └── manager.go # 密钥管理器
│ ├── middleware/
│ │ └── middleware.go # HTTP 中间件
│ └── proxy/ │ └── proxy/
│ └── proxy.go # 代理服务器核心 │ └── server.go # 代理服务器核心
├── pkg/
│ └── types/
│ └── interfaces.go # 通用接口和类型
├── scripts/
│ └── validate-keys.py # 密钥验证脚本
├── .github/
│ └── workflows/
│ └── docker-build.yml # GitHub Actions CI/CD
├── build/ # 构建输出目录 ├── build/ # 构建输出目录
├── .env.example # 配置文件模板 ├── .env.example # 配置文件模板
├── Dockerfile # Docker 构建文件 ├── Dockerfile # Docker 构建文件
├── docker-compose.yml # Docker Compose 配置 ├── docker-compose.yml # Docker Compose 配置
├── Makefile # 构建脚本 ├── Makefile # 构建脚本
├── go.mod # Go 模块文件 ├── go.mod # Go 模块文件
├── LICENSE # MIT 许可证
└── README.md # 项目文档 └── README.md # 项目文档
``` ```

View File

@@ -107,6 +107,13 @@ func setupRoutes(handlers *handler.Handler, proxyServer *proxy.ProxyServer, conf
router := gin.New() router := gin.New()
// Add server start time middleware for uptime calculation
startTime := time.Now()
router.Use(func(c *gin.Context) {
c.Set("serverStartTime", startTime)
c.Next()
})
// Add middleware // Add middleware
router.Use(middleware.Recovery()) router.Use(middleware.Recovery())
router.Use(middleware.Logger(configManager.GetLogConfig())) router.Use(middleware.Logger(configManager.GetLogConfig()))

View File

@@ -243,7 +243,16 @@ func parseBoolean(value string, defaultValue bool) bool {
if value == "" { if value == "" {
return defaultValue return defaultValue
} }
return strings.ToLower(value) == "true"
lowerValue := strings.ToLower(value)
switch lowerValue {
case "true", "1", "yes", "on":
return true
case "false", "0", "no", "off":
return false
default:
return defaultValue
}
} }
// parseArray parses array environment variable (comma-separated) // parseArray parses array environment variable (comma-separated)

View File

@@ -39,12 +39,20 @@ func (h *Handler) Health(c *gin.Context) {
httpStatus = http.StatusServiceUnavailable httpStatus = http.StatusServiceUnavailable
} }
// Calculate uptime (this should be tracked from server start time)
uptime := "unknown"
if startTime, exists := c.Get("serverStartTime"); exists {
if st, ok := startTime.(time.Time); ok {
uptime = time.Since(st).String()
}
}
c.JSON(httpStatus, gin.H{ c.JSON(httpStatus, gin.H{
"status": status, "status": status,
"timestamp": time.Now().UTC().Format(time.RFC3339), "timestamp": time.Now().UTC().Format(time.RFC3339),
"healthy_keys": stats.HealthyKeys, "healthy_keys": stats.HealthyKeys,
"total_keys": stats.TotalKeys, "total_keys": stats.TotalKeys,
"uptime": time.Since(time.Now()).String(), // This would need to be tracked properly "uptime": uptime,
}) })
} }

View File

@@ -306,12 +306,20 @@ func (km *Manager) GetBlacklist() []types.BlacklistEntry {
// setupMemoryCleanup sets up periodic memory cleanup // setupMemoryCleanup sets up periodic memory cleanup
func (km *Manager) setupMemoryCleanup() { func (km *Manager) setupMemoryCleanup() {
km.cleanupTicker = time.NewTicker(5 * time.Minute) // Reduce GC frequency to every 15 minutes to avoid performance impact
km.cleanupTicker = time.NewTicker(15 * time.Minute)
go func() { go func() {
for { for {
select { select {
case <-km.cleanupTicker.C: case <-km.cleanupTicker.C:
// Only trigger GC if memory usage is high
var m runtime.MemStats
runtime.ReadMemStats(&m)
// Trigger GC only if allocated memory is above 100MB
if m.Alloc > 100*1024*1024 {
runtime.GC() runtime.GC()
logrus.Debugf("Manual GC triggered, memory usage: %d MB", m.Alloc/1024/1024)
}
case <-km.stopCleanup: case <-km.stopCleanup:
return return
} }

View File

@@ -62,8 +62,12 @@ func Logger(config types.LogConfig) gin.HandlerFunc {
retryInfo = fmt.Sprintf(" - Retry[%d]", retryCount) retryInfo = fmt.Sprintf(" - Retry[%d]", retryCount)
} }
// Filter health check logs // Filter health check and other monitoring endpoint logs to reduce noise
if path == "/health" { if isMonitoringEndpoint(path) {
// Only log errors for monitoring endpoints
if statusCode >= 400 {
logrus.Warnf("%s %s - %d - %v", method, fullPath, statusCode, latency)
}
return return
} }
@@ -257,3 +261,14 @@ func ErrorHandler() gin.HandlerFunc {
} }
} }
} }
// isMonitoringEndpoint checks if the path is a monitoring endpoint
func isMonitoringEndpoint(path string) bool {
monitoringPaths := []string{"/health", "/stats", "/blacklist", "/reset-keys"}
for _, monitoringPath := range monitoringPaths {
if path == monitoringPath {
return true
}
}
return false
}

View File

@@ -369,8 +369,8 @@ func (ps *ProxyServer) handleStreamingResponse(c *gin.Context, resp *http.Respon
return return
} }
// Copy streaming data // Copy streaming data with optimized buffer size
buffer := make([]byte, 4096) buffer := make([]byte, 32*1024) // 32KB buffer for better performance
for { for {
n, err := resp.Body.Read(buffer) n, err := resp.Body.Read(buffer)
if n > 0 { if n > 0 {