mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-12 19:30:26 +08:00
实现请求连接数等限制/容量组件增加EB支持
This commit is contained in:
@@ -18,7 +18,7 @@ func TestRPCClient_NodeRPC(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
rpc, err := NewRPCClient(config)
|
rpc, err := NewRPCClient(config, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ func TestRPC_Dial_HTTP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ func TestRPC_Dial_HTTPS(t *testing.T) {
|
|||||||
},
|
},
|
||||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,16 @@ func FormatInt(value int) string {
|
|||||||
return strconv.Itoa(value)
|
return strconv.Itoa(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Pow1024(n int) int64 {
|
||||||
|
if n <= 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if n == 1 {
|
||||||
|
return 1024
|
||||||
|
}
|
||||||
|
return Pow1024(n-1) * 1024
|
||||||
|
}
|
||||||
|
|
||||||
func FormatBytes(bytes int64) string {
|
func FormatBytes(bytes int64) string {
|
||||||
if bytes < 1024 {
|
if bytes < 1024 {
|
||||||
return FormatInt64(bytes) + "B"
|
return FormatInt64(bytes) + "B"
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package requestlimit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "setting", "index")
|
||||||
|
this.SecondMenu("requestLimit")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ServerId int64
|
||||||
|
}) {
|
||||||
|
this.Data["serverId"] = params.ServerId
|
||||||
|
|
||||||
|
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["webId"] = webConfig.Id
|
||||||
|
this.Data["requestLimitConfig"] = webConfig.RequestLimit
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunPost(params struct {
|
||||||
|
WebId int64
|
||||||
|
RequestLimitJSON []byte
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("修改Web %d 请求限制", params.WebId)
|
||||||
|
|
||||||
|
_, err := this.RPC().HTTPWebRPC().UpdateHTTPWebRequestLimit(this.AdminContext(), &pb.UpdateHTTPWebRequestLimitRequest{
|
||||||
|
HttpWebId: params.WebId,
|
||||||
|
RequestLimitJSON: params.RequestLimitJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package requestlimit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/serverutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||||
|
Helper(serverutils.NewServerHelper()).
|
||||||
|
Prefix("/servers/server/settings/requestLimit").
|
||||||
|
GetPost("", new(IndexAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -125,7 +125,17 @@ func (this *ServerHelper) createLeftMenu(action *actions.ActionObject) {
|
|||||||
case "stat":
|
case "stat":
|
||||||
action.Data["leftMenuItems"] = this.createStatMenu(types.String(secondMenuItem), serverIdString, serverConfig)
|
action.Data["leftMenuItems"] = this.createStatMenu(types.String(secondMenuItem), serverIdString, serverConfig)
|
||||||
case "setting":
|
case "setting":
|
||||||
action.Data["leftMenuItems"] = this.createSettingsMenu(types.String(secondMenuItem), serverIdString, serverConfig)
|
var menuItems = this.createSettingsMenu(types.String(secondMenuItem), serverIdString, serverConfig)
|
||||||
|
action.Data["leftMenuItems"] = menuItems
|
||||||
|
|
||||||
|
// 当前菜单
|
||||||
|
action.Data["leftMenuActiveItem"] = nil
|
||||||
|
for _, item := range menuItems {
|
||||||
|
if item.GetBool("isActive") {
|
||||||
|
action.Data["leftMenuActiveItem"] = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
case "delete":
|
case "delete":
|
||||||
action.Data["leftMenuItems"] = this.createDeleteMenu(types.String(secondMenuItem), serverIdString, serverConfig)
|
action.Data["leftMenuItems"] = this.createDeleteMenu(types.String(secondMenuItem), serverIdString, serverConfig)
|
||||||
}
|
}
|
||||||
@@ -354,6 +364,13 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
|
|||||||
"isOn": serverConfig.Web != nil && serverConfig.Web.RemoteAddr != nil && serverConfig.Web.RemoteAddr.IsOn,
|
"isOn": serverConfig.Web != nil && serverConfig.Web.RemoteAddr != nil && serverConfig.Web.RemoteAddr.IsOn,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
menuItems = append(menuItems, maps.Map{
|
||||||
|
"name": "请求限制",
|
||||||
|
"url": "/servers/server/settings/requestLimit?serverId=" + serverIdString,
|
||||||
|
"isActive": secondMenuItem == "requestLimit",
|
||||||
|
"isOn": serverConfig.Web != nil && serverConfig.Web.RequestLimit != nil && serverConfig.Web.RequestLimit.IsOn,
|
||||||
|
})
|
||||||
|
|
||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
menuItems = append(menuItems, maps.Map{
|
menuItems = append(menuItems, maps.Map{
|
||||||
"name": "流量限制",
|
"name": "流量限制",
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/pages"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/pages"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/redirects"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/redirects"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/remoteAddr"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/remoteAddr"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/requestLimit"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/reverseProxy"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/reverseProxy"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/rewrite"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/rewrite"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/serverNames"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/serverNames"
|
||||||
|
|||||||
@@ -2723,6 +2723,105 @@ Vue.component("http-cache-ref-box", {
|
|||||||
</tbody>`
|
</tbody>`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 请求限制
|
||||||
|
Vue.component("http-request-limit-config-box", {
|
||||||
|
props: ["v-request-limit-config"],
|
||||||
|
data: function () {
|
||||||
|
let config = this.vRequestLimitConfig
|
||||||
|
if (config == null) {
|
||||||
|
config = {
|
||||||
|
isPrior: false,
|
||||||
|
isOn: false,
|
||||||
|
maxConns: 0,
|
||||||
|
maxConnsPerIP: 0,
|
||||||
|
maxBodySize: {
|
||||||
|
count: -1,
|
||||||
|
unit: "kb"
|
||||||
|
},
|
||||||
|
outBandwidthPerConn: {
|
||||||
|
count: -1,
|
||||||
|
unit: "kb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
config: config,
|
||||||
|
maxConns: config.maxConns,
|
||||||
|
maxConnsPerIP: config.maxConnsPerIP
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
maxConns: function (v) {
|
||||||
|
let conns = parseInt(v, 10)
|
||||||
|
if (isNaN(conns)) {
|
||||||
|
this.config.maxConns = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (conns < 0) {
|
||||||
|
this.config.maxConns = 0
|
||||||
|
} else {
|
||||||
|
this.config.maxConns = conns
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxConnsPerIP: function (v) {
|
||||||
|
let conns = parseInt(v, 10)
|
||||||
|
if (isNaN(conns)) {
|
||||||
|
this.config.maxConnsPerIP = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (conns < 0) {
|
||||||
|
this.config.maxConnsPerIP = 0
|
||||||
|
} else {
|
||||||
|
this.config.maxConnsPerIP = conns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="requestLimitJSON" :value="JSON.stringify(config)"/>
|
||||||
|
<table class="ui table selectable definition">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="title">是否启用</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="config.isOn"></checkbox>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tbody v-show="config.isOn">
|
||||||
|
<tr>
|
||||||
|
<td>最大并发连接数</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" maxlength="6" v-model="maxConns"/>
|
||||||
|
<p class="comment">为0表示不限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单IP最大并发连接数</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
||||||
|
<p class="comment">为0表示不限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单连接带宽限制</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-box :v-value="config.outBandwidthPerConn" :v-supported-units="['byte', 'kb', 'mb']"></size-capacity-box>
|
||||||
|
<p class="comment">客户端单个请求每秒可以读取的下行流量。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单请求最大尺寸</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-box :v-value="config.maxBodySize" :v-supported-units="['byte', 'kb', 'mb', 'gb']"></size-capacity-box>
|
||||||
|
<p class="comment">单个请求能发送的最大内容尺寸。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="margin"></div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
|
|
||||||
// 浏览条件列表
|
// 浏览条件列表
|
||||||
Vue.component("http-request-conds-view", {
|
Vue.component("http-request-conds-view", {
|
||||||
props: ["v-conds"],
|
props: ["v-conds"],
|
||||||
@@ -5976,7 +6075,7 @@ Vue.component("http-pages-and-shutdown-box", {
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p class="comment">开启临时关闭页面时,所有请求的响应都会显示此页面。可用于临时升级网站使用。</p>
|
<p class="comment">开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。</p>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -6428,6 +6527,7 @@ Vue.component("http-expires-time-config-box", {
|
|||||||
<td>强制缓存时间</td>
|
<td>强制缓存时间</td>
|
||||||
<td>
|
<td>
|
||||||
<time-duration-box :v-value="expiresTime.duration" @change="notifyChange"></time-duration-box>
|
<time-duration-box :v-value="expiresTime.duration" @change="notifyChange"></time-duration-box>
|
||||||
|
<p class="comment">从客户端访问的时间开始要缓存的时长。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -11108,7 +11208,7 @@ Vue.component("source-code-box", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("size-capacity-box", {
|
Vue.component("size-capacity-box", {
|
||||||
props: ["v-name", "v-value", "v-count", "v-unit", "size", "maxlength"],
|
props: ["v-name", "v-value", "v-count", "v-unit", "size", "maxlength", "v-supported-units"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let v = this.vValue
|
let v = this.vValue
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
@@ -11131,11 +11231,17 @@ Vue.component("size-capacity-box", {
|
|||||||
vMaxlength = 10
|
vMaxlength = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let supportedUnits = this.vSupportedUnits
|
||||||
|
if (supportedUnits == null) {
|
||||||
|
supportedUnits = []
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
capacity: v,
|
capacity: v,
|
||||||
countString: (v.count >= 0) ? v.count.toString() : "",
|
countString: (v.count >= 0) ? v.count.toString() : "",
|
||||||
vSize: vSize,
|
vSize: vSize,
|
||||||
vMaxlength: vMaxlength
|
vMaxlength: vMaxlength,
|
||||||
|
supportedUnits: supportedUnits
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -11165,12 +11271,13 @@ Vue.component("size-capacity-box", {
|
|||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<select class="ui dropdown" v-model="capacity.unit" @change="change">
|
<select class="ui dropdown" v-model="capacity.unit" @change="change">
|
||||||
<option value="byte">字节</option>
|
<option value="byte" v-if="supportedUnits.length == 0 || supportedUnits.$contains('byte')">字节</option>
|
||||||
<option value="kb">KB</option>
|
<option value="kb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('kb')">KB</option>
|
||||||
<option value="mb">MB</option>
|
<option value="mb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('mb')">MB</option>
|
||||||
<option value="gb">GB</option>
|
<option value="gb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('gb')">GB</option>
|
||||||
<option value="tb">TB</option>
|
<option value="tb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('tb')">TB</option>
|
||||||
<option value="pb">PB</option>
|
<option value="pb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('pb')">PB</option>
|
||||||
|
<option value="eb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('eb')">EB</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Vue.component("size-capacity-box", {
|
Vue.component("size-capacity-box", {
|
||||||
props: ["v-name", "v-value", "v-count", "v-unit", "size", "maxlength"],
|
props: ["v-name", "v-value", "v-count", "v-unit", "size", "maxlength", "v-supported-units"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let v = this.vValue
|
let v = this.vValue
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
@@ -22,11 +22,17 @@ Vue.component("size-capacity-box", {
|
|||||||
vMaxlength = 10
|
vMaxlength = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let supportedUnits = this.vSupportedUnits
|
||||||
|
if (supportedUnits == null) {
|
||||||
|
supportedUnits = []
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
capacity: v,
|
capacity: v,
|
||||||
countString: (v.count >= 0) ? v.count.toString() : "",
|
countString: (v.count >= 0) ? v.count.toString() : "",
|
||||||
vSize: vSize,
|
vSize: vSize,
|
||||||
vMaxlength: vMaxlength
|
vMaxlength: vMaxlength,
|
||||||
|
supportedUnits: supportedUnits
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -56,12 +62,13 @@ Vue.component("size-capacity-box", {
|
|||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<select class="ui dropdown" v-model="capacity.unit" @change="change">
|
<select class="ui dropdown" v-model="capacity.unit" @change="change">
|
||||||
<option value="byte">字节</option>
|
<option value="byte" v-if="supportedUnits.length == 0 || supportedUnits.$contains('byte')">字节</option>
|
||||||
<option value="kb">KB</option>
|
<option value="kb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('kb')">KB</option>
|
||||||
<option value="mb">MB</option>
|
<option value="mb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('mb')">MB</option>
|
||||||
<option value="gb">GB</option>
|
<option value="gb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('gb')">GB</option>
|
||||||
<option value="tb">TB</option>
|
<option value="tb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('tb')">TB</option>
|
||||||
<option value="pb">PB</option>
|
<option value="pb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('pb')">PB</option>
|
||||||
|
<option value="eb" v-if="supportedUnits.length == 0 || supportedUnits.$contains('eb')">EB</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ Vue.component("http-pages-and-shutdown-box", {
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p class="comment">开启临时关闭页面时,所有请求的响应都会显示此页面。可用于临时升级网站使用。</p>
|
<p class="comment">开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。</p>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// 请求限制
|
||||||
|
Vue.component("http-request-limit-config-box", {
|
||||||
|
props: ["v-request-limit-config"],
|
||||||
|
data: function () {
|
||||||
|
let config = this.vRequestLimitConfig
|
||||||
|
if (config == null) {
|
||||||
|
config = {
|
||||||
|
isPrior: false,
|
||||||
|
isOn: false,
|
||||||
|
maxConns: 0,
|
||||||
|
maxConnsPerIP: 0,
|
||||||
|
maxBodySize: {
|
||||||
|
count: -1,
|
||||||
|
unit: "kb"
|
||||||
|
},
|
||||||
|
outBandwidthPerConn: {
|
||||||
|
count: -1,
|
||||||
|
unit: "kb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
config: config,
|
||||||
|
maxConns: config.maxConns,
|
||||||
|
maxConnsPerIP: config.maxConnsPerIP
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
maxConns: function (v) {
|
||||||
|
let conns = parseInt(v, 10)
|
||||||
|
if (isNaN(conns)) {
|
||||||
|
this.config.maxConns = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (conns < 0) {
|
||||||
|
this.config.maxConns = 0
|
||||||
|
} else {
|
||||||
|
this.config.maxConns = conns
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxConnsPerIP: function (v) {
|
||||||
|
let conns = parseInt(v, 10)
|
||||||
|
if (isNaN(conns)) {
|
||||||
|
this.config.maxConnsPerIP = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (conns < 0) {
|
||||||
|
this.config.maxConnsPerIP = 0
|
||||||
|
} else {
|
||||||
|
this.config.maxConnsPerIP = conns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="requestLimitJSON" :value="JSON.stringify(config)"/>
|
||||||
|
<table class="ui table selectable definition">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="title">是否启用</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="config.isOn"></checkbox>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tbody v-show="config.isOn">
|
||||||
|
<tr>
|
||||||
|
<td>最大并发连接数</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" maxlength="6" v-model="maxConns"/>
|
||||||
|
<p class="comment">为0表示不限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单IP最大并发连接数</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
||||||
|
<p class="comment">为0表示不限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单连接带宽限制</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-box :v-value="config.outBandwidthPerConn" :v-supported-units="['byte', 'kb', 'mb']"></size-capacity-box>
|
||||||
|
<p class="comment">客户端单个请求每秒可以读取的下行流量。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单请求最大尺寸</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-box :v-value="config.maxBodySize" :v-supported-units="['byte', 'kb', 'mb', 'gb']"></size-capacity-box>
|
||||||
|
<p class="comment">单个请求能发送的最大内容尺寸。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="margin"></div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -116,22 +116,25 @@ window.teaweb = {
|
|||||||
|
|
||||||
formatBytes: function (bytes) {
|
formatBytes: function (bytes) {
|
||||||
bytes = Math.ceil(bytes);
|
bytes = Math.ceil(bytes);
|
||||||
if (bytes < 1024) {
|
if (bytes < Math.pow(1024, 1)) {
|
||||||
return bytes + "B";
|
return bytes + "B";
|
||||||
}
|
}
|
||||||
if (bytes < 1024 * 1024) {
|
if (bytes < Math.pow(1024, 2)) {
|
||||||
return (Math.round(bytes * 100 / 1024) / 100) + "K";
|
return (Math.round(bytes * 100 / Math.pow(1024, 1)) / 100) + "KB";
|
||||||
}
|
}
|
||||||
if (bytes < 1024 * 1024 * 1024) {
|
if (bytes < Math.pow(1024, 3)) {
|
||||||
return (Math.round(bytes * 100 / 1024 / 1024) / 100) + "M";
|
return (Math.round(bytes * 100 / Math.pow(1024, 2)) / 100) + "MB";
|
||||||
}
|
}
|
||||||
if (bytes < 1024 * 1024 * 1024 * 1024) {
|
if (bytes < Math.pow(1024, 4)) {
|
||||||
return (Math.round(bytes * 100 / 1024 / 1024 / 1024) / 100) + "G";
|
return (Math.round(bytes * 100 / Math.pow(1024, 3)) / 100) + "GB";
|
||||||
}
|
}
|
||||||
if (bytes < 1024 * 1024 * 1024 * 1024 * 1024) {
|
if (bytes < Math.pow(1024, 5)) {
|
||||||
return (Math.round(bytes * 100 / 1024 / 1024 / 1024 / 1024) / 100) + "T";
|
return (Math.round(bytes * 100 / Math.pow(1024, 4)) / 100) + "TB";
|
||||||
}
|
}
|
||||||
return (Math.round(bytes * 100 / 1024 / 1024 / 1024 / 1024 / 1024) / 100) + "P";
|
if (bytes < Math.pow(1024, 6)) {
|
||||||
|
return (Math.round(bytes * 100 / Math.pow(1024, 5)) / 100) + "PB";
|
||||||
|
}
|
||||||
|
return (Math.round(bytes * 100 / Math.pow(1024, 6)) / 100) + "EB";
|
||||||
},
|
},
|
||||||
formatNumber: function (x) {
|
formatNumber: function (x) {
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
@@ -178,18 +181,24 @@ window.teaweb = {
|
|||||||
let max = Math.max.apply(this, stats.map(countFunc))
|
let max = Math.max.apply(this, stats.map(countFunc))
|
||||||
let divider = 1
|
let divider = 1
|
||||||
let unit = ""
|
let unit = ""
|
||||||
if (max >= 1024 * 1024 * 1024 * 1024) {
|
if (max >= Math.pow(1024, 6)) {
|
||||||
unit = "T"
|
unit = "EB"
|
||||||
divider = 1024 * 1024 * 1024 * 1024
|
divider = Math.pow(1024, 6)
|
||||||
} else if (max >= 1024 * 1024 * 1024) {
|
} else if (max >= Math.pow(1024, 5)) {
|
||||||
unit = "G"
|
unit = "PB"
|
||||||
divider = 1024 * 1024 * 1024
|
divider = Math.pow(1024, 5)
|
||||||
} else if (max >= 1024 * 1024) {
|
} else if (max >= Math.pow(1024, 4)) {
|
||||||
unit = "M"
|
unit = "TB"
|
||||||
divider = 1024 * 1024
|
divider = Math.pow(1024, 4)
|
||||||
} else if (max >= 1024) {
|
} else if (max >= Math.pow(1024, 3)) {
|
||||||
unit = "K"
|
unit = "GB"
|
||||||
divider = 1024
|
divider = Math.pow(1024, 3)
|
||||||
|
} else if (max >= Math.pow(1024, 2)) {
|
||||||
|
unit = "MB"
|
||||||
|
divider = Math.pow(1024, 2)
|
||||||
|
} else if (max >= Math.pow(1024, 1)) {
|
||||||
|
unit = "KB"
|
||||||
|
divider = Math.pow(1024, 1)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
unit: unit,
|
unit: unit,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<first-menu>
|
<first-menu>
|
||||||
<menu-item href="/servers">服务列表</menu-item>
|
<menu-item href="/servers">服务列表</menu-item>
|
||||||
<span class="item disabled">|</span>
|
<span class="item disabled">|</span>
|
||||||
<menu-item :href="'/servers/server/settings?serverId=' + server.id" active="true">"{{server.name}}"设置</menu-item>
|
<menu-item :href="'/servers/server/settings?serverId=' + server.id" :active="leftMenuActiveItem == null">"{{server.name}}"设置</menu-item>
|
||||||
<span class="disabled item">|</span>
|
<span class="disabled item">»</span>
|
||||||
|
<a class="item active" v-if="leftMenuActiveItem != null" :href="leftMenuActiveItem.url">"{{leftMenuActiveItem.name}}"设置</a>
|
||||||
|
<span class="disabled item" v-if="leftMenuActiveItem != null">|</span>
|
||||||
<more-items-angle
|
<more-items-angle
|
||||||
:v-data-url="'/servers/nearby?serverId=' + server.id"
|
:v-data-url="'/servers/nearby?serverId=' + server.id"
|
||||||
:v-url="'/servers/server/settings?serverId=${serverId}'"></more-items-angle>
|
:v-url="'/servers/server/settings?serverId=${serverId}'"></more-items-angle>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Tea.context(function () {
|
|||||||
this.success = NotifySuccess("添加成功", "/servers/server/settings/locations?serverId=" + this.serverId)
|
this.success = NotifySuccess("添加成功", "/servers/server/settings/locations?serverId=" + this.serverId)
|
||||||
|
|
||||||
this.type = 1
|
this.type = 1
|
||||||
this.selectedType = null
|
this.selectedType = this.patternTypes[0]
|
||||||
|
|
||||||
|
|
||||||
this.changePatternType = function (type) {
|
this.changePatternType = function (type) {
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "../settings_menu"}
|
||||||
|
{$template "/left_menu_with_menu"}
|
||||||
|
|
||||||
|
<div class="right-box with-menu">
|
||||||
|
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<input type="hidden" name="webId" :value="webId"/>
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
|
||||||
|
<http-request-limit-config-box :v-request-limit-config="requestLimitConfig"></http-request-limit-config-box>
|
||||||
|
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifyReloadSuccess("保存成功")
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user