feat: 每用户最大连接数改为可配置,默认 30
将 maxConnsPerUser 从硬编码常量(3)改为数据库动态配置项,管理员可在 /admin/vpn 隧道设置中调整,保存后对新连接立即生效。 - model/vpn.go: VpnSetting 新增 MaxConnsPerUser 字段,gorm default:30 - db/db.go: 种子数据设默认 30;旧库回填 0 值为 30 - vpn/tunnel.go: 删除 maxConnsPerUser 常量,改读 VPN.Settings(),兜底 30 - handler/vpn.go: API 响应/请求结构体新增字段,校验范围 1-1000 - VpnView.vue: 隧道设置表单新增"每用户最大连接数"输入框 - zh.ts/en.ts: 新增 maxConnsPerUser 文案,更新首页多设备描述 - docs/client-development.md: 更新常量表为可配置项
This commit is contained in:
+17
-8
@@ -105,21 +105,30 @@ func seedDefaultAdmin(cfg *config.DatabaseConfig) error {
|
||||
func seedDefaultVpnSettings() error {
|
||||
var s model.VpnSetting
|
||||
if err := DB.First(&s, model.VpnSettingSingletonID).Error; err == nil {
|
||||
needSave := false
|
||||
if s.Subnet6 == "" {
|
||||
s.Subnet6 = "fd00:dead:beef::/112"
|
||||
needSave = true
|
||||
}
|
||||
if s.MaxConnsPerUser == 0 {
|
||||
s.MaxConnsPerUser = 30
|
||||
needSave = true
|
||||
}
|
||||
if needSave {
|
||||
DB.Save(&s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
s = model.VpnSetting{
|
||||
ID: model.VpnSettingSingletonID,
|
||||
Enabled: false,
|
||||
Subnet: "192.168.77.0/24",
|
||||
Subnet6: "fd00:dead:beef::/112",
|
||||
MTU: 1420,
|
||||
InterfaceName: "",
|
||||
DoLocalIPConfig: true,
|
||||
DoRemoteIPConfig: true,
|
||||
ID: model.VpnSettingSingletonID,
|
||||
Enabled: false,
|
||||
Subnet: "192.168.77.0/24",
|
||||
Subnet6: "fd00:dead:beef::/112",
|
||||
MTU: 1420,
|
||||
InterfaceName: "",
|
||||
DoLocalIPConfig: true,
|
||||
DoRemoteIPConfig: true,
|
||||
MaxConnsPerUser: 30,
|
||||
}
|
||||
return DB.Create(&s).Error
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type vpnSettingsResponse struct {
|
||||
AllowClientToClient bool `json:"allow_client_to_client"`
|
||||
DoLocalIPConfig bool `json:"do_local_ip_config"`
|
||||
DoRemoteIPConfig bool `json:"do_remote_ip_config"`
|
||||
MaxConnsPerUser int `json:"max_conns_per_user"`
|
||||
}
|
||||
|
||||
type updateVpnSettingsRequest struct {
|
||||
@@ -33,6 +34,7 @@ type updateVpnSettingsRequest struct {
|
||||
AllowClientToClient *bool `json:"allow_client_to_client"`
|
||||
DoLocalIPConfig *bool `json:"do_local_ip_config"`
|
||||
DoRemoteIPConfig *bool `json:"do_remote_ip_config"`
|
||||
MaxConnsPerUser *int `json:"max_conns_per_user"`
|
||||
}
|
||||
|
||||
func loadVpnSettings() (model.VpnSetting, error) {
|
||||
@@ -131,6 +133,7 @@ func GetVpnSettings(c *gin.Context) {
|
||||
AllowClientToClient: s.AllowClientToClient,
|
||||
DoLocalIPConfig: s.DoLocalIPConfig,
|
||||
DoRemoteIPConfig: s.DoRemoteIPConfig,
|
||||
MaxConnsPerUser: s.MaxConnsPerUser,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -185,6 +188,13 @@ func UpdateVpnSettings(c *gin.Context) {
|
||||
if req.DoRemoteIPConfig != nil {
|
||||
s.DoRemoteIPConfig = *req.DoRemoteIPConfig
|
||||
}
|
||||
if req.MaxConnsPerUser != nil {
|
||||
if *req.MaxConnsPerUser < 1 || *req.MaxConnsPerUser > 1000 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "每用户最大连接数范围 1-1000"})
|
||||
return
|
||||
}
|
||||
s.MaxConnsPerUser = *req.MaxConnsPerUser
|
||||
}
|
||||
|
||||
if err := db.DB.Save(&s).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存设置失败"})
|
||||
|
||||
@@ -14,6 +14,7 @@ type VpnSetting struct {
|
||||
AllowClientToClient bool `gorm:"default:false"`
|
||||
DoLocalIPConfig bool `gorm:"default:true"`
|
||||
DoRemoteIPConfig bool `gorm:"default:true"`
|
||||
MaxConnsPerUser int `gorm:"default:30"`
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,7 @@ const (
|
||||
writeTimeout = 10 * time.Second
|
||||
readyTimeout = 30 * time.Second
|
||||
pingPeriod = 30 * time.Second
|
||||
maxMessageSize = 1 << 20
|
||||
maxConnsPerUser = 3
|
||||
maxMessageSize = 1 << 20
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -99,7 +98,11 @@ func runTunnel(conn *websocket.Conn, user *model.User) {
|
||||
}
|
||||
|
||||
activeConnsMu.Lock()
|
||||
if activeConns[user.ID] >= maxConnsPerUser {
|
||||
maxConns := VPN.Settings().MaxConnsPerUser
|
||||
if maxConns <= 0 {
|
||||
maxConns = 30
|
||||
}
|
||||
if activeConns[user.ID] >= maxConns {
|
||||
activeConnsMu.Unlock()
|
||||
_ = sendJSON(conn, controlMessage{Type: "error", Message: "连接数已达上限"})
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user