diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index 1b3dea69..56152c23 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -13,9 +13,11 @@ import ( "github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/rands" "google.golang.org/grpc" + "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" "net/url" + "sync" "time" ) @@ -23,6 +25,8 @@ import ( type RPCClient struct { apiConfig *configs.APIConfig conns []*grpc.ClientConn + + locker sync.Mutex } // 构造新的RPC客户端 @@ -31,35 +35,16 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { return nil, errors.New("api config should not be nil") } - conns := []*grpc.ClientConn{} - for _, endpoint := range apiConfig.RPC.Endpoints { - u, err := url.Parse(endpoint) - if err != nil { - return nil, errors.New("parse endpoint failed: " + err.Error()) - } - var conn *grpc.ClientConn - if u.Scheme == "http" { - conn, err = grpc.Dial(u.Host, grpc.WithInsecure()) - } else if u.Scheme == "https" { - conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ - InsecureSkipVerify: true, - }))) - } else { - return nil, errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'") - } - if err != nil { - return nil, err - } - conns = append(conns, conn) - } - if len(conns) == 0 { - return nil, errors.New("[RPC]no available endpoints") + client := &RPCClient{ + apiConfig: apiConfig, } - return &RPCClient{ - apiConfig: apiConfig, - conns: conns, - }, nil + err := client.init() + if err != nil { + return nil, err + } + + return client, nil } func (this *RPCClient) AdminRPC() pb.AdminServiceClient { @@ -233,10 +218,66 @@ func (this *RPCClient) APIContext(apiNodeId int64) context.Context { return ctx } +// 初始化 +func (this *RPCClient) init() error { + // 重新连接 + conns := []*grpc.ClientConn{} + for _, endpoint := range this.apiConfig.RPC.Endpoints { + u, err := url.Parse(endpoint) + if err != nil { + return errors.New("parse endpoint failed: " + err.Error()) + } + var conn *grpc.ClientConn + if u.Scheme == "http" { + conn, err = grpc.Dial(u.Host, grpc.WithInsecure()) + } else if u.Scheme == "https" { + conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + InsecureSkipVerify: true, + }))) + } else { + return errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'") + } + if err != nil { + return err + } + conns = append(conns, conn) + } + if len(conns) == 0 { + return errors.New("[RPC]no available endpoints") + } + this.conns = conns + return nil +} + // 随机选择一个连接 func (this *RPCClient) pickConn() *grpc.ClientConn { + this.locker.Lock() + defer this.locker.Unlock() + + // 检查连接状态 + if len(this.conns) > 0 { + availableConns := []*grpc.ClientConn{} + for _, conn := range this.conns { + if conn.GetState() == connectivity.Ready { + availableConns = append(availableConns, conn) + } + } + + if len(availableConns) > 0 { + return availableConns[rands.Int(0, len(availableConns)-1)] + } + } + + // 重新初始化 + err := this.init() + if err != nil { + // 错误提示已经在构造对象时打印过,所以这里不再重复打印 + return nil + } + if len(this.conns) == 0 { return nil } + return this.conns[rands.Int(0, len(this.conns)-1)] } diff --git a/internal/web/actions/default/servers/components/waf/log.go b/internal/web/actions/default/servers/components/waf/log.go index 409c0614..793ce52a 100644 --- a/internal/web/actions/default/servers/components/waf/log.go +++ b/internal/web/actions/default/servers/components/waf/log.go @@ -1,6 +1,12 @@ package waf -import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + timeutil "github.com/iwind/TeaGo/utils/time" + "regexp" + "strings" +) type LogAction struct { actionutils.ParentAction @@ -10,6 +16,64 @@ func (this *LogAction) Init() { this.Nav("", "", "log") } -func (this *LogAction) RunGet(params struct{}) { +func (this *LogAction) RunGet(params struct { + Day string + RequestId string + FirewallPolicyId int64 +}) { + if len(params.Day) == 0 { + params.Day = timeutil.Format("Y-m-d") + } + + this.Data["path"] = this.Request.URL.Path + this.Data["day"] = params.Day + this.Data["accessLogs"] = []interface{}{} + + day := params.Day + if len(day) > 0 && regexp.MustCompile(`\d{4}-\d{2}-\d{2}`).MatchString(day) { + day = strings.ReplaceAll(day, "-", "") + size := int64(10) + + resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ + RequestId: params.RequestId, + FirewallPolicyId: params.FirewallPolicyId, + Day: day, + Size: size, + }) + if err != nil { + this.ErrorPage(err) + return + } + + if len(resp.AccessLogs) == 0 { + this.Data["accessLogs"] = []interface{}{} + } else { + this.Data["accessLogs"] = resp.AccessLogs + } + this.Data["hasMore"] = resp.HasMore + this.Data["nextRequestId"] = resp.RequestId + + // 上一个requestId + this.Data["hasPrev"] = false + this.Data["lastRequestId"] = "" + if len(params.RequestId) > 0 { + this.Data["hasPrev"] = true + prevResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ + RequestId: params.RequestId, + FirewallPolicyId: params.FirewallPolicyId, + Day: day, + Size: size, + Reverse: true, + }) + if err != nil { + this.ErrorPage(err) + return + } + if int64(len(prevResp.AccessLogs)) == size { + this.Data["lastRequestId"] = prevResp.RequestId + } + } + } + this.Show() } diff --git a/web/public/js/components/server/http-access-log-box.js b/web/public/js/components/server/http-access-log-box.js index 793fda67..8aa55694 100644 --- a/web/public/js/components/server/http-access-log-box.js +++ b/web/public/js/components/server/http-access-log-box.js @@ -17,6 +17,6 @@ Vue.component("http-access-log-box", { } }, template: `
- {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] "{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} {{accessLog.proto}}" {{accessLog.status}} [cached] [waf {{accessLog.attrs['waf_action']}}] - 耗时:{{formatCost(accessLog.requestTime)}} ms + {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] "{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} {{accessLog.proto}}" {{accessLog.status}} [cached] [waf {{accessLog.attrs['waf.action']}}] - 耗时:{{formatCost(accessLog.requestTime)}} ms
` }) \ No newline at end of file diff --git a/web/public/js/components/server/http-firewall-config-box.js b/web/public/js/components/server/http-firewall-config-box.js index 189194b0..4b1c1de2 100644 --- a/web/public/js/components/server/http-firewall-config-box.js +++ b/web/public/js/components/server/http-firewall-config-box.js @@ -54,7 +54,7 @@ Vue.component("http-firewall-config-box", { -

[正在停用的策略]{{selectedPolicy.description}}

+

[正在停用的策略]{{selectedPolicy.description}}   详情»

diff --git a/web/views/@default/servers/components/waf/log.html b/web/views/@default/servers/components/waf/log.html index 5bb825ea..a3e64b83 100644 --- a/web/views/@default/servers/components/waf/log.html +++ b/web/views/@default/servers/components/waf/log.html @@ -1,8 +1,49 @@ {$layout} + +{$var "header"} + + + + + + +{$end} + {$template "/left_menu"}
{$template "waf_menu"} -

此功能暂未开放,敬请期待。

+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +

暂时还没有日志。

+ + + + + + +
+ +
+ 上一页 + 上一页 +   |   + 下一页 + 下一页 +
\ No newline at end of file diff --git a/web/views/@default/servers/components/waf/log.js b/web/views/@default/servers/components/waf/log.js new file mode 100644 index 00000000..f2c07081 --- /dev/null +++ b/web/views/@default/servers/components/waf/log.js @@ -0,0 +1,8 @@ +Tea.context(function () { + this.$delay(function () { + let that = this + teaweb.datepicker("day-input", function (day) { + that.day = day + }) + }) +}) \ No newline at end of file