diff --git a/internal/rpc/rpc_client_test.go b/internal/rpc/rpc_client_test.go index 1fa59d64..d0cb2361 100644 --- a/internal/rpc/rpc_client_test.go +++ b/internal/rpc/rpc_client_test.go @@ -18,7 +18,7 @@ func TestRPCClient_NodeRPC(t *testing.T) { if err != nil { t.Fatal(err) } - rpc, err := NewRPCClient(config) + rpc, err := NewRPCClient(config, true) if err != nil { t.Fatal(err) } @@ -41,7 +41,7 @@ func TestRPC_Dial_HTTP(t *testing.T) { }, NodeId: "a7e55782dab39bce0901058a1e14a0e6", Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y", - }) + }, true) if err != nil { t.Fatal(err) } @@ -62,7 +62,7 @@ func TestRPC_Dial_HTTP_2(t *testing.T) { }, NodeId: "a7e55782dab39bce0901058a1e14a0e6", Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y", - }) + }, true) if err != nil { t.Fatal(err) } @@ -83,7 +83,7 @@ func TestRPC_Dial_HTTPS(t *testing.T) { }, NodeId: "a7e55782dab39bce0901058a1e14a0e6", Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y", - }) + }, true) if err != nil { t.Fatal(err) } diff --git a/internal/utils/numberutils/utils.go b/internal/utils/numberutils/utils.go index 71bfd4ed..ee3e5618 100644 --- a/internal/utils/numberutils/utils.go +++ b/internal/utils/numberutils/utils.go @@ -13,6 +13,16 @@ func FormatInt(value int) string { 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 { if bytes < 1024 { return FormatInt64(bytes) + "B" diff --git a/internal/web/actions/default/servers/server/settings/requestLimit/index.go b/internal/web/actions/default/servers/server/settings/requestLimit/index.go new file mode 100644 index 00000000..4e60fa7c --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/requestLimit/index.go @@ -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() +} diff --git a/internal/web/actions/default/servers/server/settings/requestLimit/init.go b/internal/web/actions/default/servers/server/settings/requestLimit/init.go new file mode 100644 index 00000000..dbd09811 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/requestLimit/init.go @@ -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() + }) +} diff --git a/internal/web/actions/default/servers/serverutils/server_helper.go b/internal/web/actions/default/servers/serverutils/server_helper.go index a05e8429..427e164b 100644 --- a/internal/web/actions/default/servers/serverutils/server_helper.go +++ b/internal/web/actions/default/servers/serverutils/server_helper.go @@ -125,7 +125,17 @@ func (this *ServerHelper) createLeftMenu(action *actions.ActionObject) { case "stat": action.Data["leftMenuItems"] = this.createStatMenu(types.String(secondMenuItem), serverIdString, serverConfig) 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": 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, }) + 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 { menuItems = append(menuItems, maps.Map{ "name": "流量限制", diff --git a/internal/web/import.go b/internal/web/import.go index 9f3f6778..48afff1e 100644 --- a/internal/web/import.go +++ b/internal/web/import.go @@ -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/redirects" _ "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/rewrite" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/serverNames" diff --git a/web/public/js/components.js b/web/public/js/components.js index e2ea7658..b43a9e78 100755 --- a/web/public/js/components.js +++ b/web/public/js/components.js @@ -2723,6 +2723,105 @@ Vue.component("http-cache-ref-box", { ` }) +// 请求限制 +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: `
| 是否启用 | +
+ |
+
| 最大并发连接数 | +
+
+ 为0表示不限制。 + |
+
| 单IP最大并发连接数 | +
+
+ 为0表示不限制。 + |
+
| 单连接带宽限制 | +
+ 客户端单个请求每秒可以读取的下行流量。 + |
+
| 单请求最大尺寸 | +
+ 单个请求能发送的最大内容尺寸。 + |
+
开启临时关闭页面时,所有请求的响应都会显示此页面。可用于临时升级网站使用。
+开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。
@@ -6428,6 +6527,7 @@ Vue.component("http-expires-time-config-box", {从客户端访问的时间开始要缓存的时长。
开启临时关闭页面时,所有请求的响应都会显示此页面。可用于临时升级网站使用。
+开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。
diff --git a/web/public/js/components/server/http-request-limit-config-box.js b/web/public/js/components/server/http-request-limit-config-box.js new file mode 100644 index 00000000..1f8813ea --- /dev/null +++ b/web/public/js/components/server/http-request-limit-config-box.js @@ -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: `| 是否启用 | +
+ |
+
| 最大并发连接数 | +
+
+ 为0表示不限制。 + |
+
| 单IP最大并发连接数 | +
+
+ 为0表示不限制。 + |
+
| 单连接带宽限制 | +
+ 客户端单个请求每秒可以读取的下行流量。 + |
+
| 单请求最大尺寸 | +
+ 单个请求能发送的最大内容尺寸。 + |
+