diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index 06fcc594..a561ac7e 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -36,6 +36,7 @@ type RPCClient struct { httpCachePolicyClients []pb.HTTPCachePolicyServiceClient httpFirewallPolicyClients []pb.HTTPFirewallPolicyServiceClient httpLocationClients []pb.HTTPLocationServiceClient + httpWebsocketClients []pb.HTTPWebsocketServiceClient } func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { @@ -61,6 +62,7 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { httpCachePolicyClients := []pb.HTTPCachePolicyServiceClient{} httpFirewallPolicyClients := []pb.HTTPFirewallPolicyServiceClient{} httpLocationClients := []pb.HTTPLocationServiceClient{} + httpWebsocketClients := []pb.HTTPWebsocketServiceClient{} conns := []*grpc.ClientConn{} for _, endpoint := range apiConfig.RPC.Endpoints { @@ -94,6 +96,7 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { httpCachePolicyClients = append(httpCachePolicyClients, pb.NewHTTPCachePolicyServiceClient(conn)) httpFirewallPolicyClients = append(httpFirewallPolicyClients, pb.NewHTTPFirewallPolicyServiceClient(conn)) httpLocationClients = append(httpLocationClients, pb.NewHTTPLocationServiceClient(conn)) + httpWebsocketClients = append(httpWebsocketClients, pb.NewHTTPWebsocketServiceClient(conn)) } return &RPCClient{ @@ -116,6 +119,7 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { httpCachePolicyClients: httpCachePolicyClients, httpFirewallPolicyClients: httpFirewallPolicyClients, httpLocationClients: httpLocationClients, + httpWebsocketClients: httpWebsocketClients, }, nil } @@ -245,6 +249,13 @@ func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient { return nil } +func (this *RPCClient) HTTPWebsocketRPC() pb.HTTPWebsocketServiceClient { + if len(this.httpWebsocketClients) > 0 { + return this.httpWebsocketClients[rands.Int(0, len(this.httpWebsocketClients)-1)] + } + return nil +} + func (this *RPCClient) Context(adminId int64) context.Context { ctx := context.Background() m := maps.Map{ diff --git a/internal/web/actions/default/servers/server/settings/locations/locationutils/location_helper.go b/internal/web/actions/default/servers/server/settings/locations/locationutils/location_helper.go index 22d38344..b1c89687 100644 --- a/internal/web/actions/default/servers/server/settings/locations/locationutils/location_helper.go +++ b/internal/web/actions/default/servers/server/settings/locations/locationutils/location_helper.go @@ -54,84 +54,81 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString "isActive": secondMenuItem == "basic", }, } - menuItems = append(menuItems, maps.Map{ "name": "HTTP", "url": "/servers/server/settings/locations/http?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "http", }) - menuItems = append(menuItems, maps.Map{ "name": "Web设置", "url": "/servers/server/settings/locations/web?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "web", }) - menuItems = append(menuItems, maps.Map{ "name": "反向代理", "url": "/servers/server/settings/locations/reverseProxy?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "reverseProxy", }) - + menuItems = append(menuItems, maps.Map{ + "name": "重写规则", + "url": "/servers/server/settings/locations/rewrite?serverId=" + serverIdString + "&locationId=" + locationIdString, + "isActive": secondMenuItem == "rewrite", + }) menuItems = append(menuItems, maps.Map{ "name": "访问控制", "url": "/servers/server/settings/locations/access?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "access", }) - menuItems = append(menuItems, maps.Map{ "name": "WAF", "url": "/servers/server/settings/locations/waf?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "waf", }) - menuItems = append(menuItems, maps.Map{ "name": "缓存", "url": "/servers/server/settings/locations/cache?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "cache", }) - menuItems = append(menuItems, maps.Map{ "name": "-", "url": "", "isActive": false, }) - menuItems = append(menuItems, maps.Map{ "name": "字符编码", "url": "/servers/server/settings/locations/charset?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "charset", }) - menuItems = append(menuItems, maps.Map{ "name": "访问日志", "url": "/servers/server/settings/locations/accessLog?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "accessLog", }) - menuItems = append(menuItems, maps.Map{ "name": "统计", "url": "/servers/server/settings/locations/stat?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "stat", }) - menuItems = append(menuItems, maps.Map{ "name": "Gzip压缩", "url": "/servers/server/settings/locations/gzip?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "gzip", }) - menuItems = append(menuItems, maps.Map{ "name": "特殊页面", "url": "/servers/server/settings/locations/pages?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "pages", }) - menuItems = append(menuItems, maps.Map{ "name": "HTTP Header", "url": "/servers/server/settings/locations/headers?serverId=" + serverIdString + "&locationId=" + locationIdString, "isActive": secondMenuItem == "header", }) + menuItems = append(menuItems, maps.Map{ + "name": "Websocket", + "url": "/servers/server/settings/locations/websocket?serverId=" + serverIdString + "&locationId=" + locationIdString, + "isActive": secondMenuItem == "websocket", + }) return menuItems } diff --git a/internal/web/actions/default/servers/server/settings/locations/rewrite/index.go b/internal/web/actions/default/servers/server/settings/locations/rewrite/index.go new file mode 100644 index 00000000..4d481cf1 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/locations/rewrite/index.go @@ -0,0 +1,20 @@ +package rewrite + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { +} + +func (this *IndexAction) RunGet(params struct { + LocationId int64 +}) { + // TODO + + this.Show() +} diff --git a/internal/web/actions/default/servers/server/settings/locations/rewrite/init.go b/internal/web/actions/default/servers/server/settings/locations/rewrite/init.go new file mode 100644 index 00000000..e03b352c --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/locations/rewrite/init.go @@ -0,0 +1,21 @@ +package rewrite + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/locationutils" + "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()). + Helper(locationutils.NewLocationHelper()). + Helper(serverutils.NewServerHelper()). + Data("tinyMenuItem", "rewrite"). + Prefix("/servers/server/settings/locations/rewrite"). + Get("", new(IndexAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/servers/server/settings/locations/websocket/index.go b/internal/web/actions/default/servers/server/settings/locations/websocket/index.go new file mode 100644 index 00000000..58de11b9 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/locations/websocket/index.go @@ -0,0 +1,112 @@ +package websocket + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" + "github.com/iwind/TeaGo/actions" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + +} + +func (this *IndexAction) RunGet(params struct { + LocationId int64 +}) { + webConfig, err := webutils.FindWebConfigWithLocationId(this.Parent(), params.LocationId) + if err != nil { + this.ErrorPage(err) + return + } + + this.Data["webId"] = webConfig.Id + this.Data["websocketRef"] = webConfig.WebsocketRef + this.Data["websocketConfig"] = webConfig.Websocket + + this.Show() +} + +func (this *IndexAction) RunPost(params struct { + WebId int64 + WebsocketRefJSON []byte + WebsocketJSON []byte + + Must *actions.Must +}) { + // TODO 检查配置 + + websocketRef := &serverconfigs.HTTPWebsocketRef{} + err := json.Unmarshal(params.WebsocketRefJSON, websocketRef) + if err != nil { + this.ErrorPage(err) + return + } + + websocketConfig := &serverconfigs.HTTPWebsocketConfig{} + err = json.Unmarshal(params.WebsocketJSON, websocketConfig) + if err != nil { + this.ErrorPage(err) + return + } + err = websocketConfig.Init() + if err != nil { + this.ErrorPage(err) + return + } + + // 创建 + handshakeTimeoutJSON, err := json.Marshal(websocketConfig.HandshakeTimeout) + if err != nil { + this.ErrorPage(err) + return + } + + // 创建或修改 + if websocketConfig.Id <= 0 { + createResp, err := this.RPC().HTTPWebsocketRPC().CreateHTTPWebsocket(this.AdminContext(), &pb.CreateHTTPWebsocketRequest{ + HandshakeTimeoutJSON: handshakeTimeoutJSON, + AllowAllOrigins: websocketConfig.AllowAllOrigins, + AllowedOrigins: websocketConfig.AllowedOrigins, + RequestSameOrigin: websocketConfig.RequestSameOrigin, + RequestOrigin: websocketConfig.RequestOrigin, + }) + if err != nil { + this.ErrorPage(err) + return + } + websocketConfig.Id = createResp.WebsocketId + } else { + _, err = this.RPC().HTTPWebsocketRPC().UpdateHTTPWebsocket(this.AdminContext(), &pb.UpdateHTTPWebsocketRequest{ + WebsocketId: websocketConfig.Id, + HandshakeTimeoutJSON: handshakeTimeoutJSON, + AllowAllOrigins: websocketConfig.AllowAllOrigins, + AllowedOrigins: websocketConfig.AllowedOrigins, + RequestSameOrigin: websocketConfig.RequestSameOrigin, + RequestOrigin: websocketConfig.RequestOrigin, + }) + } + + websocketRef.WebsocketId = websocketConfig.Id + websocketRefJSON, err := json.Marshal(websocketRef) + if err != nil { + this.ErrorPage(err) + return + } + _, err = this.RPC().HTTPWebRPC().UpdateHTTPWebWebsocket(this.AdminContext(), &pb.UpdateHTTPWebWebsocketRequest{ + WebId: params.WebId, + WebsocketJSON: websocketRefJSON, + }) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/servers/server/settings/locations/websocket/init.go b/internal/web/actions/default/servers/server/settings/locations/websocket/init.go new file mode 100644 index 00000000..3c8c2d55 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/locations/websocket/init.go @@ -0,0 +1,21 @@ +package websocket + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/locationutils" + "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()). + Helper(locationutils.NewLocationHelper()). + Helper(serverutils.NewServerHelper()). + Data("tinyMenuItem", "websocket"). + Prefix("/servers/server/settings/locations/websocket"). + GetPost("", new(IndexAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/servers/server/settings/rewrite/index.go b/internal/web/actions/default/servers/server/settings/rewrite/index.go new file mode 100644 index 00000000..08cba790 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/rewrite/index.go @@ -0,0 +1,22 @@ +package rewrite + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + this.Nav("", "setting", "index") + this.SecondMenu("rewrite") +} + +func (this *IndexAction) RunGet(params struct { + ServerId int64 +}) { + // TODO + + this.Show() +} diff --git a/internal/web/actions/default/servers/server/settings/rewrite/init.go b/internal/web/actions/default/servers/server/settings/rewrite/init.go new file mode 100644 index 00000000..8d819f4b --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/rewrite/init.go @@ -0,0 +1,18 @@ +package rewrite + +import ( + "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()). + Helper(serverutils.NewServerHelper()). + Prefix("/servers/server/settings/rewrite"). + Get("", new(IndexAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/servers/server/settings/websocket/createOrigin.go b/internal/web/actions/default/servers/server/settings/websocket/createOrigin.go new file mode 100644 index 00000000..79279a2a --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/websocket/createOrigin.go @@ -0,0 +1,32 @@ +package websocket + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/iwind/TeaGo/actions" +) + +// 添加来源域 +type CreateOriginAction struct { + actionutils.ParentAction +} + +func (this *CreateOriginAction) Init() { + this.Nav("", "", "") +} + +func (this *CreateOriginAction) RunGet(params struct{}) { + this.Show() +} + +func (this *CreateOriginAction) RunPost(params struct { + Origin string + + Must *actions.Must +}) { + params.Must. + Field("origin", params.Origin). + Require("请输入域名") + + this.Data["origin"] = params.Origin + this.Success() +} diff --git a/web/public/js/components/server/http-websocket-box.js b/web/public/js/components/server/http-websocket-box.js new file mode 100644 index 00000000..b2913fda --- /dev/null +++ b/web/public/js/components/server/http-websocket-box.js @@ -0,0 +1,161 @@ +Vue.component("http-websocket-box", { + props: ["v-websocket-ref", "v-websocket-config", "v-is-location"], + data: function () { + let websocketRef = this.vWebsocketRef + if (websocketRef == null) { + websocketRef = { + isPrior: false, + isOn: true, + websocketId: 0 + } + } + + let websocketConfig = this.vWebsocketConfig + if (websocketConfig == null) { + websocketConfig = { + id: 0, + isOn: true, + handshakeTimeout: { + count: 30, + unit: "second" + }, + allowAllOrigins: true, + allowedOrigins: [], + requestSameOrigin: true, + requestOrigin: "" + } + } else { + if (websocketConfig.handshakeTimeout == null) { + websocketConfig.handshakeTimeout = { + count: 30, + unit: "second", + } + } + if (websocketConfig.allowedOrigins == null) { + websocketConfig.allowedOrigins = [] + } + } + + return { + websocketRef: websocketRef, + websocketConfig: websocketConfig, + handshakeTimeoutCountString: websocketConfig.handshakeTimeout.count.toString(), + advancedVisible: false + } + }, + watch: { + handshakeTimeoutCountString: function (v) { + let count = parseInt(v) + if (!isNaN(count) && count >= 0) { + this.websocketConfig.handshakeTimeout.count = count + } else { + this.websocketConfig.handshakeTimeout.count = 0 + } + } + }, + methods: { + isOn: function () { + return (!this.vIsLocation || this.websocketRef.isPrior) && this.websocketRef.isOn + }, + changeAdvancedVisible: function (v) { + this.advancedVisible = v + }, + createOrigin: function () { + let that = this + teaweb.popup("/servers/server/settings/websocket/createOrigin", { + height: "12.5em", + callback: function (resp) { + that.websocketConfig.allowedOrigins.push(resp.data.origin) + } + }) + }, + removeOrigin: function (index) { + this.websocketConfig.allowedOrigins.$remove(index) + } + }, + template: `
| 是否启用配置 | +
+					 
+						
+						
+					 
+				 | 
+			
| 允许所有来源域(Origin) | +
+					 
+						
+						
+					 
+					选中表示允许所有的来源域。 + | 
+			
| 允许的来源域列表(Origin) | +
+					
+					
+					 只允许在列表中的来源域名访问Websocket服务。 + | 
+			
| 是否传递请求来源域 | +
+					 
+						
+						
+					 
+					选中表示把接收到的请求中的Origin字段传递到源站。 + | 
+			
| 指定传递的来源域 | +
+					
+					 指定向源站传递的Origin字段值。 + | 
+			
| 握手超时时间(Handshake) | +
+					 
+						 
+					
+							
+						 
+						
+							秒
+						 
+					0表示使用默认的时间设置。 + | 
+