diff --git a/internal/web/actions/default/servers/server/settings/conds/addCondPopup.go b/internal/web/actions/default/servers/server/settings/conds/addCondPopup.go new file mode 100644 index 00000000..0235bf10 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/conds/addCondPopup.go @@ -0,0 +1,39 @@ +package conds + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" + "github.com/iwind/TeaGo/actions" +) + +type AddCondPopupAction struct { + actionutils.ParentAction +} + +func (this *AddCondPopupAction) Init() { +} + +func (this *AddCondPopupAction) RunGet(params struct{}) { + this.Data["components"] = condutils.ReadAllAvailableCondTypes() + + this.Show() +} + +func (this *AddCondPopupAction) RunPost(params struct { + CondType string + CondJSON []byte + + Must *actions.Must +}) { + condConfig := &shared.HTTPRequestCond{} + err := json.Unmarshal(params.CondJSON, condConfig) + if err != nil { + this.Fail("解析条件设置时发生了错误:" + err.Error()) + } + condConfig.Type = params.CondType + + this.Data["cond"] = condConfig + this.Success() +} diff --git a/internal/web/actions/default/servers/server/settings/conds/addGroupPopup.go b/internal/web/actions/default/servers/server/settings/conds/addGroupPopup.go new file mode 100644 index 00000000..b23ce5a6 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/conds/addGroupPopup.go @@ -0,0 +1,37 @@ +package conds + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" + "github.com/iwind/TeaGo/actions" +) + +type AddGroupPopupAction struct { + actionutils.ParentAction +} + +func (this *AddGroupPopupAction) Init() { +} + +func (this *AddGroupPopupAction) RunGet(params struct{}) { + this.Data["components"] = condutils.ReadAllAvailableCondTypes() + + this.Show() +} + +func (this *AddGroupPopupAction) RunPost(params struct { + CondGroupJSON []byte + + Must *actions.Must +}) { + groupConfig := &shared.HTTPRequestCondGroup{} + err := json.Unmarshal(params.CondGroupJSON, groupConfig) + if err != nil { + this.Fail("解析条件时发生错误:" + err.Error()) + } + + this.Data["group"] = groupConfig + this.Success() +} diff --git a/internal/web/actions/default/servers/server/settings/conds/condutils/utils.go b/internal/web/actions/default/servers/server/settings/conds/condutils/utils.go new file mode 100644 index 00000000..ed727954 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/conds/condutils/utils.go @@ -0,0 +1,48 @@ +package condutils + +import ( + "encoding/json" + "github.com/iwind/TeaGo/Tea" + _ "github.com/iwind/TeaGo/bootstrap" + "github.com/iwind/TeaGo/files" + "github.com/iwind/TeaGo/logs" + "path/filepath" +) + +type CondJSComponent struct { + Type string `json:"type"` + Name string `json:"name"` + Description string `json:"description"` + Component string `json:"component"` +} + +// 读取所有可用的条件 +func ReadAllAvailableCondTypes() []*CondJSComponent { + result := []*CondJSComponent{} + + dir := Tea.Root + "/web/" + if Tea.IsTesting() { + dir = filepath.Dir(Tea.Root) + "/web" + } + dir += "/public/js/conds/" + jsonFiles := files.NewFile(dir).List() + for _, file := range jsonFiles { + if file.Ext() == ".json" { + data, err := file.ReadAll() + if err != nil { + logs.Println("[COND]read data from json file: " + err.Error()) + continue + } + + c := []*CondJSComponent{} + err = json.Unmarshal(data, &c) + if err != nil { + logs.Println("[COND]decode json failed: " + err.Error()) + continue + } + result = append(result, c...) + } + } + + return result +} diff --git a/internal/web/actions/default/servers/server/settings/conds/condutils/utils_test.go b/internal/web/actions/default/servers/server/settings/conds/condutils/utils_test.go new file mode 100644 index 00000000..1c12ee6f --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/conds/condutils/utils_test.go @@ -0,0 +1,7 @@ +package condutils + +import "testing" + +func TestReadAllAvailableCondTypes(t *testing.T) { + t.Log(ReadAllAvailableCondTypes()) +} diff --git a/internal/web/actions/default/servers/server/settings/conds/init.go b/internal/web/actions/default/servers/server/settings/conds/init.go new file mode 100644 index 00000000..cdaf2dd0 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/conds/init.go @@ -0,0 +1,17 @@ +package conds + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" + "github.com/iwind/TeaGo" +) + +func init() { + TeaGo.BeforeStart(func(server *TeaGo.Server) { + server. + Helper(helpers.NewUserMustAuth()). + Prefix("/servers/server/settings/conds"). + GetPost("/addGroupPopup", new(AddGroupPopupAction)). + GetPost("/addCondPopup", new(AddCondPopupAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/servers/server/settings/gzip/index.go b/internal/web/actions/default/servers/server/settings/gzip/index.go index 9576f7a6..936fb6f0 100644 --- a/internal/web/actions/default/servers/server/settings/gzip/index.go +++ b/internal/web/actions/default/servers/server/settings/gzip/index.go @@ -66,11 +66,12 @@ func (this *IndexAction) RunGet(params struct { } func (this *IndexAction) RunPost(params struct { - WebId int64 - GzipId int64 - Level int - MinLength string - MaxLength string + WebId int64 + GzipId int64 + Level int + MinLength string + MaxLength string + CondGroupsJSON []byte Must *actions.Must }) { @@ -98,10 +99,11 @@ func (this *IndexAction) RunPost(params struct { if params.GzipId > 0 { _, err := this.RPC().HTTPGzipRPC().UpdateHTTPGzip(this.AdminContext(), &pb.UpdateHTTPGzipRequest{ - GzipId: params.GzipId, - Level: types.Int32(params.Level), - MinLength: minLength, - MaxLength: maxLength, + GzipId: params.GzipId, + Level: types.Int32(params.Level), + MinLength: minLength, + MaxLength: maxLength, + CondGroupsJSON: params.CondGroupsJSON, }) if err != nil { this.ErrorPage(err) @@ -109,9 +111,10 @@ func (this *IndexAction) RunPost(params struct { } } else { resp, err := this.RPC().HTTPGzipRPC().CreateHTTPGzip(this.AdminContext(), &pb.CreateHTTPGzipRequest{ - Level: types.Int32(params.Level), - MinLength: minLength, - MaxLength: maxLength, + Level: types.Int32(params.Level), + MinLength: minLength, + MaxLength: maxLength, + CondGroupsJSON: params.CondGroupsJSON, }) if err != nil { this.ErrorPage(err) diff --git a/internal/web/actions/default/ui/components.go b/internal/web/actions/default/ui/components.go index ccbdd074..a135ff38 100644 --- a/internal/web/actions/default/ui/components.go +++ b/internal/web/actions/default/ui/components.go @@ -1,7 +1,8 @@ package ui import ( - "bytes" + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils" "github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/files" @@ -21,7 +22,6 @@ func (this *ComponentsAction) RunGet(params struct{}) { } f := files.NewFile(webRoot) - buf := bytes.NewBuffer([]byte{}) f.Range(func(file *files.File) { if !file.IsFile() { return @@ -34,9 +34,17 @@ func (this *ComponentsAction) RunGet(params struct{}) { logs.Error(err) return } - buf.Write(data) - buf.WriteByte('\n') - buf.WriteByte('\n') + this.Write(data) + this.Write([]byte{'\n', '\n'}) }) - this.Write(buf.Bytes()) + + // 条件组件 + typesJSON, err := json.Marshal(condutils.ReadAllAvailableCondTypes()) + if err != nil { + logs.Println("ComponentsAction: " + err.Error()) + } else { + this.WriteString("window.REQUEST_COND_COMPONENTS = ") + this.Write(typesJSON) + this.Write([]byte{'\n', '\n'}) + } } diff --git a/internal/web/import.go b/internal/web/import.go index 082466af..adda6b87 100644 --- a/internal/web/import.go +++ b/internal/web/import.go @@ -30,6 +30,7 @@ import ( _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/accessLog" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/cache" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/charset" + _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/gzip" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/headers" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/http" diff --git a/web/public/js/components/common/more-options-indicator.js b/web/public/js/components/common/more-options-indicator.js index 754431a9..b7dd48f1 100644 --- a/web/public/js/components/common/more-options-indicator.js +++ b/web/public/js/components/common/more-options-indicator.js @@ -15,5 +15,5 @@ Vue.component("more-options-indicator", { } } }, - template: '更多选项 ' + template: '更多选项收起选项 ' }); \ No newline at end of file diff --git a/web/public/js/components/server/http-cond-definitions.js b/web/public/js/components/server/http-cond-definitions.js new file mode 100644 index 00000000..f381d35d --- /dev/null +++ b/web/public/js/components/server/http-cond-definitions.js @@ -0,0 +1,157 @@ +// URL扩展名条件 +Vue.component("http-cond-url-extension", { + props: ["v-cond"], + data: function () { + let cond = this.vCond + if (cond == null) { + cond = { + param: "${requestPathExtension}", + operator: "in", + value: "[]" + } + } + return { + cond: cond, + extensions: JSON.parse(cond.value), // TODO 可以拖动排序 + + isAdding: false, + addingExt: "" + } + }, + watch: { + extensions: function () { + this.cond.value = JSON.stringify(this.extensions) + } + }, + methods: { + addExt: function () { + this.isAdding = !this.isAdding + + if (this.isAdding) { + let that = this + setTimeout(function () { + that.$refs.addingExt.focus() + }, 100) + } + }, + cancelAdding: function () { + this.isAdding = false + this.addingExt = "" + }, + confirmAdding: function () { + // TODO 做更详细的校验 + // TODO 如果有重复的则提示之 + + if (this.addingExt.length == 0) { + return + } + if (this.addingExt[0] != ".") { + this.addingExt = "." + this.addingExt + } + this.addingExt = this.addingExt.replace(/\s+/g, "") + this.extensions.push(this.addingExt) + + // 清除状态 + this.cancelAdding() + }, + removeExt: function (index) { + this.extensions.$remove(index) + } + }, + template: `
` +}) + +// 根据MimeType +Vue.component("http-cond-mime-type", { + props: ["v-cond"], + data: function () { + let cond = this.vCond + if (cond == null) { + cond = { + type: "mime-type", + param: "${response.contentType}", + operator: "mime type", + value: "[]" + } + } + return { + cond: cond, + mimeTypes: JSON.parse(cond.value), // TODO 可以拖动排序 + + isAdding: false, + addingMimeType: "" + } + }, + watch: { + mimeTypes: function () { + this.cond.value = JSON.stringify(this.mimeTypes) + } + }, + methods: { + addMimeType: function () { + this.isAdding = !this.isAdding + + if (this.isAdding) { + let that = this + setTimeout(function () { + that.$refs.addingMimeType.focus() + }, 100) + } + }, + cancelAdding: function () { + this.isAdding = false + this.addingMimeType = "" + }, + confirmAdding: function () { + // TODO 做更详细的校验 + // TODO 如果有重复的则提示之 + + if (this.addingMimeType.length == 0) { + return + } + this.addingMimeType = this.addingMimeType.replace(/\s+/g, "") + this.mimeTypes.push(this.addingMimeType) + + // 清除状态 + this.cancelAdding() + }, + removeMimeType: function (index) { + this.mimeTypes.$remove(index) + } + }, + template: `` +}) \ No newline at end of file diff --git a/web/public/js/components/server/http-gzip-box.js b/web/public/js/components/server/http-gzip-box.js index 8192ee14..3f3a1d84 100644 --- a/web/public/js/components/server/http-gzip-box.js +++ b/web/public/js/components/server/http-gzip-box.js @@ -7,17 +7,22 @@ Vue.component("http-gzip-box", { isOn: true, level: 0, minLength: null, - maxLength: null + maxLength: null, + condGroups: [] } } return { gzip: gzip, + advancedVisible: false } }, methods: { isOn: function () { return (!this.vIsLocation || this.vGzipRef.isPrior) && this.vGzipRef.isOn + }, + changeAdvancedVisible: function (v) { + this.advancedVisible = v } }, template: `级别越高,压缩比例越大。
| + + + {{cond.param}} {{cond.operator}} + {{typeName(cond)}}: + {{cond.value}} + + + {{group.connector}} + + | ++ + | +